Merge "Reenable SocksProxyTest"
diff --git a/check-ojluni-files b/check-ojluni-files
new file mode 100755
index 0000000..c0066fc
--- /dev/null
+++ b/check-ojluni-files
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+
+# Copyright (C) 2016 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.
+
+
+##### Script to check whether the files openjdk_java_files.mk match
+##### those in the corresponding directory.
+COMMAND='diff <(for i in $(openjdk_java_files); do echo "\$$i"; done | sort) '
+COMMAND=${COMMAND}'<( find ojluni/src/main/java -type f | grep '\''\.java$$'\'' | sort )'
+
+# Need to do it this nasty way (creating a Makefile on the fly and
+# executing the bash command inside it) as to read the openjdk_java_files
+# variable from an .mk file.
+make -s -f <(cat <<EOF
+include openjdk_java_files.mk
+check_openjdk_java_files: ; /bin/bash -c "$COMMAND"
+EOF)
+
+if [ $? -eq 0 ]; then
+ echo 'No differences found'
+else
+ echo 'Differences found'
+ exit 1
+fi
+
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java
index 792ee3d..9a4a406 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/Character_UnicodeBlockTest.java
@@ -4,9 +4,9 @@
* The ASF licenses this file to You 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.
@@ -232,6 +232,14 @@
assertEquals(Character.UnicodeBlock.SPECIALS, Character.UnicodeBlock.of((char) 0xfff0));
assertEquals(Character.UnicodeBlock.SPECIALS, Character.UnicodeBlock.of((char) 0xffff));
+ // Blocks added in 1.8
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of((char) 0x08a0));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of((char) 0x08ff));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of((char) 0x1cc0));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of((char) 0x1ccf));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of((char) 0xaae0));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of((char) 0xaaff));
+
// Negative test: The range [0x0860, 0x08A0) is currently unassigned.
assertEquals(null, Character.UnicodeBlock.of((char) 0x0860));
assertEquals(null, Character.UnicodeBlock.of((char) 0x089F));
@@ -489,6 +497,30 @@
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.of(0x100000));
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.of(0x10ffff));
+ // Blocks added in 1.8
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of(0x08a0));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.of(0x08ff));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of(0x1cc0));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.of(0x1ccf));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of(0xaae0));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.of(0xaaff));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.of(0x10980));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.of(0x1099f));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.of(0x109a0));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.of(0x109ff));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.of(0x110d0));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.of(0x110ff));
+ assertEquals(Character.UnicodeBlock.CHAKMA, Character.UnicodeBlock.of(0x11100));
+ assertEquals(Character.UnicodeBlock.CHAKMA, Character.UnicodeBlock.of(0x1114f));
+ assertEquals(Character.UnicodeBlock.SHARADA, Character.UnicodeBlock.of(0x11180));
+ assertEquals(Character.UnicodeBlock.SHARADA, Character.UnicodeBlock.of(0x111df));
+ assertEquals(Character.UnicodeBlock.TAKRI, Character.UnicodeBlock.of(0x11680));
+ assertEquals(Character.UnicodeBlock.TAKRI, Character.UnicodeBlock.of(0x116cf));
+ assertEquals(Character.UnicodeBlock.MIAO, Character.UnicodeBlock.of(0x16f00));
+ assertEquals(Character.UnicodeBlock.MIAO, Character.UnicodeBlock.of(0x16f9f));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS, Character.UnicodeBlock.of(0x1ee00));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS, Character.UnicodeBlock.of(0x1eeff));
+
// Negative test: The range [0x0860, 0x08A0) is currently unassigned.
assertEquals(null, Character.UnicodeBlock.of((char) 0x0860));
assertEquals(null, Character.UnicodeBlock.of((char) 0x089F));
@@ -793,6 +825,37 @@
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.forName("SUPPLEMENTARY_PRIVATE_USE_AREA_B"));
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.forName("Supplementary Private Use Area-B"));
assertEquals(Character.UnicodeBlock.SUPPLEMENTARY_PRIVATE_USE_AREA_B, Character.UnicodeBlock.forName("SupplementaryPrivateUseArea-B"));
+
+ // Blocks added in 1.8
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.forName("ARABIC_EXTENDED_A"));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.forName("arabic extended-A"));
+ assertEquals(Character.UnicodeBlock.ARABIC_EXTENDED_A, Character.UnicodeBlock.forName("ArabicExtended-A"));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.forName("SUNDANESE_SUPPLEMENT"));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.forName("Sundanese Supplement"));
+ assertEquals(Character.UnicodeBlock.SUNDANESE_SUPPLEMENT, Character.UnicodeBlock.forName("SundaneseSupplement"));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.forName("MEETEI_MAYEK_EXTENSIONS"));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.forName("MEETEI MAYEK EXTENSIONS"));
+ assertEquals(Character.UnicodeBlock.MEETEI_MAYEK_EXTENSIONS, Character.UnicodeBlock.forName("MeeteiMayekExtensions"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.forName("MEROITIC_HIEROGLYPHS"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.forName("MEROITIC HIEROGLYPHS"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_HIEROGLYPHS, Character.UnicodeBlock.forName("MeroiticHieroglyphs"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.forName("MEROITIC_CURSIVE"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.forName("MEROITIC CURSIVE"));
+ assertEquals(Character.UnicodeBlock.MEROITIC_CURSIVE, Character.UnicodeBlock.forName("MeroiticCursive"));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.forName("SORA_SOMPENG"));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.forName("SORA SOMPENG"));
+ assertEquals(Character.UnicodeBlock.SORA_SOMPENG, Character.UnicodeBlock.forName("SoraSompeng"));
+ assertEquals(Character.UnicodeBlock.CHAKMA, Character.UnicodeBlock.forName("CHAKMA"));
+ assertEquals(Character.UnicodeBlock.SHARADA, Character.UnicodeBlock.forName("SHARADA"));
+ assertEquals(Character.UnicodeBlock.TAKRI, Character.UnicodeBlock.forName("TAKRI"));
+ assertEquals(Character.UnicodeBlock.MIAO, Character.UnicodeBlock.forName("MIAO"));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
+ Character.UnicodeBlock.forName("ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS"));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
+ Character.UnicodeBlock.forName("ARABIC MATHEMATICAL ALPHABETIC SYMBOLS"));
+ assertEquals(Character.UnicodeBlock.ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
+ Character.UnicodeBlock.forName("ArabicMathematicalAlphabeticSymbols"));
+
}
public void test_forNameLjava_lang_StringExceptions() {
diff --git a/luni/src/test/java/libcore/java/lang/StringTest.java b/luni/src/test/java/libcore/java/lang/StringTest.java
index 5809da3..7e34d44 100644
--- a/luni/src/test/java/libcore/java/lang/StringTest.java
+++ b/luni/src/test/java/libcore/java/lang/StringTest.java
@@ -25,6 +25,7 @@
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Locale;
import junit.framework.TestCase;
@@ -547,4 +548,48 @@
assertEquals((int) low, surrogateCP.codePoints().toArray()[1]); // Unmatched surrogate.
assertEquals((int) '0', surrogateCP.codePoints().toArray()[2]);
}
+
+ public void testJoin_CharSequenceArray() {
+ assertEquals("", String.join("-"));
+ assertEquals("", String.join("-", ""));
+ assertEquals("foo", String.join("-", "foo"));
+ assertEquals("foo---bar---boo", String.join("---", "foo", "bar", "boo"));
+ assertEquals("foobarboo", String.join("", "foo", "bar", "boo"));
+ assertEquals("null-null", String.join("-", null, null));
+ assertEquals("¯\\_(ツ)_/¯", String.join("(ツ)", "¯\\_", "_/¯"));
+ }
+
+ public void testJoin_CharSequenceArray_NPE() {
+ try {
+ String.join(null, "foo", "bar");
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
+ public void testJoin_Iterable() {
+ ArrayList<String> iterable = new ArrayList<>();
+ assertEquals("", String.join("-", iterable));
+
+ iterable.add("foo");
+ assertEquals("foo", String.join("-", iterable));
+
+ iterable.add("bar");
+ assertEquals("foo...bar", String.join("...", iterable));
+
+ iterable.add("foo");
+ assertEquals("foo-bar-foo", String.join("-", iterable));
+ assertEquals("foobarfoo", String.join("", iterable));
+ }
+
+ public void testJoin_Iterable_NPE() {
+ try {
+ String.join(null, new ArrayList<String>());
+ fail();
+ } catch (NullPointerException expected) {}
+
+ try {
+ String.join("-", (Iterable<String>)null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java b/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java
index d78456d..a251963 100644
--- a/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java
+++ b/luni/src/test/java/libcore/java/net/ServerSocketConcurrentCloseTest.java
@@ -1,11 +1,17 @@
-package java.net;
+package libcore.java.net;
import junit.framework.TestCase;
import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketImpl;
+import java.net.SocketException;
+import java.net.SocketAddress;
+import java.net.ServerSocket;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Tests for race conditions between {@link ServerSocket#close()} and
@@ -34,16 +40,33 @@
}
final ExposedServerSocket serverSocket = new ExposedServerSocket();
serverSocket.close();
- try {
- // Hack: Need to subclass to access the protected constructor without reflection
- Socket socket = new Socket((SocketImpl) null) { };
- serverSocket.implAcceptExposedForTest(socket);
- fail("accepting on a closed socket should throw");
- } catch (SocketException expected) {
- // expected
- } catch (IOException e) {
- throw new AssertionError(e);
+ // implAccept() on background thread to prevent this test hanging
+ final AtomicReference<Exception> failure = new AtomicReference<>();
+ final CountDownLatch threadFinishedLatch = new CountDownLatch(1);
+ Thread thread = new Thread("implAccept() closed ServerSocket") {
+ public void run() {
+ try {
+ // Hack: Need to subclass to access the protected constructor without reflection
+ Socket socket = new Socket((SocketImpl) null) { };
+ serverSocket.implAcceptExposedForTest(socket);
+ } catch (SocketException expected) {
+ // pass
+ } catch (IOException|RuntimeException e) {
+ failure.set(e);
+ } finally {
+ threadFinishedLatch.countDown();
+ }
+ }
+ };
+ thread.start();
+
+ boolean completed = threadFinishedLatch.await(5, TimeUnit.SECONDS);
+ assertTrue("implAccept didn't throw or return within time limit", completed);
+ Exception e = failure.get();
+ if (e != null) {
+ throw new AssertionError("Unexpected exception", e);
}
+ thread.join();
}
/**
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 37fa771..7c5cc42 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -16,15 +16,19 @@
package libcore.java.net;
-import com.android.okhttp.AndroidShimResponseCache;
-
import com.google.mockwebserver.Dispatcher;
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.MockWebServer;
import com.google.mockwebserver.RecordedRequest;
import com.google.mockwebserver.SocketPolicy;
+
+import com.android.okhttp.AndroidShimResponseCache;
+
+import junit.framework.TestCase;
+
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -35,7 +39,6 @@
import java.net.CacheResponse;
import java.net.HttpRetryException;
import java.net.HttpURLConnection;
-import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.PasswordAuthentication;
import java.net.ProtocolException;
@@ -82,8 +85,8 @@
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import libcore.java.security.TestKeyStore;
-import libcore.java.util.AbstractResourceLeakageDetectorTestCase;
import libcore.javax.net.ssl.TestSSLContext;
+
import tests.net.DelegatingSocketFactory;
import static com.google.mockwebserver.SocketPolicy.DISCONNECT_AT_END;
@@ -96,16 +99,18 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.spy;
-public final class URLConnectionTest extends AbstractResourceLeakageDetectorTestCase {
+public final class URLConnectionTest extends TestCase {
private MockWebServer server;
private AndroidShimResponseCache cache;
private String hostName;
+ private List<TestSSLContext> testSSLContextsToClose;
@Override protected void setUp() throws Exception {
super.setUp();
server = new MockWebServer();
hostName = server.getHostName();
+ testSSLContextsToClose = new ArrayList<>();
}
@Override protected void tearDown() throws Exception {
@@ -123,6 +128,9 @@
cache.delete();
cache = null;
}
+ for (TestSSLContext testSSLContext : testSSLContextsToClose) {
+ testSSLContext.close();
+ }
super.tearDown();
}
@@ -521,7 +529,7 @@
}
public void testConnectViaHttps() throws IOException, InterruptedException {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
@@ -538,7 +546,7 @@
}
public void testConnectViaHttpsReusingConnections() throws IOException, InterruptedException {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
SSLSocketFactory clientSocketFactory = testSSLContext.clientContext.getSocketFactory();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
@@ -560,7 +568,7 @@
public void testConnectViaHttpsReusingConnectionsDifferentFactories()
throws IOException, InterruptedException {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
@@ -588,6 +596,7 @@
public void testConnectViaHttpsToUntrustedServer() throws IOException, InterruptedException {
TestSSLContext testSSLContext = TestSSLContext.create(TestKeyStore.getClientCA2(),
TestKeyStore.getServer());
+ testSSLContextsToClose.add(testSSLContext);
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse()); // unused
@@ -666,7 +675,7 @@
}
private void testConnectViaDirectProxyToHttps(ProxyConfig proxyConfig) throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
@@ -704,7 +713,7 @@
* through a proxy. http://b/3097277
*/
private void testConnectViaHttpProxyToHttps(ProxyConfig proxyConfig) throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
@@ -737,7 +746,7 @@
* Tolerate bad https proxy response when using HttpResponseCache. http://b/6754912
*/
public void testConnectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache() throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
initResponseCache();
@@ -912,7 +921,7 @@
public void testProxyConnectIncludesProxyHeadersOnly()
throws IOException, InterruptedException {
RecordingHostnameVerifier hostnameVerifier = new RecordingHostnameVerifier();
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
server.enqueue(new MockResponse()
@@ -945,7 +954,7 @@
public void testProxyAuthenticateOnConnect() throws Exception {
Authenticator.setDefault(new SimpleAuthenticator());
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
server.enqueue(new MockResponse()
.setResponseCode(407)
@@ -980,7 +989,7 @@
// 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();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
server.enqueue(new MockResponse()
.setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
@@ -1449,7 +1458,7 @@
* http://code.google.com/p/android/issues/detail?id=12860
*/
private void testSecureStreamingPost(StreamingMode streamingMode) throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("Success!"));
server.play();
@@ -1660,7 +1669,7 @@
}
public void testRedirectedOnHttps() throws IOException, InterruptedException {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse()
.setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
@@ -1682,7 +1691,7 @@
}
public void testNotRedirectedFromHttpsToHttp() throws IOException, InterruptedException {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse()
.setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
@@ -1919,7 +1928,7 @@
SSLSocketFactory defaultSSLSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory();
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
try {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("ABC"));
server.enqueue(new MockResponse().setBody("DEF"));
@@ -2681,7 +2690,7 @@
}
public void testSslFallback_allSupportedProtocols() throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
String[] allSupportedProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3" };
SSLSocketFactory serverSocketFactory =
@@ -2734,7 +2743,7 @@
}
public void testSslFallback_defaultProtocols() throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
@@ -2784,7 +2793,7 @@
}
public void testInspectSslBeforeConnect() throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse());
server.play();
@@ -2819,7 +2828,7 @@
* http://code.google.com/p/android/issues/detail?id=24431
*/
public void testInspectSslAfterConnect() throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
+ TestSSLContext testSSLContext = createDefaultTestSSLContext();
server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse());
server.play();
@@ -2838,45 +2847,6 @@
}
}
- // http://b/26769689
- public void testSSLSocketFactoryWithIpv6LiteralHostname() throws Exception {
- TestSSLContext testSSLContext = TestSSLContext.create();
- server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
- server.enqueue(new MockResponse());
- server.play();
-
- final AtomicReference<String> hostNameUsed = new AtomicReference<>(null);
-
- SSLSocketFactory factory = new DelegatingSSLSocketFactory(
- testSSLContext.clientContext.getSocketFactory()) {
- @Override
- public SSLSocket createSocket(Socket s, String host, int port, boolean autoClose)
- throws IOException {
- hostNameUsed.set(host);
- return (SSLSocket) delegate.createSocket(s, host, port, autoClose);
- }
- };
-
- HttpsURLConnection urlConnection = (HttpsURLConnection)
- new URL("https://[" + Inet6Address.getLoopbackAddress().getHostAddress() + "]:"
- + server.getPort() + "/").openConnection();
- urlConnection.setSSLSocketFactory(factory);
- try {
- urlConnection.connect();
- fail();
- } catch (IOException expected) {
- // We expect the connection to fail with a cert validation exception because we're
- // using a literal address.
- } finally {
- urlConnection.disconnect();
- }
-
- // Note that the square brackets around the literal address were crucial. Whatsapp
- // wouldn't function properly without them.
- assertEquals("[" + Inet6Address.getLoopbackAddress().getHostAddress() + "]",
- hostNameUsed.get());
- }
-
/**
* Returns a gzipped copy of {@code bytes}.
*/
@@ -2919,6 +2889,12 @@
return new HashSet<String>(Arrays.asList(elements));
}
+ private TestSSLContext createDefaultTestSSLContext() {
+ TestSSLContext result = TestSSLContext.create();
+ testSSLContextsToClose.add(result);
+ return result;
+ }
+
enum TransferKind {
CHUNKED() {
@Override void setBody(MockResponse response, byte[] content, int chunkSize)
diff --git a/ojluni/src/main/java/com/sun/net/ssl/internal/ssl/Provider.java b/ojluni/src/main/java/com/sun/net/ssl/internal/ssl/Provider.java
deleted file mode 100755
index b1a08ce..0000000
--- a/ojluni/src/main/java/com/sun/net/ssl/internal/ssl/Provider.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.net.ssl.internal.ssl;
-
-import sun.security.ssl.SunJSSE;
-
-/**
- * Main class for the SunJSSE provider. The actual code was moved to the
- * class sun.security.ssl.SunJSSE, but for backward compatibility we
- * continue to use this class as the main Provider class.
- */
-public final class Provider extends SunJSSE {
-
- private static final long serialVersionUID = 3231825739635378733L;
-
- // standard constructor
- public Provider() {
- super();
- }
-
- // prefered constructor to enable FIPS mode at runtime
- public Provider(java.security.Provider cryptoProvider) {
- super(cryptoProvider);
- }
-
- // constructor to enable FIPS mode from java.security file
- public Provider(String cryptoProvider) {
- super(cryptoProvider);
- }
-
- // public for now, but we may want to change it or not document it.
- public static synchronized boolean isFIPS() {
- return SunJSSE.isFIPS();
- }
-
- /**
- * Installs the JSSE provider.
- */
- public static synchronized void install() {
- /* nop. Remove this method in the future. */
- }
-
-}
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
old mode 100755
new mode 100644
index aa71ca4..383a358
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package java.lang;
+import sun.misc.FloatingDecimal;
import java.util.Arrays;
/**
@@ -35,12 +36,16 @@
* particular sequence of characters, but the length and content of the
* sequence can be changed through certain method calls.
*
+ * <p>Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
* @author Michael McCloskey
* @author Martin Buchholz
* @author Ulf Zibis
* @since 1.5
*/
-abstract class AbstractStringBuilder implements CharSequence {
+abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
@@ -70,6 +75,7 @@
* @return the length of the sequence of characters currently
* represented by this object
*/
+ @Override
public int length() {
return count;
}
@@ -91,11 +97,13 @@
* array is allocated with greater capacity. The new capacity is the
* larger of:
* <ul>
- * <li>The <code>minimumCapacity</code> argument.
- * <li>Twice the old capacity, plus <code>2</code>.
+ * <li>The {@code minimumCapacity} argument.
+ * <li>Twice the old capacity, plus {@code 2}.
* </ul>
- * If the <code>minimumCapacity</code> argument is nonpositive, this
+ * If the {@code minimumCapacity} argument is nonpositive, this
* method takes no action and simply returns.
+ * Note that subsequent operations on this object can reduce the
+ * actual capacity below that requested here.
*
* @param minimumCapacity the minimum desired capacity.
*/
@@ -108,7 +116,7 @@
* This method has the same contract as ensureCapacity, but is
* never synchronized.
*/
- void ensureCapacityInternal(int minimumCapacity) {
+ private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
@@ -147,26 +155,26 @@
* Sets the length of the character sequence.
* The sequence is changed to a new character sequence
* whose length is specified by the argument. For every nonnegative
- * index <i>k</i> less than <code>newLength</code>, the character at
+ * index <i>k</i> less than {@code newLength}, the character at
* index <i>k</i> in the new character sequence is the same as the
* character at index <i>k</i> in the old sequence if <i>k</i> is less
* than the length of the old character sequence; otherwise, it is the
- * null character <code>'\u0000'</code>.
+ * null character {@code '\u005Cu0000'}.
*
- * In other words, if the <code>newLength</code> argument is less than
+ * In other words, if the {@code newLength} argument is less than
* the current length, the length is changed to the specified length.
* <p>
- * If the <code>newLength</code> argument is greater than or equal
+ * If the {@code newLength} argument is greater than or equal
* to the current length, sufficient null characters
- * (<code>'\u0000'</code>) are appended so that
- * length becomes the <code>newLength</code> argument.
+ * ({@code '\u005Cu0000'}) are appended so that
+ * length becomes the {@code newLength} argument.
* <p>
- * The <code>newLength</code> argument must be greater than or equal
- * to <code>0</code>.
+ * The {@code newLength} argument must be greater than or equal
+ * to {@code 0}.
*
* @param newLength the new length
* @throws IndexOutOfBoundsException if the
- * <code>newLength</code> argument is negative.
+ * {@code newLength} argument is negative.
*/
public void setLength(int newLength) {
if (newLength < 0)
@@ -174,30 +182,30 @@
ensureCapacityInternal(newLength);
if (count < newLength) {
- for (; count < newLength; count++)
- value[count] = '\0';
- } else {
- count = newLength;
+ Arrays.fill(value, count, newLength, '\0');
}
+
+ count = newLength;
}
/**
- * Returns the <code>char</code> value in this sequence at the specified index.
- * The first <code>char</code> value is at index <code>0</code>, the next at index
- * <code>1</code>, and so on, as in array indexing.
+ * Returns the {@code char} value in this sequence at the specified index.
+ * The first {@code char} value is at index {@code 0}, the next at index
+ * {@code 1}, and so on, as in array indexing.
* <p>
* The index argument must be greater than or equal to
- * <code>0</code>, and less than the length of this sequence.
+ * {@code 0}, and less than the length of this sequence.
*
- * <p>If the <code>char</code> value specified by the index is a
+ * <p>If the {@code char} value specified by the index is a
* <a href="Character.html#unicode">surrogate</a>, the surrogate
* value is returned.
*
- * @param index the index of the desired <code>char</code> value.
- * @return the <code>char</code> value at the specified index.
- * @throws IndexOutOfBoundsException if <code>index</code> is
- * negative or greater than or equal to <code>length()</code>.
+ * @param index the index of the desired {@code char} value.
+ * @return the {@code char} value at the specified index.
+ * @throws IndexOutOfBoundsException if {@code index} is
+ * negative or greater than or equal to {@code length()}.
*/
+ @Override
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
@@ -206,22 +214,22 @@
/**
* Returns the character (Unicode code point) at the specified
- * index. The index refers to <code>char</code> values
- * (Unicode code units) and ranges from <code>0</code> to
- * {@link #length()}<code> - 1</code>.
+ * index. The index refers to {@code char} values
+ * (Unicode code units) and ranges from {@code 0} to
+ * {@link #length()}{@code - 1}.
*
- * <p> If the <code>char</code> value specified at the given index
+ * <p> If the {@code char} value specified at the given index
* is in the high-surrogate range, the following index is less
* than the length of this sequence, and the
- * <code>char</code> value at the following index is in the
+ * {@code char} value at the following index is in the
* low-surrogate range, then the supplementary code point
* corresponding to this surrogate pair is returned. Otherwise,
- * the <code>char</code> value at the given index is returned.
+ * the {@code char} value at the given index is returned.
*
- * @param index the index to the <code>char</code> values
+ * @param index the index to the {@code char} values
* @return the code point value of the character at the
- * <code>index</code>
- * @exception IndexOutOfBoundsException if the <code>index</code>
+ * {@code index}
+ * @exception IndexOutOfBoundsException if the {@code index}
* argument is negative or not less than the length of this
* sequence.
*/
@@ -229,27 +237,27 @@
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
- return Character.codePointAt(value, index);
+ return Character.codePointAtImpl(value, index, count);
}
/**
* Returns the character (Unicode code point) before the specified
- * index. The index refers to <code>char</code> values
- * (Unicode code units) and ranges from <code>1</code> to {@link
+ * index. The index refers to {@code char} values
+ * (Unicode code units) and ranges from {@code 1} to {@link
* #length()}.
*
- * <p> If the <code>char</code> value at <code>(index - 1)</code>
- * is in the low-surrogate range, <code>(index - 2)</code> is not
- * negative, and the <code>char</code> value at <code>(index -
- * 2)</code> is in the high-surrogate range, then the
+ * <p> If the {@code char} value at {@code (index - 1)}
+ * is in the low-surrogate range, {@code (index - 2)} is not
+ * negative, and the {@code char} value at {@code (index -
+ * 2)} is in the high-surrogate range, then the
* supplementary code point value of the surrogate pair is
- * returned. If the <code>char</code> value at <code>index -
- * 1</code> is an unpaired low-surrogate or a high-surrogate, the
+ * returned. If the {@code char} value at {@code index -
+ * 1} is an unpaired low-surrogate or a high-surrogate, the
* surrogate value is returned.
*
* @param index the index following the code point that should be returned
* @return the Unicode code point value before the given index.
- * @exception IndexOutOfBoundsException if the <code>index</code>
+ * @exception IndexOutOfBoundsException if the {@code index}
* argument is less than 1 or greater than the length
* of this sequence.
*/
@@ -258,28 +266,28 @@
if ((i < 0) || (i >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
- return Character.codePointBefore(value, index);
+ return Character.codePointBeforeImpl(value, index, 0);
}
/**
* Returns the number of Unicode code points in the specified text
* range of this sequence. The text range begins at the specified
- * <code>beginIndex</code> and extends to the <code>char</code> at
- * index <code>endIndex - 1</code>. Thus the length (in
- * <code>char</code>s) of the text range is
- * <code>endIndex-beginIndex</code>. Unpaired surrogates within
+ * {@code beginIndex} and extends to the {@code char} at
+ * index {@code endIndex - 1}. Thus the length (in
+ * {@code char}s) of the text range is
+ * {@code endIndex-beginIndex}. Unpaired surrogates within
* this sequence count as one code point each.
*
- * @param beginIndex the index to the first <code>char</code> of
+ * @param beginIndex the index to the first {@code char} of
* the text range.
- * @param endIndex the index after the last <code>char</code> of
+ * @param endIndex the index after the last {@code char} of
* the text range.
* @return the number of Unicode code points in the specified text
* range
* @exception IndexOutOfBoundsException if the
- * <code>beginIndex</code> is negative, or <code>endIndex</code>
+ * {@code beginIndex} is negative, or {@code endIndex}
* is larger than the length of this sequence, or
- * <code>beginIndex</code> is larger than <code>endIndex</code>.
+ * {@code beginIndex} is larger than {@code endIndex}.
*/
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
@@ -290,22 +298,22 @@
/**
* Returns the index within this sequence that is offset from the
- * given <code>index</code> by <code>codePointOffset</code> code
+ * given {@code index} by {@code codePointOffset} code
* points. Unpaired surrogates within the text range given by
- * <code>index</code> and <code>codePointOffset</code> count as
+ * {@code index} and {@code codePointOffset} count as
* one code point each.
*
* @param index the index to be offset
* @param codePointOffset the offset in code points
* @return the index within this sequence
- * @exception IndexOutOfBoundsException if <code>index</code>
+ * @exception IndexOutOfBoundsException if {@code index}
* is negative or larger then the length of this sequence,
- * or if <code>codePointOffset</code> is positive and the subsequence
- * starting with <code>index</code> has fewer than
- * <code>codePointOffset</code> code points,
- * or if <code>codePointOffset</code> is negative and the subsequence
- * before <code>index</code> has fewer than the absolute value of
- * <code>codePointOffset</code> code points.
+ * or if {@code codePointOffset} is positive and the subsequence
+ * starting with {@code index} has fewer than
+ * {@code codePointOffset} code points,
+ * or if {@code codePointOffset} is negative and the subsequence
+ * before {@code index} has fewer than the absolute value of
+ * {@code codePointOffset} code points.
*/
public int offsetByCodePoints(int index, int codePointOffset) {
if (index < 0 || index > count) {
@@ -317,32 +325,30 @@
/**
* Characters are copied from this sequence into the
- * destination character array <code>dst</code>. The first character to
- * be copied is at index <code>srcBegin</code>; the last character to
- * be copied is at index <code>srcEnd-1</code>. The total number of
- * characters to be copied is <code>srcEnd-srcBegin</code>. The
- * characters are copied into the subarray of <code>dst</code> starting
- * at index <code>dstBegin</code> and ending at index:
- * <p><blockquote><pre>
+ * destination character array {@code dst}. The first character to
+ * be copied is at index {@code srcBegin}; the last character to
+ * be copied is at index {@code srcEnd-1}. The total number of
+ * characters to be copied is {@code srcEnd-srcBegin}. The
+ * characters are copied into the subarray of {@code dst} starting
+ * at index {@code dstBegin} and ending at index:
+ * <pre>{@code
* dstbegin + (srcEnd-srcBegin) - 1
- * </pre></blockquote>
+ * }</pre>
*
* @param srcBegin start copying at this offset.
* @param srcEnd stop copying at this offset.
* @param dst the array to copy the data into.
- * @param dstBegin offset into <code>dst</code>.
- * @throws NullPointerException if <code>dst</code> is
- * <code>null</code>.
+ * @param dstBegin offset into {@code dst}.
* @throws IndexOutOfBoundsException if any of the following is true:
* <ul>
- * <li><code>srcBegin</code> is negative
- * <li><code>dstBegin</code> is negative
- * <li>the <code>srcBegin</code> argument is greater than
- * the <code>srcEnd</code> argument.
- * <li><code>srcEnd</code> is greater than
- * <code>this.length()</code>.
- * <li><code>dstBegin+srcEnd-srcBegin</code> is greater than
- * <code>dst.length</code>
+ * <li>{@code srcBegin} is negative
+ * <li>{@code dstBegin} is negative
+ * <li>the {@code srcBegin} argument is greater than
+ * the {@code srcEnd} argument.
+ * <li>{@code srcEnd} is greater than
+ * {@code this.length()}.
+ * <li>{@code dstBegin+srcEnd-srcBegin} is greater than
+ * {@code dst.length}
* </ul>
*/
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
@@ -357,18 +363,18 @@
}
/**
- * The character at the specified index is set to <code>ch</code>. This
+ * The character at the specified index is set to {@code ch}. This
* sequence is altered to represent a new character sequence that is
* identical to the old character sequence, except that it contains the
- * character <code>ch</code> at position <code>index</code>.
+ * character {@code ch} at position {@code index}.
* <p>
* The index argument must be greater than or equal to
- * <code>0</code>, and less than the length of this sequence.
+ * {@code 0}, and less than the length of this sequence.
*
* @param index the index of the character to modify.
* @param ch the new character.
- * @throws IndexOutOfBoundsException if <code>index</code> is
- * negative or greater than or equal to <code>length()</code>.
+ * @throws IndexOutOfBoundsException if {@code index} is
+ * negative or greater than or equal to {@code length()}.
*/
public void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
@@ -412,10 +418,11 @@
* @hide
*/
public AbstractStringBuilder append(String str) {
- if (str == null) str = "null";
+ if (str == null)
+ return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
- str.getCharsNoCheck(0, len, value, count);
+ str.getChars(0, len, value, count);
count += len;
return this;
}
@@ -424,7 +431,7 @@
/** @hide */
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
- return append("null");
+ return appendNull();
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
@@ -432,18 +439,46 @@
return this;
}
+ /**
+ * @since 1.8
+ * @hide
+ */
+ AbstractStringBuilder append(AbstractStringBuilder asb) {
+ if (asb == null)
+ return appendNull();
+ int len = asb.length();
+ ensureCapacityInternal(count + len);
+ asb.getChars(0, len, value, count);
+ count += len;
+ return this;
+ }
+
// Documentation in subclasses because of synchro difference
/** @hide */
+ @Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
- s = "null";
+ return appendNull();
if (s instanceof String)
return this.append((String)s);
- if (s instanceof StringBuffer)
- return this.append((StringBuffer)s);
+ if (s instanceof AbstractStringBuilder)
+ return this.append((AbstractStringBuilder)s);
+
return this.append(s, 0, s.length());
}
+ private AbstractStringBuilder appendNull() {
+ int c = count;
+ ensureCapacityInternal(c + 4);
+ final char[] value = this.value;
+ value[c++] = 'n';
+ value[c++] = 'u';
+ value[c++] = 'l';
+ value[c++] = 'l';
+ count = c;
+ return this;
+ }
+
/**
* Appends a subsequence of the specified {@code CharSequence} to this
* sequence.
@@ -474,6 +509,7 @@
* {@code end} is greater than {@code s.length()}
* @hide
*/
+ @Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
@@ -483,16 +519,8 @@
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
- if (s instanceof String) {
- ((String) s).getCharsNoCheck(start, end, value, count);
- } else if (s instanceof AbstractStringBuilder) {
- AbstractStringBuilder other = (AbstractStringBuilder) s;
- System.arraycopy(other.value, start, value, count, len);
- } else {
- for (int i = start, j = count; i < end; i++, j++) {
- value[j] = s.charAt(i);
- }
- }
+ for (int i = start, j = count; i < end; i++, j++)
+ value[j] = s.charAt(i);
count += len;
return this;
}
@@ -569,19 +597,17 @@
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
- value[count] = 't';
- value[count+1] = 'r';
- value[count+2] = 'u';
- value[count+3] = 'e';
- count += 4;
+ value[count++] = 't';
+ value[count++] = 'r';
+ value[count++] = 'u';
+ value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
- value[count] = 'f';
- value[count+1] = 'a';
- value[count+2] = 'l';
- value[count+3] = 's';
- value[count+4] = 'e';
- count += 5;
+ value[count++] = 'f';
+ value[count++] = 'a';
+ value[count++] = 'l';
+ value[count++] = 's';
+ value[count++] = 'e';
}
return this;
}
@@ -602,6 +628,7 @@
* @return a reference to this object.
* @hide
*/
+ @Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
@@ -676,9 +703,7 @@
* @hide
*/
public AbstractStringBuilder append(float f) {
- FloatingDecimal.getThreadLocalInstance()
- .loadFloat(f)
- .appendTo(this);
+ FloatingDecimal.appendTo(f,this);
return this;
}
@@ -696,9 +721,7 @@
* @hide
*/
public AbstractStringBuilder append(double d) {
- FloatingDecimal.getThreadLocalInstance()
- .loadDouble(d)
- .appendTo(this);
+ FloatingDecimal.appendTo(d,this);
return this;
}
@@ -770,21 +793,21 @@
}
/**
- * Removes the <code>char</code> at the specified position in this
- * sequence. This sequence is shortened by one <code>char</code>.
+ * Removes the {@code char} at the specified position in this
+ * sequence. This sequence is shortened by one {@code char}.
*
* <p>Note: If the character at the given index is a supplementary
* character, this method does not remove the entire character. If
* correct handling of supplementary characters is required,
- * determine the number of <code>char</code>s to remove by calling
- * <code>Character.charCount(thisSequence.codePointAt(index))</code>,
- * where <code>thisSequence</code> is this sequence.
+ * determine the number of {@code char}s to remove by calling
+ * {@code Character.charCount(thisSequence.codePointAt(index))},
+ * where {@code thisSequence} is this sequence.
*
- * @param index Index of <code>char</code> to remove
+ * @param index Index of {@code char} to remove
* @return This object.
- * @throws StringIndexOutOfBoundsException if the <code>index</code>
+ * @throws StringIndexOutOfBoundsException if the {@code index}
* is negative or greater than or equal to
- * <code>length()</code>.
+ * {@code length()}.
* @hide
*/
public AbstractStringBuilder deleteCharAt(int index) {
@@ -797,12 +820,12 @@
/**
* Replaces the characters in a substring of this sequence
- * with characters in the specified <code>String</code>. The substring
- * begins at the specified <code>start</code> and extends to the character
- * at index <code>end - 1</code> or to the end of the
+ * with characters in the specified {@code String}. The substring
+ * begins at the specified {@code start} and extends to the character
+ * at index {@code end - 1} or to the end of the
* sequence if no such character exists. First the
* characters in the substring are removed and then the specified
- * <code>String</code> is inserted at <code>start</code>. (This
+ * {@code String} is inserted at {@code start}. (This
* sequence will be lengthened to accommodate the
* specified String if necessary.)
*
@@ -810,9 +833,9 @@
* @param end The ending index, exclusive.
* @param str String that will replace previous contents.
* @return This object.
- * @throws StringIndexOutOfBoundsException if <code>start</code>
- * is negative, greater than <code>length()</code>, or
- * greater than <code>end</code>.
+ * @throws StringIndexOutOfBoundsException if {@code start}
+ * is negative, greater than {@code length()}, or
+ * greater than {@code end}.
* @hide
*/
public AbstractStringBuilder replace(int start, int end, String str) {
@@ -830,20 +853,20 @@
ensureCapacityInternal(newCount);
System.arraycopy(value, end, value, start + len, count - end);
- str.getCharsNoCheck(0, len, value, start);
+ str.getChars(value, start);
count = newCount;
return this;
}
/**
- * Returns a new <code>String</code> that contains a subsequence of
+ * Returns a new {@code String} that contains a subsequence of
* characters currently contained in this character sequence. The
* substring begins at the specified index and extends to the end of
* this sequence.
*
* @param start The beginning index, inclusive.
* @return The new string.
- * @throws StringIndexOutOfBoundsException if <code>start</code> is
+ * @throws StringIndexOutOfBoundsException if {@code start} is
* less than zero, or greater than the length of this object.
*/
public String substring(int start) {
@@ -855,44 +878,45 @@
*
* <p> An invocation of this method of the form
*
- * <blockquote><pre>
- * sb.subSequence(begin, end)</pre></blockquote>
+ * <pre>{@code
+ * sb.subSequence(begin, end)}</pre>
*
* behaves in exactly the same way as the invocation
*
- * <blockquote><pre>
- * sb.substring(begin, end)</pre></blockquote>
+ * <pre>{@code
+ * sb.substring(begin, end)}</pre>
*
* This method is provided so that this class can
- * implement the {@link CharSequence} interface. </p>
+ * implement the {@link CharSequence} interface.
*
* @param start the start index, inclusive.
* @param end the end index, exclusive.
* @return the specified subsequence.
*
* @throws IndexOutOfBoundsException
- * if <tt>start</tt> or <tt>end</tt> are negative,
- * if <tt>end</tt> is greater than <tt>length()</tt>,
- * or if <tt>start</tt> is greater than <tt>end</tt>
+ * if {@code start} or {@code end} are negative,
+ * if {@code end} is greater than {@code length()},
+ * or if {@code start} is greater than {@code end}
* @spec JSR-51
*/
+ @Override
public CharSequence subSequence(int start, int end) {
return substring(start, end);
}
/**
- * Returns a new <code>String</code> that contains a subsequence of
+ * Returns a new {@code String} that contains a subsequence of
* characters currently contained in this sequence. The
- * substring begins at the specified <code>start</code> and
- * extends to the character at index <code>end - 1</code>.
+ * substring begins at the specified {@code start} and
+ * extends to the character at index {@code end - 1}.
*
* @param start The beginning index, inclusive.
* @param end The ending index, exclusive.
* @return The new string.
- * @throws StringIndexOutOfBoundsException if <code>start</code>
- * or <code>end</code> are negative or greater than
- * <code>length()</code>, or <code>start</code> is
- * greater than <code>end</code>.
+ * @throws StringIndexOutOfBoundsException if {@code start}
+ * or {@code end} are negative or greater than
+ * {@code length()}, or {@code start} is
+ * greater than {@code end}.
*/
public String substring(int start, int end) {
if (start < 0)
@@ -1006,7 +1030,7 @@
int len = str.length();
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
- str.getCharsNoCheck(0, len, value, offset);
+ str.getChars(value, offset);
count += len;
return this;
}
@@ -1294,18 +1318,16 @@
* Returns the index within this string of the first occurrence of the
* specified substring. The integer returned is the smallest value
* <i>k</i> such that:
- * <blockquote><pre>
+ * <pre>{@code
* this.toString().startsWith(str, <i>k</i>)
- * </pre></blockquote>
- * is <code>true</code>.
+ * }</pre>
+ * is {@code true}.
*
* @param str any string.
* @return if the string argument occurs as a substring within this
* object, then the index of the first character of the first
* such substring is returned; if it does not occur as a
- * substring, <code>-1</code> is returned.
- * @throws java.lang.NullPointerException if <code>str</code> is
- * <code>null</code>.
+ * substring, {@code -1} is returned.
*/
public int indexOf(String str) {
return indexOf(str, 0);
@@ -1314,19 +1336,17 @@
/**
* Returns the index within this string of the first occurrence of the
* specified substring, starting at the specified index. The integer
- * returned is the smallest value <tt>k</tt> for which:
- * <blockquote><pre>
- * k >= Math.min(fromIndex, str.length()) &&
+ * returned is the smallest value {@code k} for which:
+ * <pre>{@code
+ * k >= Math.min(fromIndex, this.length()) &&
* this.toString().startsWith(str, k)
- * </pre></blockquote>
+ * }</pre>
* If no such value of <i>k</i> exists, then -1 is returned.
*
* @param str the substring for which to search.
* @param fromIndex the index from which to start the search.
* @return the index within this string of the first occurrence of the
* specified substring, starting at the specified index.
- * @throws java.lang.NullPointerException if <code>str</code> is
- * <code>null</code>.
*/
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, 0, count,
@@ -1336,20 +1356,18 @@
/**
* Returns the index within this string of the rightmost occurrence
* of the specified substring. The rightmost empty string "" is
- * considered to occur at the index value <code>this.length()</code>.
+ * considered to occur at the index value {@code this.length()}.
* The returned index is the largest value <i>k</i> such that
- * <blockquote><pre>
+ * <pre>{@code
* this.toString().startsWith(str, k)
- * </pre></blockquote>
+ * }</pre>
* is true.
*
* @param str the substring to search for.
* @return if the string argument occurs one or more times as a substring
* within this object, then the index of the first character of
* the last such substring is returned. If it does not occur as
- * a substring, <code>-1</code> is returned.
- * @throws java.lang.NullPointerException if <code>str</code> is
- * <code>null</code>.
+ * a substring, {@code -1} is returned.
*/
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
@@ -1359,22 +1377,20 @@
* Returns the index within this string of the last occurrence of the
* specified substring. The integer returned is the largest value <i>k</i>
* such that:
- * <blockquote><pre>
- * k <= Math.min(fromIndex, str.length()) &&
+ * <pre>{@code
+ * k <= Math.min(fromIndex, this.length()) &&
* this.toString().startsWith(str, k)
- * </pre></blockquote>
+ * }</pre>
* If no such value of <i>k</i> exists, then -1 is returned.
*
* @param str the substring to search for.
* @param fromIndex the index to start the search from.
* @return the index within this sequence of the last occurrence of the
* specified substring.
- * @throws java.lang.NullPointerException if <code>str</code> is
- * <code>null</code>.
*/
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, 0, count,
- str.toCharArray(), 0, str.length(), fromIndex);
+ str.toCharArray(), 0, str.length(), fromIndex);
}
/**
@@ -1385,8 +1401,8 @@
* is never reversed.
*
* Let <i>n</i> be the character length of this character sequence
- * (not the length in <code>char</code> values) just prior to
- * execution of the <code>reverse</code> method. Then the
+ * (not the length in {@code char} values) just prior to
+ * execution of the {@code reverse} method. Then the
* character at index <i>k</i> in the new character sequence is
* equal to the character at index <i>n-k-1</i> in the old
* character sequence.
@@ -1394,56 +1410,61 @@
* <p>Note that the reverse operation may result in producing
* surrogate pairs that were unpaired low-surrogates and
* high-surrogates before the operation. For example, reversing
- * "\uDC00\uD800" produces "\uD800\uDC00" which is
+ * "\u005CuDC00\u005CuD800" produces "\u005CuD800\u005CuDC00" which is
* a valid surrogate pair.
*
* @return a reference to this object.
* @hide
*/
public AbstractStringBuilder reverse() {
- boolean hasSurrogate = false;
+ boolean hasSurrogates = false;
int n = count - 1;
- for (int j = (n-1) >> 1; j >= 0; --j) {
- char temp = value[j];
- char temp2 = value[n - j];
- if (!hasSurrogate) {
- hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
- || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
+ for (int j = (n-1) >> 1; j >= 0; j--) {
+ int k = n - j;
+ char cj = value[j];
+ char ck = value[k];
+ value[j] = ck;
+ value[k] = cj;
+ if (Character.isSurrogate(cj) ||
+ Character.isSurrogate(ck)) {
+ hasSurrogates = true;
}
- value[j] = temp2;
- value[n - j] = temp;
}
- if (hasSurrogate) {
- // Reverse back all valid surrogate pairs
- for (int i = 0; i < count - 1; i++) {
- char c2 = value[i];
- if (Character.isLowSurrogate(c2)) {
- char c1 = value[i + 1];
- if (Character.isHighSurrogate(c1)) {
- value[i++] = c1;
- value[i] = c2;
- }
- }
- }
+ if (hasSurrogates) {
+ reverseAllValidSurrogatePairs();
}
return this;
}
+ /** Outlined helper method for reverse() */
+ private void reverseAllValidSurrogatePairs() {
+ for (int i = 0; i < count - 1; i++) {
+ char c2 = value[i];
+ if (Character.isLowSurrogate(c2)) {
+ char c1 = value[i + 1];
+ if (Character.isHighSurrogate(c1)) {
+ value[i++] = c1;
+ value[i] = c2;
+ }
+ }
+ }
+ }
+
/**
* Returns a string representing the data in this sequence.
- * A new <code>String</code> object is allocated and initialized to
+ * A new {@code String} object is allocated and initialized to
* contain the character sequence currently represented by this
- * object. This <code>String</code> is then returned. Subsequent
+ * object. This {@code String} is then returned. Subsequent
* changes to this sequence do not affect the contents of the
- * <code>String</code>.
+ * {@code String}.
*
* @return a string representation of this sequence of characters.
- * @hide
*/
+ @Override
public abstract String toString();
/**
- * Needed by <tt>String</tt> for the contentEquals method.
+ * Needed by {@code String} for the contentEquals method.
*/
final char[] getValue() {
return value;
diff --git a/ojluni/src/main/java/java/lang/Character.java b/ojluni/src/main/java/java/lang/Character.java
index 11d2fe3..ac04a7d 100644
--- a/ojluni/src/main/java/java/lang/Character.java
+++ b/ojluni/src/main/java/java/lang/Character.java
@@ -670,8 +670,14 @@
* This name must be the same as the block identifier.
*/
private UnicodeBlock(String idName) {
+ this(idName, true);
+ }
+
+ private UnicodeBlock(String idName, boolean isMap) {
super(idName);
- map.put(idName, this);
+ if (isMap) {
+ map.put(idName, this);
+ }
}
/**
@@ -1252,7 +1258,7 @@
*/
@Deprecated
public static final UnicodeBlock SURROGATES_AREA =
- new UnicodeBlock("SURROGATES_AREA");
+ new UnicodeBlock("SURROGATES_AREA", false);
/**
* Constant for the "Syriac" Unicode character block.
diff --git a/ojluni/src/main/java/java/lang/ClassCastException.java b/ojluni/src/main/java/java/lang/ClassCastException.java
old mode 100755
new mode 100644
index fc9b261..e4ca76c
--- a/ojluni/src/main/java/java/lang/ClassCastException.java
+++ b/ojluni/src/main/java/java/lang/ClassCastException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
* Thrown to indicate that the code has attempted to cast an object
* to a subclass of which it is not an instance. For example, the
* following code generates a <code>ClassCastException</code>:
- * <p><blockquote><pre>
+ * <blockquote><pre>
* Object x = new Integer(0);
* System.out.println((String)x);
* </pre></blockquote>
diff --git a/ojluni/src/main/java/java/lang/Comparable.java b/ojluni/src/main/java/java/lang/Comparable.java
old mode 100755
new mode 100644
index c049323..c14e493
--- a/ojluni/src/main/java/java/lang/Comparable.java
+++ b/ojluni/src/main/java/java/lang/Comparable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,7 +56,7 @@
* method.<p>
*
* For example, if one adds two keys <tt>a</tt> and <tt>b</tt> such that
- * <tt>(!a.equals(b) && a.compareTo(b) == 0)</tt> to a sorted
+ * {@code (!a.equals(b) && a.compareTo(b) == 0)} to a sorted
* set that does not use an explicit comparator, the second <tt>add</tt>
* operation returns false (and the size of the sorted set does not increase)
* because <tt>a</tt> and <tt>b</tt> are equivalent from the sorted set's
@@ -93,7 +93,6 @@
* @see java.util.Comparator
* @since 1.2
*/
-
public interface Comparable<T> {
/**
* Compares this object with the specified object for order. Returns a
diff --git a/ojluni/src/main/java/java/lang/Deprecated.java b/ojluni/src/main/java/java/lang/Deprecated.java
old mode 100755
new mode 100644
index 2b1546b..58a0691
--- a/ojluni/src/main/java/java/lang/Deprecated.java
+++ b/ojluni/src/main/java/java/lang/Deprecated.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,7 @@
*
* @author Neal Gafter
* @since 1.5
+ * @jls 9.6.3.6 @Deprecated
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/ojluni/src/main/java/java/lang/Double.java b/ojluni/src/main/java/java/lang/Double.java
old mode 100755
new mode 100644
index 59f8088..2bc2bf3
--- a/ojluni/src/main/java/java/lang/Double.java
+++ b/ojluni/src/main/java/java/lang/Double.java
@@ -26,6 +26,7 @@
package java.lang;
+import sun.misc.FloatingDecimal;
import sun.misc.FpUtils;
import sun.misc.DoubleConsts;
@@ -135,6 +136,7 @@
*
* @since JDK1.1
*/
+ @SuppressWarnings("unchecked")
public static final Class<Double> TYPE = (Class<Double>) double[].class.getComponentType();
/**
@@ -146,7 +148,7 @@
* <li>Otherwise, the result is a string that represents the sign and
* magnitude (absolute value) of the argument. If the sign is negative,
* the first character of the result is '{@code -}'
- * (<code>'\u002D'</code>); if the sign is positive, no sign character
+ * ({@code '\u005Cu002D'}); if the sign is positive, no sign character
* appears in the result. As for the magnitude <i>m</i>:
* <ul>
* <li>If <i>m</i> is infinity, it is represented by the characters
@@ -162,7 +164,7 @@
* <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less
* than 10<sup>7</sup>, then it is represented as the integer part of
* <i>m</i>, in decimal form with no leading zeroes, followed by
- * '{@code .}' (<code>'\u002E'</code>), followed by one or
+ * '{@code .}' ({@code '\u005Cu002E'}), followed by one or
* more decimal digits representing the fractional part of <i>m</i>.
*
* <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or
@@ -174,9 +176,9 @@
* 10<sup><i>n</i></sup> so that 1 ≤ <i>a</i> {@literal <} 10. The
* magnitude is then represented as the integer part of <i>a</i>,
* as a single decimal digit, followed by '{@code .}'
- * (<code>'\u002E'</code>), followed by decimal digits
+ * ({@code '\u005Cu002E'}), followed by decimal digits
* representing the fractional part of <i>a</i>, followed by the
- * letter '{@code E}' (<code>'\u0045'</code>), followed
+ * letter '{@code E}' ({@code '\u005Cu0045'}), followed
* by a representation of <i>n</i> as a decimal integer, as
* produced by the method {@link Integer#toString(int)}.
* </ul>
@@ -200,7 +202,7 @@
* @return a string representation of the argument.
*/
public static String toString(double d) {
- return FloatingDecimal.getThreadLocalInstance().loadDouble(d).toJavaFormatString();
+ return FloatingDecimal.toJavaFormatString(d);
}
/**
@@ -214,7 +216,7 @@
* <li>Otherwise, the result is a string that represents the sign
* and magnitude of the argument. If the sign is negative, the
* first character of the result is '{@code -}'
- * (<code>'\u002D'</code>); if the sign is positive, no sign
+ * ({@code '\u005Cu002D'}); if the sign is positive, no sign
* character appears in the result. As for the magnitude <i>m</i>:
*
* <ul>
@@ -255,7 +257,7 @@
* </ul>
*
* <table border>
- * <caption><h3>Examples</h3></caption>
+ * <caption>Examples</caption>
* <tr><th>Floating-point Value</th><th>Hexadecimal String</th>
* <tr><td>{@code 1.0}</td> <td>{@code 0x1.0p0}</td>
* <tr><td>{@code -1.0}</td> <td>{@code -0x1.0p0}</td>
@@ -283,14 +285,14 @@
* 7.19.6.1; however, the output of this method is more
* tightly specified.
*/
- if (!FpUtils.isFinite(d) )
+ if (!isFinite(d) )
// For infinity and NaN, use the decimal output.
return Double.toString(d);
else {
// Initialized to maximum size of output.
- StringBuffer answer = new StringBuffer(24);
+ StringBuilder answer = new StringBuilder(24);
- if (FpUtils.rawCopySign(1.0, d) == -1.0) // value is negative,
+ if (Math.copySign(1.0, d) == -1.0) // value is negative,
answer.append("-"); // so append sign info
answer.append("0x");
@@ -299,8 +301,7 @@
if(d == 0.0) {
answer.append("0.0p0");
- }
- else {
+ } else {
boolean subnormal = (d < DoubleConsts.MIN_NORMAL);
// Isolate significand bits and OR in a high-order bit
@@ -323,13 +324,14 @@
"0":
signif.replaceFirst("0{1,12}$", ""));
+ answer.append('p');
// If the value is subnormal, use the E_min exponent
// value for double; otherwise, extract and report d's
// exponent (the representation of a subnormal uses
// E_min -1).
- answer.append("p" + (subnormal ?
- DoubleConsts.MIN_EXPONENT:
- FpUtils.getExponent(d) ));
+ answer.append(subnormal ?
+ DoubleConsts.MIN_EXPONENT:
+ Math.getExponent(d));
}
return answer.toString();
}
@@ -360,15 +362,11 @@
* <dd><i>SignedInteger</i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>HexFloatingPointLiteral</i>:
* <dd> <i>HexSignificand BinaryExponent FloatTypeSuffix<sub>opt</sub></i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>HexSignificand:</i>
* <dd><i>HexNumeral</i>
@@ -379,15 +377,11 @@
* </i>{@code .} <i>HexDigits</i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>BinaryExponent:</i>
* <dd><i>BinaryExponentIndicator SignedInteger</i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>BinaryExponentIndicator:</i>
* <dd>{@code p}
@@ -452,8 +446,7 @@
* a {@code NumberFormatException} be thrown, the regular
* expression below can be used to screen the input string:
*
- * <code>
- * <pre>
+ * <pre>{@code
* final String Digits = "(\\p{Digit}+)";
* final String HexDigits = "(\\p{XDigit}+)";
* // an exponent is 'e' or 'E' followed by an optionally
@@ -473,7 +466,7 @@
* // in addition to strings of floating-point literals, the
* // two sub-patterns below are simplifications of the grammar
* // productions from section 3.10.2 of
- * // <cite>The Java™ Language Specification</cite>.
+ * // The Java Language Specification.
*
* // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
* "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
@@ -498,8 +491,7 @@
* else {
* // Perform suitable alternative action
* }
- * </pre>
- * </code>
+ * }</pre>
*
* @param s the string to be parsed.
* @return a {@code Double} object holding the value
@@ -508,7 +500,7 @@
* parsable number.
*/
public static Double valueOf(String s) throws NumberFormatException {
- return new Double(FloatingDecimal.getThreadLocalInstance().readJavaFormatString(s).doubleValue());
+ return new Double(parseDouble(s));
}
/**
@@ -544,7 +536,7 @@
* @since 1.2
*/
public static double parseDouble(String s) throws NumberFormatException {
- return FloatingDecimal.getThreadLocalInstance().readJavaFormatString(s).doubleValue();
+ return FloatingDecimal.parseDouble(s);
}
/**
@@ -555,7 +547,7 @@
* @return {@code true} if the value of the argument is NaN;
* {@code false} otherwise.
*/
- static public boolean isNaN(double v) {
+ public static boolean isNaN(double v) {
return (v != v);
}
@@ -567,7 +559,7 @@
* @return {@code true} if the value of the argument is positive
* infinity or negative infinity; {@code false} otherwise.
*/
- static public boolean isInfinite(double v) {
+ public static boolean isInfinite(double v) {
return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
}
@@ -614,8 +606,7 @@
* @see java.lang.Double#valueOf(java.lang.String)
*/
public Double(String s) throws NumberFormatException {
- // REMIND: this is inefficient
- this(valueOf(s).doubleValue());
+ value = parseDouble(s);
}
/**
@@ -655,11 +646,12 @@
}
/**
- * Returns the value of this {@code Double} as a {@code byte} (by
- * casting to a {@code byte}).
+ * Returns the value of this {@code Double} as a {@code byte}
+ * after a narrowing primitive conversion.
*
* @return the {@code double} value represented by this object
* converted to type {@code byte}
+ * @jls 5.1.3 Narrowing Primitive Conversions
* @since JDK1.1
*/
public byte byteValue() {
@@ -667,11 +659,12 @@
}
/**
- * Returns the value of this {@code Double} as a
- * {@code short} (by casting to a {@code short}).
+ * Returns the value of this {@code Double} as a {@code short}
+ * after a narrowing primitive conversion.
*
* @return the {@code double} value represented by this object
* converted to type {@code short}
+ * @jls 5.1.3 Narrowing Primitive Conversions
* @since JDK1.1
*/
public short shortValue() {
@@ -679,8 +672,9 @@
}
/**
- * Returns the value of this {@code Double} as an
- * {@code int} (by casting to type {@code int}).
+ * Returns the value of this {@code Double} as an {@code int}
+ * after a narrowing primitive conversion.
+ * @jls 5.1.3 Narrowing Primitive Conversions
*
* @return the {@code double} value represented by this object
* converted to type {@code int}
@@ -690,22 +684,24 @@
}
/**
- * Returns the value of this {@code Double} as a
- * {@code long} (by casting to type {@code long}).
+ * Returns the value of this {@code Double} as a {@code long}
+ * after a narrowing primitive conversion.
*
* @return the {@code double} value represented by this object
* converted to type {@code long}
+ * @jls 5.1.3 Narrowing Primitive Conversions
*/
public long longValue() {
return (long)value;
}
/**
- * Returns the {@code float} value of this
- * {@code Double} object.
+ * Returns the value of this {@code Double} as a {@code float}
+ * after a narrowing primitive conversion.
*
* @return the {@code double} value represented by this object
* converted to type {@code float}
+ * @jls 5.1.3 Narrowing Primitive Conversions
* @since JDK1.0
*/
public float floatValue() {
@@ -713,13 +709,12 @@
}
/**
- * Returns the {@code double} value of this
- * {@code Double} object.
+ * Returns the {@code double} value of this {@code Double} object.
*
* @return the {@code double} value represented by this object
*/
public double doubleValue() {
- return (double)value;
+ return value;
}
/**
@@ -743,6 +738,7 @@
*
* @return a {@code hash code} value for this object.
*/
+ @Override
public int hashCode() {
return Double.hashCode(value);
}
@@ -912,13 +908,13 @@
* <p>In all other cases, let <i>s</i>, <i>e</i>, and <i>m</i> be three
* values that can be computed from the argument:
*
- * <blockquote><pre>
- * int s = ((bits >> 63) == 0) ? 1 : -1;
- * int e = (int)((bits >> 52) & 0x7ffL);
+ * <blockquote><pre>{@code
+ * int s = ((bits >> 63) == 0) ? 1 : -1;
+ * int e = (int)((bits >> 52) & 0x7ffL);
* long m = (e == 0) ?
- * (bits & 0xfffffffffffffL) << 1 :
+ * (bits & 0xfffffffffffffL) << 1 :
* (bits & 0xfffffffffffffL) | 0x10000000000000L;
- * </pre></blockquote>
+ * }</pre></blockquote>
*
* Then the floating-point result equals the value of the mathematical
* expression <i>s</i>·<i>m</i>·2<sup><i>e</i>-1075</sup>.
diff --git a/ojluni/src/main/java/java/lang/Float.java b/ojluni/src/main/java/java/lang/Float.java
old mode 100755
new mode 100644
index d75953e..32bd625
--- a/ojluni/src/main/java/java/lang/Float.java
+++ b/ojluni/src/main/java/java/lang/Float.java
@@ -26,7 +26,7 @@
package java.lang;
-import sun.misc.FpUtils;
+import sun.misc.FloatingDecimal;
import sun.misc.FloatConsts;
import sun.misc.DoubleConsts;
@@ -134,6 +134,7 @@
*
* @since JDK1.1
*/
+ @SuppressWarnings("unchecked")
public static final Class<Float> TYPE = (Class<Float>) float[].class.getComponentType();
/**
@@ -145,7 +146,7 @@
* <li>Otherwise, the result is a string that represents the sign and
* magnitude (absolute value) of the argument. If the sign is
* negative, the first character of the result is
- * '{@code -}' (<code>'\u002D'</code>); if the sign is
+ * '{@code -}' ({@code '\u005Cu002D'}); if the sign is
* positive, no sign character appears in the result. As for
* the magnitude <i>m</i>:
* <ul>
@@ -161,7 +162,7 @@
* less than 10<sup>7</sup>, then it is represented as the
* integer part of <i>m</i>, in decimal form with no leading
* zeroes, followed by '{@code .}'
- * (<code>'\u002E'</code>), followed by one or more
+ * ({@code '\u005Cu002E'}), followed by one or more
* decimal digits representing the fractional part of
* <i>m</i>.
* <li> If <i>m</i> is less than 10<sup>-3</sup> or greater than or
@@ -173,10 +174,10 @@
* 10<sup><i>n</i></sup> so that 1 ≤ <i>a</i> {@literal <} 10.
* The magnitude is then represented as the integer part of
* <i>a</i>, as a single decimal digit, followed by
- * '{@code .}' (<code>'\u002E'</code>), followed by
+ * '{@code .}' ({@code '\u005Cu002E'}), followed by
* decimal digits representing the fractional part of
* <i>a</i>, followed by the letter '{@code E}'
- * (<code>'\u0045'</code>), followed by a representation
+ * ({@code '\u005Cu0045'}), followed by a representation
* of <i>n</i> as a decimal integer, as produced by the
* method {@link java.lang.Integer#toString(int)}.
*
@@ -203,7 +204,7 @@
* @return a string representation of the argument.
*/
public static String toString(float f) {
- return FloatingDecimal.getThreadLocalInstance().loadFloat(f).toJavaFormatString();
+ return FloatingDecimal.toJavaFormatString(f);
}
/**
@@ -217,7 +218,7 @@
* <li>Otherwise, the result is a string that represents the sign and
* magnitude (absolute value) of the argument. If the sign is negative,
* the first character of the result is '{@code -}'
- * (<code>'\u002D'</code>); if the sign is positive, no sign character
+ * ({@code '\u005Cu002D'}); if the sign is positive, no sign character
* appears in the result. As for the magnitude <i>m</i>:
*
* <ul>
@@ -258,7 +259,7 @@
* </ul>
*
* <table border>
- * <caption><h3>Examples</h3></caption>
+ * <caption>Examples</caption>
* <tr><th>Floating-point Value</th><th>Hexadecimal String</th>
* <tr><td>{@code 1.0}</td> <td>{@code 0x1.0p0}</td>
* <tr><td>{@code -1.0}</td> <td>{@code -0x1.0p0}</td>
@@ -286,10 +287,10 @@
// Adjust exponent to create subnormal double, then
// replace subnormal double exponent with subnormal float
// exponent
- String s = Double.toHexString(FpUtils.scalb((double)f,
- /* -1022+126 */
- DoubleConsts.MIN_EXPONENT-
- FloatConsts.MIN_EXPONENT));
+ String s = Double.toHexString(Math.scalb((double)f,
+ /* -1022+126 */
+ DoubleConsts.MIN_EXPONENT-
+ FloatConsts.MIN_EXPONENT));
return s.replaceFirst("p-1022$", "p-126");
}
else // double string will be the same as float string
@@ -321,15 +322,11 @@
* <dd><i>SignedInteger</i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>HexFloatingPointLiteral</i>:
* <dd> <i>HexSignificand BinaryExponent FloatTypeSuffix<sub>opt</sub></i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>HexSignificand:</i>
* <dd><i>HexNumeral</i>
@@ -340,15 +337,11 @@
* </i>{@code .} <i>HexDigits</i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>BinaryExponent:</i>
* <dd><i>BinaryExponentIndicator SignedInteger</i>
* </dl>
*
- * <p>
- *
* <dl>
* <dt><i>BinaryExponentIndicator:</i>
* <dd>{@code p}
@@ -421,7 +414,7 @@
* parsable number.
*/
public static Float valueOf(String s) throws NumberFormatException {
- return new Float(FloatingDecimal.getThreadLocalInstance().readJavaFormatString(s).floatValue());
+ return new Float(parseFloat(s));
}
/**
@@ -456,7 +449,7 @@
* @since 1.2
*/
public static float parseFloat(String s) throws NumberFormatException {
- return FloatingDecimal.getThreadLocalInstance().readJavaFormatString(s).floatValue();
+ return FloatingDecimal.parseFloat(s);
}
/**
@@ -467,7 +460,7 @@
* @return {@code true} if the argument is NaN;
* {@code false} otherwise.
*/
- static public boolean isNaN(float v) {
+ public static boolean isNaN(float v) {
return (v != v);
}
@@ -479,10 +472,11 @@
* @return {@code true} if the argument is positive infinity or
* negative infinity; {@code false} otherwise.
*/
- static public boolean isInfinite(float v) {
+ public static boolean isInfinite(float v) {
return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
}
+
/**
* Returns {@code true} if the argument is a finite floating-point
* value; returns {@code false} otherwise (for NaN and infinity
@@ -536,8 +530,7 @@
* @see java.lang.Float#valueOf(java.lang.String)
*/
public Float(String s) throws NumberFormatException {
- // REMIND: this is inefficient
- this(valueOf(s).floatValue());
+ value = parseFloat(s);
}
/**
@@ -577,22 +570,24 @@
}
/**
- * Returns the value of this {@code Float} as a {@code byte} (by
- * casting to a {@code byte}).
+ * Returns the value of this {@code Float} as a {@code byte} after
+ * a narrowing primitive conversion.
*
* @return the {@code float} value represented by this object
* converted to type {@code byte}
+ * @jls 5.1.3 Narrowing Primitive Conversions
*/
public byte byteValue() {
return (byte)value;
}
/**
- * Returns the value of this {@code Float} as a {@code short} (by
- * casting to a {@code short}).
+ * Returns the value of this {@code Float} as a {@code short}
+ * after a narrowing primitive conversion.
*
* @return the {@code float} value represented by this object
* converted to type {@code short}
+ * @jls 5.1.3 Narrowing Primitive Conversions
* @since JDK1.1
*/
public short shortValue() {
@@ -600,22 +595,24 @@
}
/**
- * Returns the value of this {@code Float} as an {@code int} (by
- * casting to type {@code int}).
+ * Returns the value of this {@code Float} as an {@code int} after
+ * a narrowing primitive conversion.
*
* @return the {@code float} value represented by this object
* converted to type {@code int}
+ * @jls 5.1.3 Narrowing Primitive Conversions
*/
public int intValue() {
return (int)value;
}
/**
- * Returns value of this {@code Float} as a {@code long} (by
- * casting to type {@code long}).
+ * Returns value of this {@code Float} as a {@code long} after a
+ * narrowing primitive conversion.
*
* @return the {@code float} value represented by this object
* converted to type {@code long}
+ * @jls 5.1.3 Narrowing Primitive Conversions
*/
public long longValue() {
return (long)value;
@@ -631,11 +628,12 @@
}
/**
- * Returns the {@code double} value of this {@code Float} object.
+ * Returns the value of this {@code Float} as a {@code double}
+ * after a widening primitive conversion.
*
* @return the {@code float} value represented by this
- * object is converted to type {@code double} and the
- * result of the conversion is returned.
+ * object converted to type {@code double}
+ * @jls 5.1.2 Widening Primitive Conversions
*/
public double doubleValue() {
return (double)value;
@@ -650,8 +648,9 @@
*
* @return a hash code value for this object.
*/
+ @Override
public int hashCode() {
- return floatToIntBits(value);
+ return Float.hashCode(value);
}
/**
@@ -815,13 +814,13 @@
* <p>In all other cases, let <i>s</i>, <i>e</i>, and <i>m</i> be three
* values that can be computed from the argument:
*
- * <blockquote><pre>
- * int s = ((bits >> 31) == 0) ? 1 : -1;
- * int e = ((bits >> 23) & 0xff);
+ * <blockquote><pre>{@code
+ * int s = ((bits >> 31) == 0) ? 1 : -1;
+ * int e = ((bits >> 23) & 0xff);
* int m = (e == 0) ?
- * (bits & 0x7fffff) << 1 :
+ * (bits & 0x7fffff) << 1 :
* (bits & 0x7fffff) | 0x800000;
- * </pre></blockquote>
+ * }</pre></blockquote>
*
* Then the floating-point result equals the value of the mathematical
* expression <i>s</i>·<i>m</i>·2<sup><i>e</i>-150</sup>.
diff --git a/ojluni/src/main/java/java/lang/FloatingDecimal.java b/ojluni/src/main/java/java/lang/FloatingDecimal.java
deleted file mode 100755
index d27c5ae..0000000
--- a/ojluni/src/main/java/java/lang/FloatingDecimal.java
+++ /dev/null
@@ -1,2476 +0,0 @@
- /*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.lang;
-
-import sun.misc.FpUtils;
-import sun.misc.FDBigInt;
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
-import java.util.regex.*;
-
-public class FloatingDecimal {
- boolean isExceptional;
- boolean isNegative;
- int decExponent;
- char digits[];
- int nDigits;
- int bigIntExp;
- int bigIntNBits;
- boolean mustSetRoundDir = false;
- boolean fromHex = false;
- int roundDir = 0; // set by doubleValue
-
- /*
- * Constants of the implementation
- * Most are IEEE-754 related.
- * (There are more really boring constants at the end.)
- */
- static final long signMask = 0x8000000000000000L;
- static final long expMask = 0x7ff0000000000000L;
- static final long fractMask= ~(signMask|expMask);
- static final int expShift = 52;
- static final int expBias = 1023;
- static final long fractHOB = ( 1L<<expShift ); // assumed High-Order bit
- static final long expOne = ((long)expBias)<<expShift; // exponent of 1.0
- static final int maxSmallBinExp = 62;
- static final int minSmallBinExp = -( 63 / 3 );
- static final int maxDecimalDigits = 15;
- static final int maxDecimalExponent = 308;
- static final int minDecimalExponent = -324;
- static final int bigDecimalExponent = 324; // i.e. abs(minDecimalExponent)
-
- static final long highbyte = 0xff00000000000000L;
- static final long highbit = 0x8000000000000000L;
- static final long lowbytes = ~highbyte;
-
- static final int singleSignMask = 0x80000000;
- static final int singleExpMask = 0x7f800000;
- static final int singleFractMask = ~(singleSignMask|singleExpMask);
- static final int singleExpShift = 23;
- static final int singleFractHOB = 1<<singleExpShift;
- static final int singleExpBias = 127;
- static final int singleMaxDecimalDigits = 7;
- static final int singleMaxDecimalExponent = 38;
- static final int singleMinDecimalExponent = -45;
-
- static final int intDecimalDigits = 9;
-
- /*
- * count number of bits from high-order 1 bit to low-order 1 bit,
- * inclusive.
- */
- private static int
- countBits( long v ){
- //
- // the strategy is to shift until we get a non-zero sign bit
- // then shift until we have no bits left, counting the difference.
- // we do byte shifting as a hack. Hope it helps.
- //
- if ( v == 0L ) return 0;
-
- while ( ( v & highbyte ) == 0L ){
- v <<= 8;
- }
- while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
- v <<= 1;
- }
-
- int n = 0;
- while (( v & lowbytes ) != 0L ){
- v <<= 8;
- n += 8;
- }
- while ( v != 0L ){
- v <<= 1;
- n += 1;
- }
- return n;
- }
-
- /*
- * Keep big powers of 5 handy for future reference.
- */
- private static FDBigInt b5p[];
-
- private static synchronized FDBigInt
- big5pow( int p ){
- assert p >= 0 : p; // negative power of 5
- if ( b5p == null ){
- b5p = new FDBigInt[ p+1 ];
- }else if (b5p.length <= p ){
- FDBigInt t[] = new FDBigInt[ p+1 ];
- System.arraycopy( b5p, 0, t, 0, b5p.length );
- b5p = t;
- }
- if ( b5p[p] != null )
- return b5p[p];
- else if ( p < small5pow.length )
- return b5p[p] = new FDBigInt( small5pow[p] );
- else if ( p < long5pow.length )
- return b5p[p] = new FDBigInt( long5pow[p] );
- else {
- // construct the value.
- // recursively.
- int q, r;
- // in order to compute 5^p,
- // compute its square root, 5^(p/2) and square.
- // or, let q = p / 2, r = p -q, then
- // 5^p = 5^(q+r) = 5^q * 5^r
- q = p >> 1;
- r = p - q;
- FDBigInt bigq = b5p[q];
- if ( bigq == null )
- bigq = big5pow ( q );
- if ( r < small5pow.length ){
- return (b5p[p] = bigq.mult( small5pow[r] ) );
- }else{
- FDBigInt bigr = b5p[ r ];
- if ( bigr == null )
- bigr = big5pow( r );
- return (b5p[p] = bigq.mult( bigr ) );
- }
- }
- }
-
- //
- // a common operation
- //
- private static FDBigInt
- multPow52( FDBigInt v, int p5, int p2 ){
- if ( p5 != 0 ){
- if ( p5 < small5pow.length ){
- v = v.mult( small5pow[p5] );
- } else {
- v = v.mult( big5pow( p5 ) );
- }
- }
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
- }
- return v;
- }
-
- //
- // another common operation
- //
- private static FDBigInt
- constructPow52( int p5, int p2 ){
- FDBigInt v = new FDBigInt( big5pow( p5 ) );
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
- }
- return v;
- }
-
- /*
- * Make a floating double into a FDBigInt.
- * This could also be structured as a FDBigInt
- * constructor, but we'd have to build a lot of knowledge
- * about floating-point representation into it, and we don't want to.
- *
- * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
- * bigIntExp and bigIntNBits
- *
- */
- private FDBigInt
- doubleToBigInt( double dval ){
- long lbits = Double.doubleToLongBits( dval ) & ~signMask;
- int binexp = (int)(lbits >>> expShift);
- lbits &= fractMask;
- if ( binexp > 0 ){
- lbits |= fractHOB;
- } else {
- assert lbits != 0L : lbits; // doubleToBigInt(0.0)
- binexp +=1;
- while ( (lbits & fractHOB ) == 0L){
- lbits <<= 1;
- binexp -= 1;
- }
- }
- binexp -= expBias;
- int nbits = countBits( lbits );
- /*
- * We now know where the high-order 1 bit is,
- * and we know how many there are.
- */
- int lowOrderZeros = expShift+1-nbits;
- lbits >>>= lowOrderZeros;
-
- bigIntExp = binexp+1-nbits;
- bigIntNBits = nbits;
- return new FDBigInt( lbits );
- }
-
- /*
- * Compute a number that is the ULP of the given value,
- * for purposes of addition/subtraction. Generally easy.
- * More difficult if subtracting and the argument
- * is a normalized a power of 2, as the ULP changes at these points.
- */
- private static double ulp( double dval, boolean subtracting ){
- long lbits = Double.doubleToLongBits( dval ) & ~signMask;
- int binexp = (int)(lbits >>> expShift);
- double ulpval;
- if ( subtracting && ( binexp >= expShift ) && ((lbits&fractMask) == 0L) ){
- // for subtraction from normalized, powers of 2,
- // use next-smaller exponent
- binexp -= 1;
- }
- if ( binexp > expShift ){
- ulpval = Double.longBitsToDouble( ((long)(binexp-expShift))<<expShift );
- } else if ( binexp == 0 ){
- ulpval = Double.MIN_VALUE;
- } else {
- ulpval = Double.longBitsToDouble( 1L<<(binexp-1) );
- }
- if ( subtracting ) ulpval = - ulpval;
-
- return ulpval;
- }
-
- /*
- * Round a double to a float.
- * In addition to the fraction bits of the double,
- * look at the class instance variable roundDir,
- * which should help us avoid double-rounding error.
- * roundDir was set in hardValueOf if the estimate was
- * close enough, but not exact. It tells us which direction
- * of rounding is preferred.
- */
- float
- stickyRound( double dval ){
- long lbits = Double.doubleToLongBits( dval );
- long binexp = lbits & expMask;
- if ( binexp == 0L || binexp == expMask ){
- // what we have here is special.
- // don't worry, the right thing will happen.
- return (float) dval;
- }
- lbits += (long)roundDir; // hack-o-matic.
- return (float)Double.longBitsToDouble( lbits );
- }
-
-
- /*
- * This is the easy subcase --
- * all the significant bits, after scaling, are held in lvalue.
- * negSign and decExponent tell us what processing and scaling
- * has already been done. Exceptional cases have already been
- * stripped out.
- * In particular:
- * lvalue is a finite number (not Inf, nor NaN)
- * lvalue > 0L (not zero, nor negative).
- *
- * The only reason that we develop the digits here, rather than
- * calling on Long.toString() is that we can do it a little faster,
- * and besides want to treat trailing 0s specially. If Long.toString
- * changes, we should re-evaluate this strategy!
- */
- private void
- developLongDigits( int decExponent, long lvalue, long insignificant ){
- char digits[];
- int ndigits;
- int digitno;
- int c;
- //
- // Discard non-significant low-order bits, while rounding,
- // up to insignificant value.
- int i;
- for ( i = 0; insignificant >= 10L; i++ )
- insignificant /= 10L;
- if ( i != 0 ){
- long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
- long residue = lvalue % pow10;
- lvalue /= pow10;
- decExponent += i;
- if ( residue >= (pow10>>1) ){
- // round up based on the low-order bits we're discarding
- lvalue++;
- }
- }
- if ( lvalue <= Integer.MAX_VALUE ){
- assert lvalue > 0L : lvalue; // lvalue <= 0
- // even easier subcase!
- // can do int arithmetic rather than long!
- int ivalue = (int)lvalue;
- ndigits = 10;
- digits = (char[])(perThreadBuffer.get());
- digitno = ndigits-1;
- c = ivalue%10;
- ivalue /= 10;
- while ( c == 0 ){
- decExponent++;
- c = ivalue%10;
- ivalue /= 10;
- }
- while ( ivalue != 0){
- digits[digitno--] = (char)(c+'0');
- decExponent++;
- c = ivalue%10;
- ivalue /= 10;
- }
- digits[digitno] = (char)(c+'0');
- } else {
- // same algorithm as above (same bugs, too )
- // but using long arithmetic.
- ndigits = 20;
- digits = (char[])(perThreadBuffer.get());
- digitno = ndigits-1;
- c = (int)(lvalue%10L);
- lvalue /= 10L;
- while ( c == 0 ){
- decExponent++;
- c = (int)(lvalue%10L);
- lvalue /= 10L;
- }
- while ( lvalue != 0L ){
- digits[digitno--] = (char)(c+'0');
- decExponent++;
- c = (int)(lvalue%10L);
- lvalue /= 10;
- }
- digits[digitno] = (char)(c+'0');
- }
- char result [];
- ndigits -= digitno;
- result = new char[ ndigits ];
- System.arraycopy( digits, digitno, result, 0, ndigits );
- this.digits = result;
- this.decExponent = decExponent+1;
- this.nDigits = ndigits;
- }
-
- //
- // add one to the least significant digit.
- // in the unlikely event there is a carry out,
- // deal with it.
- // assert that this will only happen where there
- // is only one digit, e.g. (float)1e-44 seems to do it.
- //
- private void
- roundup(){
- int i;
- int q = digits[ i = (nDigits-1)];
- if ( q == '9' ){
- while ( q == '9' && i > 0 ){
- digits[i] = '0';
- q = digits[--i];
- }
- if ( q == '9' ){
- // carryout! High-order 1, rest 0s, larger exp.
- decExponent += 1;
- digits[0] = '1';
- return;
- }
- // else fall through.
- }
- digits[i] = (char)(q+1);
- }
-
- private FloatingDecimal() {}
-
- private static final ThreadLocal<FloatingDecimal> TL_INSTANCE = new ThreadLocal<FloatingDecimal>() {
- @Override protected FloatingDecimal initialValue() {
- return new FloatingDecimal();
- }
- };
- public static FloatingDecimal getThreadLocalInstance() {
- return TL_INSTANCE.get();
- }
-
- /*
- * FIRST IMPORTANT LOAD: DOUBLE
- */
- public FloatingDecimal loadDouble(double d) {
- long dBits = Double.doubleToLongBits( d );
- long fractBits;
- int binExp;
- int nSignificantBits;
-
- mustSetRoundDir = false;
- fromHex = false;
- roundDir = 0;
-
- // discover and delete sign
- if ( (dBits&signMask) != 0 ){
- isNegative = true;
- dBits ^= signMask;
- } else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (int)( (dBits&expMask) >> expShift );
- fractBits = dBits&fractMask;
- if ( binExp == (int)(expMask>>expShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
- }
- nDigits = digits.length;
- return this;
- }
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0L ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- return this;
- }
- while ( (fractBits&fractHOB) == 0L ){
- fractBits <<= 1;
- binExp -= 1;
- }
- nSignificantBits = expShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= fractHOB;
- nSignificantBits = expShift+1;
- }
- binExp -= expBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, fractBits, nSignificantBits );
- return this;
- }
-
- /*
- * SECOND IMPORTANT LOAD: SINGLE
- */
- public FloatingDecimal loadFloat(float f) {
- int fBits = Float.floatToIntBits( f );
- int fractBits;
- int binExp;
- int nSignificantBits;
-
- mustSetRoundDir = false;
- fromHex = false;
- roundDir = 0;
-
- // discover and delete sign
- if ( (fBits&singleSignMask) != 0 ){
- isNegative = true;
- fBits ^= singleSignMask;
- } else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (int)( (fBits&singleExpMask) >> singleExpShift );
- fractBits = fBits&singleFractMask;
- if ( binExp == (int)(singleExpMask>>singleExpShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
- }
- nDigits = digits.length;
- return this;
- }
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0 ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- return this;
- }
- while ( (fractBits&singleFractHOB) == 0 ){
- fractBits <<= 1;
- binExp -= 1;
- }
- nSignificantBits = singleExpShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= singleFractHOB;
- nSignificantBits = singleExpShift+1;
- }
- binExp -= singleExpBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
- return this;
- }
-
- private void
- dtoa( int binExp, long fractBits, int nSignificantBits )
- {
- int nFractBits; // number of significant bits of fractBits;
- int nTinyBits; // number of these to the right of the point.
- int decExp;
-
- // Examine number. Determine if it is an easy case,
- // which we can do pretty trivially using float/long conversion,
- // or whether we must do real work.
- nFractBits = countBits( fractBits );
- nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
- if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
- // Look more closely at the number to decide if,
- // with scaling by 10^nTinyBits, the result will fit in
- // a long.
- if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64 ) ){
- /*
- * We can do this:
- * take the fraction bits, which are normalized.
- * (a) nTinyBits == 0: Shift left or right appropriately
- * to align the binary point at the extreme right, i.e.
- * where a long int point is expected to be. The integer
- * result is easily converted to a string.
- * (b) nTinyBits > 0: Shift right by expShift-nFractBits,
- * which effectively converts to long and scales by
- * 2^nTinyBits. Then multiply by 5^nTinyBits to
- * complete the scaling. We know this won't overflow
- * because we just counted the number of bits necessary
- * in the result. The integer you get from this can
- * then be converted to a string pretty easily.
- */
- long halfULP;
- if ( nTinyBits == 0 ) {
- if ( binExp > nSignificantBits ){
- halfULP = 1L << ( binExp-nSignificantBits-1);
- } else {
- halfULP = 0L;
- }
- if ( binExp >= expShift ){
- fractBits <<= (binExp-expShift);
- } else {
- fractBits >>>= (expShift-binExp) ;
- }
- developLongDigits( 0, fractBits, halfULP );
- return;
- }
- /*
- * The following causes excess digits to be printed
- * out in the single-float case. Our manipulation of
- * halfULP here is apparently not correct. If we
- * better understand how this works, perhaps we can
- * use this special case again. But for the time being,
- * we do not.
- * else {
- * fractBits >>>= expShift+1-nFractBits;
- * fractBits *= long5pow[ nTinyBits ];
- * halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
- * developLongDigits( -nTinyBits, fractBits, halfULP );
- * return;
- * }
- */
- }
- }
- /*
- * This is the hard case. We are going to compute large positive
- * integers B and S and integer decExp, s.t.
- * d = ( B / S ) * 10^decExp
- * 1 <= B / S < 10
- * Obvious choices are:
- * decExp = floor( log10(d) )
- * B = d * 2^nTinyBits * 10^max( 0, -decExp )
- * S = 10^max( 0, decExp) * 2^nTinyBits
- * (noting that nTinyBits has already been forced to non-negative)
- * I am also going to compute a large positive integer
- * M = (1/2^nSignificantBits) * 2^nTinyBits * 10^max( 0, -decExp )
- * i.e. M is (1/2) of the ULP of d, scaled like B.
- * When we iterate through dividing B/S and picking off the
- * quotient bits, we will know when to stop when the remainder
- * is <= M.
- *
- * We keep track of powers of 2 and powers of 5.
- */
-
- /*
- * Estimate decimal exponent. (If it is small-ish,
- * we could double-check.)
- *
- * First, scale the mantissa bits such that 1 <= d2 < 2.
- * We are then going to estimate
- * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5)
- * and so we can estimate
- * log10(d) ~=~ log10(d2) + binExp * log10(2)
- * take the floor and call it decExp.
- * FIXME -- use more precise constants here. It costs no more.
- */
- double d2 = Double.longBitsToDouble(
- expOne | ( fractBits &~ fractHOB ) );
- decExp = (int)Math.floor(
- (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 );
- int B2, B5; // powers of 2 and powers of 5, respectively, in B
- int S2, S5; // powers of 2 and powers of 5, respectively, in S
- int M2, M5; // powers of 2 and powers of 5, respectively, in M
- int Bbits; // binary digits needed to represent B, approx.
- int tenSbits; // binary digits needed to represent 10*S, approx.
- FDBigInt Sval, Bval, Mval;
-
- B5 = Math.max( 0, -decExp );
- B2 = B5 + nTinyBits + binExp;
-
- S5 = Math.max( 0, decExp );
- S2 = S5 + nTinyBits;
-
- M5 = B5;
- M2 = B2 - nSignificantBits;
-
- /*
- * the long integer fractBits contains the (nFractBits) interesting
- * bits from the mantissa of d ( hidden 1 added if necessary) followed
- * by (expShift+1-nFractBits) zeros. In the interest of compactness,
- * I will shift out those zeros before turning fractBits into a
- * FDBigInt. The resulting whole number will be
- * d * 2^(nFractBits-1-binExp).
- */
- fractBits >>>= (expShift+1-nFractBits);
- B2 -= nFractBits-1;
- int common2factor = Math.min( B2, S2 );
- B2 -= common2factor;
- S2 -= common2factor;
- M2 -= common2factor;
-
- /*
- * HACK!! For exact powers of two, the next smallest number
- * is only half as far away as we think (because the meaning of
- * ULP changes at power-of-two bounds) for this reason, we
- * hack M2. Hope this works.
- */
- if ( nFractBits == 1 )
- M2 -= 1;
-
- if ( M2 < 0 ){
- // oops.
- // since we cannot scale M down far enough,
- // we must scale the other values up.
- B2 -= M2;
- S2 -= M2;
- M2 = 0;
- }
- /*
- * Construct, Scale, iterate.
- * Some day, we'll write a stopping test that takes
- * account of the asymmetry of the spacing of floating-point
- * numbers below perfect powers of 2
- * 26 Sept 96 is not that day.
- * So we use a symmetric test.
- */
- char digits[] = this.digits = new char[18];
- int ndigit = 0;
- boolean low, high;
- long lowDigitDifference;
- int q;
-
- /*
- * Detect the special cases where all the numbers we are about
- * to compute will fit in int or long integers.
- * In these cases, we will avoid doing FDBigInt arithmetic.
- * We use the same algorithms, except that we "normalize"
- * our FDBigInts before iterating. This is to make division easier,
- * as it makes our fist guess (quotient of high-order words)
- * more accurate!
- *
- * Some day, we'll write a stopping test that takes
- * account of the asymmetry of the spacing of floating-point
- * numbers below perfect powers of 2
- * 26 Sept 96 is not that day.
- * So we use a symmetric test.
- */
- Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 ));
- tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 ));
- if ( Bbits < 64 && tenSbits < 64){
- if ( Bbits < 32 && tenSbits < 32){
- // wa-hoo! They're all ints!
- int b = ((int)fractBits * small5pow[B5] ) << B2;
- int s = small5pow[S5] << S2;
- int m = small5pow[M5] << M2;
- int tens = s * 10;
- /*
- * Unroll the first iteration. If our decExp estimate
- * was too high, our first quotient will be zero. In this
- * case, we discard it and decrement decExp.
- */
- ndigit = 0;
- q = b / s;
- b = 10 * ( b % s );
- m *= 10;
- low = (b < m );
- high = (b+m > tens );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
- } else {
- digits[ndigit++] = (char)('0' + q);
- }
- /*
- * HACK! Java spec sez that we always have at least
- * one digit after the . in either F- or E-form output.
- * Thus we will need more than one digit if we're using
- * E-form
- */
- if ( decExp < -3 || decExp >= 8 ){
- high = low = false;
- }
- while( ! low && ! high ){
- q = b / s;
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- if ( m > 0L ){
- low = (b < m );
- high = (b+m > tens );
- } else {
- // hack -- m might overflow!
- // in this case, it is certainly > b,
- // which won't
- // and b+m > tens, too, since that has overflowed
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
- } else {
- // still good! they're all longs!
- long b = (fractBits * long5pow[B5] ) << B2;
- long s = long5pow[S5] << S2;
- long m = long5pow[M5] << M2;
- long tens = s * 10L;
- /*
- * Unroll the first iteration. If our decExp estimate
- * was too high, our first quotient will be zero. In this
- * case, we discard it and decrement decExp.
- */
- ndigit = 0;
- q = (int) ( b / s );
- b = 10L * ( b % s );
- m *= 10L;
- low = (b < m );
- high = (b+m > tens );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
- } else {
- digits[ndigit++] = (char)('0' + q);
- }
- /*
- * HACK! Java spec sez that we always have at least
- * one digit after the . in either F- or E-form output.
- * Thus we will need more than one digit if we're using
- * E-form
- */
- if ( decExp < -3 || decExp >= 8 ){
- high = low = false;
- }
- while( ! low && ! high ){
- q = (int) ( b / s );
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- if ( m > 0L ){
- low = (b < m );
- high = (b+m > tens );
- } else {
- // hack -- m might overflow!
- // in this case, it is certainly > b,
- // which won't
- // and b+m > tens, too, since that has overflowed
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
- }
- } else {
- FDBigInt tenSval;
- int shiftBias;
-
- /*
- * We really must do FDBigInt arithmetic.
- * Fist, construct our FDBigInt initial values.
- */
- Bval = multPow52( new FDBigInt( fractBits ), B5, B2 );
- Sval = constructPow52( S5, S2 );
- Mval = constructPow52( M5, M2 );
-
-
- // normalize so that division works better
- Bval.lshiftMe( shiftBias = Sval.normalizeMe() );
- Mval.lshiftMe( shiftBias );
- tenSval = Sval.mult( 10 );
- /*
- * Unroll the first iteration. If our decExp estimate
- * was too high, our first quotient will be zero. In this
- * case, we discard it and decrement decExp.
- */
- ndigit = 0;
- q = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
- } else {
- digits[ndigit++] = (char)('0' + q);
- }
- /*
- * HACK! Java spec sez that we always have at least
- * one digit after the . in either F- or E-form output.
- * Thus we will need more than one digit if we're using
- * E-form
- */
- if ( decExp < -3 || decExp >= 8 ){
- high = low = false;
- }
- while( ! low && ! high ){
- q = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- assert q < 10 : q; // excessively large digit
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- digits[ndigit++] = (char)('0' + q);
- }
- if ( high && low ){
- Bval.lshiftMe(1);
- lowDigitDifference = Bval.cmp(tenSval);
- } else
- lowDigitDifference = 0L; // this here only for flow analysis!
- }
- this.decExponent = decExp+1;
- this.digits = digits;
- this.nDigits = ndigit;
- /*
- * Last digit gets rounded based on stopping condition.
- */
- if ( high ){
- if ( low ){
- if ( lowDigitDifference == 0L ){
- // it's a tie!
- // choose based on which digits we like.
- if ( (digits[nDigits-1]&1) != 0 ) roundup();
- } else if ( lowDigitDifference > 0 ){
- roundup();
- }
- } else {
- roundup();
- }
- }
- }
-
- public String
- toString(){
- // most brain-dead version
- StringBuffer result = new StringBuffer( nDigits+8 );
- if ( isNegative ){ result.append( '-' ); }
- if ( isExceptional ){
- result.append( digits, 0, nDigits );
- } else {
- result.append( "0.");
- result.append( digits, 0, nDigits );
- result.append('e');
- result.append( decExponent );
- }
- return new String(result);
- }
-
- public String toJavaFormatString() {
- char result[] = (char[])(perThreadBuffer.get());
- int i = getChars(result);
- return new String(result, 0, i);
- }
-
- private int getChars(char[] result) {
- assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
- int i = 0;
- if (isNegative) { result[0] = '-'; i = 1; }
- if (isExceptional) {
- System.arraycopy(digits, 0, result, i, nDigits);
- i += nDigits;
- } else {
- if (decExponent > 0 && decExponent < 8) {
- // case with digits.digits
- int charLength = Math.min(nDigits, decExponent);
- System.arraycopy(digits, 0, result, i, charLength);
- i += charLength;
- if (charLength < decExponent) {
- charLength = decExponent-charLength;
- System.arraycopy(zero, 0, result, i, charLength);
- i += charLength;
- result[i++] = '.';
- result[i++] = '0';
- } else {
- result[i++] = '.';
- if (charLength < nDigits) {
- int t = nDigits - charLength;
- System.arraycopy(digits, charLength, result, i, t);
- i += t;
- } else {
- result[i++] = '0';
- }
- }
- } else if (decExponent <=0 && decExponent > -3) {
- // case with 0.digits
- result[i++] = '0';
- result[i++] = '.';
- if (decExponent != 0) {
- System.arraycopy(zero, 0, result, i, -decExponent);
- i -= decExponent;
- }
- System.arraycopy(digits, 0, result, i, nDigits);
- i += nDigits;
- } else {
- // case with digit.digitsEexponent
- result[i++] = digits[0];
- result[i++] = '.';
- if (nDigits > 1) {
- System.arraycopy(digits, 1, result, i, nDigits-1);
- i += nDigits-1;
- } else {
- result[i++] = '0';
- }
- result[i++] = 'E';
- int e;
- if (decExponent <= 0) {
- result[i++] = '-';
- e = -decExponent+1;
- } else {
- e = decExponent-1;
- }
- // decExponent has 1, 2, or 3, digits
- if (e <= 9) {
- result[i++] = (char)(e+'0');
- } else if (e <= 99) {
- result[i++] = (char)(e/10 +'0');
- result[i++] = (char)(e%10 + '0');
- } else {
- result[i++] = (char)(e/100+'0');
- e %= 100;
- result[i++] = (char)(e/10+'0');
- result[i++] = (char)(e%10 + '0');
- }
- }
- }
- return i;
- }
-
- // Per-thread buffer for string/stringbuffer conversion
- private static ThreadLocal perThreadBuffer = new ThreadLocal() {
- protected synchronized Object initialValue() {
- return new char[26];
- }
- };
-
- public void appendTo(AbstractStringBuilder buf) {
- if (isNegative) { buf.append('-'); }
- if (isExceptional) {
- buf.append(digits, 0 , nDigits);
- return;
- }
- if (decExponent > 0 && decExponent < 8) {
- // print digits.digits.
- int charLength = Math.min(nDigits, decExponent);
- buf.append(digits, 0 , charLength);
- if (charLength < decExponent) {
- charLength = decExponent-charLength;
- buf.append(zero, 0 , charLength);
- buf.append(".0");
- } else {
- buf.append('.');
- if (charLength < nDigits) {
- buf.append(digits, charLength, nDigits - charLength);
- } else {
- buf.append('0');
- }
- }
- } else if (decExponent <=0 && decExponent > -3) {
- buf.append("0.");
- if (decExponent != 0) {
- buf.append(zero, 0, -decExponent);
- }
- buf.append(digits, 0, nDigits);
- } else {
- buf.append(digits[0]);
- buf.append('.');
- if (nDigits > 1) {
- buf.append(digits, 1, nDigits-1);
- } else {
- buf.append('0');
- }
- buf.append('E');
- int e;
- if (decExponent <= 0) {
- buf.append('-');
- e = -decExponent + 1;
- } else {
- e = decExponent - 1;
- }
- // decExponent has 1, 2, or 3, digits
- if (e <= 9) {
- buf.append((char)(e + '0'));
- } else if (e <= 99) {
- buf.append((char)(e/10 + '0'));
- buf.append((char)(e%10 + '0'));
- } else {
- buf.append((char)(e/100 + '0'));
- e %= 100;
- buf.append((char)(e/10 + '0'));
- buf.append((char)(e%10 + '0'));
- }
- }
- }
-
- public FloatingDecimal
- readJavaFormatString( String in ) throws NumberFormatException {
- boolean isNegative = false;
- boolean signSeen = false;
- int decExp;
- char c;
-
- parseNumber:
- try{
- in = in.trim(); // don't fool around with white space.
- // throws NullPointerException if null
- int l = in.length();
- if ( l == 0 ) throw new NumberFormatException("empty String");
- int i = 0;
- switch ( c = in.charAt( i ) ){
- case '-':
- isNegative = true;
- //FALLTHROUGH
- case '+':
- i++;
- signSeen = true;
- }
-
- // Check for NaN and Infinity strings
- c = in.charAt(i);
- if(c == 'N' || c == 'I') { // possible NaN or infinity
- boolean potentialNaN = false;
- char targetChars[] = null; // char array of "NaN" or "Infinity"
-
- if(c == 'N') {
- targetChars = notANumber;
- potentialNaN = true;
- } else {
- targetChars = infinity;
- }
-
- // compare Input string to "NaN" or "Infinity"
- int j = 0;
- while(i < l && j < targetChars.length) {
- if(in.charAt(i) == targetChars[j]) {
- i++; j++;
- }
- else // something is amiss, throw exception
- break parseNumber;
- }
-
- // For the candidate string to be a NaN or infinity,
- // all characters in input string and target char[]
- // must be matched ==> j must equal targetChars.length
- // and i must equal l
- if( (j == targetChars.length) && (i == l) ) { // return NaN or infinity
- return (potentialNaN ? loadDouble(Double.NaN) // NaN has no sign
- : loadDouble(isNegative?
- Double.NEGATIVE_INFINITY:
- Double.POSITIVE_INFINITY)) ;
- }
- else { // something went wrong, throw exception
- break parseNumber;
- }
-
- } else if (c == '0') { // check for hexadecimal floating-point number
- if (l > i+1 ) {
- char ch = in.charAt(i+1);
- if (ch == 'x' || ch == 'X' ) // possible hex string
- return parseHexString(in);
- }
- } // look for and process decimal floating-point string
-
- char[] digits = new char[ l ];
- int nDigits= 0;
- boolean decSeen = false;
- int decPt = 0;
- int nLeadZero = 0;
- int nTrailZero= 0;
- digitLoop:
- while ( i < l ){
- switch ( c = in.charAt( i ) ){
- case '0':
- if ( nDigits > 0 ){
- nTrailZero += 1;
- } else {
- nLeadZero += 1;
- }
- break; // out of switch.
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- while ( nTrailZero > 0 ){
- digits[nDigits++] = '0';
- nTrailZero -= 1;
- }
- digits[nDigits++] = c;
- break; // out of switch.
- case '.':
- if ( decSeen ){
- // already saw one ., this is the 2nd.
- throw new NumberFormatException("multiple points");
- }
- decPt = i;
- if ( signSeen ){
- decPt -= 1;
- }
- decSeen = true;
- break; // out of switch.
- default:
- break digitLoop;
- }
- i++;
- }
- /*
- * At this point, we've scanned all the digits and decimal
- * point we're going to see. Trim off leading and trailing
- * zeros, which will just confuse us later, and adjust
- * our initial decimal exponent accordingly.
- * To review:
- * we have seen i total characters.
- * nLeadZero of them were zeros before any other digits.
- * nTrailZero of them were zeros after any other digits.
- * if ( decSeen ), then a . was seen after decPt characters
- * ( including leading zeros which have been discarded )
- * nDigits characters were neither lead nor trailing
- * zeros, nor point
- */
- /*
- * special hack: if we saw no non-zero digits, then the
- * answer is zero!
- * Unfortunately, we feel honor-bound to keep parsing!
- */
- if ( nDigits == 0 ){
- digits = zero;
- nDigits = 1;
- if ( nLeadZero == 0 ){
- // we saw NO DIGITS AT ALL,
- // not even a crummy 0!
- // this is not allowed.
- break parseNumber; // go throw exception
- }
-
- }
-
- /* Our initial exponent is decPt, adjusted by the number of
- * discarded zeros. Or, if there was no decPt,
- * then its just nDigits adjusted by discarded trailing zeros.
- */
- if ( decSeen ){
- decExp = decPt - nLeadZero;
- } else {
- decExp = nDigits+nTrailZero;
- }
-
- /*
- * Look for 'e' or 'E' and an optionally signed integer.
- */
- if ( (i < l) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
- int expSign = 1;
- int expVal = 0;
- int reallyBig = Integer.MAX_VALUE / 10;
- boolean expOverflow = false;
- switch( in.charAt(++i) ){
- case '-':
- expSign = -1;
- //FALLTHROUGH
- case '+':
- i++;
- }
- int expAt = i;
- expLoop:
- while ( i < l ){
- if ( expVal >= reallyBig ){
- // the next character will cause integer
- // overflow.
- expOverflow = true;
- }
- switch ( c = in.charAt(i++) ){
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- expVal = expVal*10 + ( (int)c - (int)'0' );
- continue;
- default:
- i--; // back up.
- break expLoop; // stop parsing exponent.
- }
- }
- int expLimit = bigDecimalExponent+nDigits+nTrailZero;
- if ( expOverflow || ( expVal > expLimit ) ){
- //
- // The intent here is to end up with
- // infinity or zero, as appropriate.
- // The reason for yielding such a small decExponent,
- // rather than something intuitive such as
- // expSign*Integer.MAX_VALUE, is that this value
- // is subject to further manipulation in
- // doubleValue() and floatValue(), and I don't want
- // it to be able to cause overflow there!
- // (The only way we can get into trouble here is for
- // really outrageous nDigits+nTrailZero, such as 2 billion. )
- //
- decExp = expSign*expLimit;
- } else {
- // this should not overflow, since we tested
- // for expVal > (MAX+N), where N >= abs(decExp)
- decExp = decExp + expSign*expVal;
- }
-
- // if we saw something not a digit ( or end of string )
- // after the [Ee][+-], without seeing any digits at all
- // this is certainly an error. If we saw some digits,
- // but then some trailing garbage, that might be ok.
- // so we just fall through in that case.
- // HUMBUG
- if ( i == expAt )
- break parseNumber; // certainly bad
- }
- /*
- * We parsed everything we could.
- * If there are leftovers, then this is not good input!
- */
- if ( i < l &&
- ((i != l - 1) ||
- (in.charAt(i) != 'f' &&
- in.charAt(i) != 'F' &&
- in.charAt(i) != 'd' &&
- in.charAt(i) != 'D'))) {
- break parseNumber; // go throw exception
- }
-
- this.isNegative = isNegative;
- this.decExponent = decExp;
- this.digits = digits;
- this.nDigits = nDigits;
- this.isExceptional = false;
- return this;
- } catch ( StringIndexOutOfBoundsException e ){ }
- throw new NumberFormatException("For input string: \"" + in + "\"");
- }
-
- /*
- * Take a FloatingDecimal, which we presumably just scanned in,
- * and find out what its value is, as a double.
- *
- * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
- * ROUNDING DIRECTION in case the result is really destined
- * for a single-precision float.
- */
-
- public strictfp double doubleValue(){
- int kDigits = Math.min( nDigits, maxDecimalDigits+1 );
- long lValue;
- double dValue;
- double rValue, tValue;
-
- // First, check for NaN and Infinity values
- if(digits == infinity || digits == notANumber) {
- if(digits == notANumber)
- return Double.NaN;
- else
- return (isNegative?Double.NEGATIVE_INFINITY:Double.POSITIVE_INFINITY);
- }
- else {
- if (mustSetRoundDir) {
- roundDir = 0;
- }
- /*
- * convert the lead kDigits to a long integer.
- */
- // (special performance hack: start to do it using int)
- int iValue = (int)digits[0]-(int)'0';
- int iDigits = Math.min( kDigits, intDecimalDigits );
- for ( int i=1; i < iDigits; i++ ){
- iValue = iValue*10 + (int)digits[i]-(int)'0';
- }
- lValue = (long)iValue;
- for ( int i=iDigits; i < kDigits; i++ ){
- lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
- }
- dValue = (double)lValue;
- int exp = decExponent-kDigits;
- /*
- * lValue now contains a long integer with the value of
- * the first kDigits digits of the number.
- * dValue contains the (double) of the same.
- */
-
- if ( nDigits <= maxDecimalDigits ){
- /*
- * possibly an easy case.
- * We know that the digits can be represented
- * exactly. And if the exponent isn't too outrageous,
- * the whole thing can be done with one operation,
- * thus one rounding error.
- * Note that all our constructors trim all leading and
- * trailing zeros, so simple values (including zero)
- * will always end up here
- */
- if (exp == 0 || dValue == 0.0)
- return (isNegative)? -dValue : dValue; // small floating integer
- else if ( exp >= 0 ){
- if ( exp <= maxSmallTen ){
- /*
- * Can get the answer with one operation,
- * thus one roundoff.
- */
- rValue = dValue * small10pow[exp];
- if ( mustSetRoundDir ){
- tValue = rValue / small10pow[exp];
- roundDir = ( tValue == dValue ) ? 0
- :( tValue < dValue ) ? 1
- : -1;
- }
- return (isNegative)? -rValue : rValue;
- }
- int slop = maxDecimalDigits - kDigits;
- if ( exp <= maxSmallTen+slop ){
- /*
- * We can multiply dValue by 10^(slop)
- * and it is still "small" and exact.
- * Then we can multiply by 10^(exp-slop)
- * with one rounding.
- */
- dValue *= small10pow[slop];
- rValue = dValue * small10pow[exp-slop];
-
- if ( mustSetRoundDir ){
- tValue = rValue / small10pow[exp-slop];
- roundDir = ( tValue == dValue ) ? 0
- :( tValue < dValue ) ? 1
- : -1;
- }
- return (isNegative)? -rValue : rValue;
- }
- /*
- * Else we have a hard case with a positive exp.
- */
- } else {
- if ( exp >= -maxSmallTen ){
- /*
- * Can get the answer in one division.
- */
- rValue = dValue / small10pow[-exp];
- tValue = rValue * small10pow[-exp];
- if ( mustSetRoundDir ){
- roundDir = ( tValue == dValue ) ? 0
- :( tValue < dValue ) ? 1
- : -1;
- }
- return (isNegative)? -rValue : rValue;
- }
- /*
- * Else we have a hard case with a negative exp.
- */
- }
- }
-
- /*
- * Harder cases:
- * The sum of digits plus exponent is greater than
- * what we think we can do with one error.
- *
- * Start by approximating the right answer by,
- * naively, scaling by powers of 10.
- */
- if ( exp > 0 ){
- if ( decExponent > maxDecimalExponent+1 ){
- /*
- * Lets face it. This is going to be
- * Infinity. Cut to the chase.
- */
- return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
- }
- if ( (exp&15) != 0 ){
- dValue *= small10pow[exp&15];
- }
- if ( (exp>>=4) != 0 ){
- int j;
- for( j = 0; exp > 1; j++, exp>>=1 ){
- if ( (exp&1)!=0)
- dValue *= big10pow[j];
- }
- /*
- * The reason for the weird exp > 1 condition
- * in the above loop was so that the last multiply
- * would get unrolled. We handle it here.
- * It could overflow.
- */
- double t = dValue * big10pow[j];
- if ( Double.isInfinite( t ) ){
- /*
- * It did overflow.
- * Look more closely at the result.
- * If the exponent is just one too large,
- * then use the maximum finite as our estimate
- * value. Else call the result infinity
- * and punt it.
- * ( I presume this could happen because
- * rounding forces the result here to be
- * an ULP or two larger than
- * Double.MAX_VALUE ).
- */
- t = dValue / 2.0;
- t *= big10pow[j];
- if ( Double.isInfinite( t ) ){
- return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
- }
- t = Double.MAX_VALUE;
- }
- dValue = t;
- }
- } else if ( exp < 0 ){
- exp = -exp;
- if ( decExponent < minDecimalExponent-1 ){
- /*
- * Lets face it. This is going to be
- * zero. Cut to the chase.
- */
- return (isNegative)? -0.0 : 0.0;
- }
- if ( (exp&15) != 0 ){
- dValue /= small10pow[exp&15];
- }
- if ( (exp>>=4) != 0 ){
- int j;
- for( j = 0; exp > 1; j++, exp>>=1 ){
- if ( (exp&1)!=0)
- dValue *= tiny10pow[j];
- }
- /*
- * The reason for the weird exp > 1 condition
- * in the above loop was so that the last multiply
- * would get unrolled. We handle it here.
- * It could underflow.
- */
- double t = dValue * tiny10pow[j];
- if ( t == 0.0 ){
- /*
- * It did underflow.
- * Look more closely at the result.
- * If the exponent is just one too small,
- * then use the minimum finite as our estimate
- * value. Else call the result 0.0
- * and punt it.
- * ( I presume this could happen because
- * rounding forces the result here to be
- * an ULP or two less than
- * Double.MIN_VALUE ).
- */
- t = dValue * 2.0;
- t *= tiny10pow[j];
- if ( t == 0.0 ){
- return (isNegative)? -0.0 : 0.0;
- }
- t = Double.MIN_VALUE;
- }
- dValue = t;
- }
- }
-
- /*
- * dValue is now approximately the result.
- * The hard part is adjusting it, by comparison
- * with FDBigInt arithmetic.
- * Formulate the EXACT big-number result as
- * bigD0 * 10^exp
- */
- FDBigInt bigD0 = new FDBigInt( lValue, digits, kDigits, nDigits );
- exp = decExponent - nDigits;
-
- correctionLoop:
- while(true){
- /* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
- * bigIntExp and bigIntNBits
- */
- FDBigInt bigB = doubleToBigInt( dValue );
-
- /*
- * Scale bigD, bigB appropriately for
- * big-integer operations.
- * Naively, we multiply by powers of ten
- * and powers of two. What we actually do
- * is keep track of the powers of 5 and
- * powers of 2 we would use, then factor out
- * common divisors before doing the work.
- */
- int B2, B5; // powers of 2, 5 in bigB
- int D2, D5; // powers of 2, 5 in bigD
- int Ulp2; // powers of 2 in halfUlp.
- if ( exp >= 0 ){
- B2 = B5 = 0;
- D2 = D5 = exp;
- } else {
- B2 = B5 = -exp;
- D2 = D5 = 0;
- }
- if ( bigIntExp >= 0 ){
- B2 += bigIntExp;
- } else {
- D2 -= bigIntExp;
- }
- Ulp2 = B2;
- // shift bigB and bigD left by a number s. t.
- // halfUlp is still an integer.
- int hulpbias;
- if ( bigIntExp+bigIntNBits <= -expBias+1 ){
- // This is going to be a denormalized number
- // (if not actually zero).
- // half an ULP is at 2^-(expBias+expShift+1)
- hulpbias = bigIntExp+ expBias + expShift;
- } else {
- hulpbias = expShift + 2 - bigIntNBits;
- }
- B2 += hulpbias;
- D2 += hulpbias;
- // if there are common factors of 2, we might just as well
- // factor them out, as they add nothing useful.
- int common2 = Math.min( B2, Math.min( D2, Ulp2 ) );
- B2 -= common2;
- D2 -= common2;
- Ulp2 -= common2;
- // do multiplications by powers of 5 and 2
- bigB = multPow52( bigB, B5, B2 );
- FDBigInt bigD = multPow52( new FDBigInt( bigD0 ), D5, D2 );
- //
- // to recap:
- // bigB is the scaled-big-int version of our floating-point
- // candidate.
- // bigD is the scaled-big-int version of the exact value
- // as we understand it.
- // halfUlp is 1/2 an ulp of bigB, except for special cases
- // of exact powers of 2
- //
- // the plan is to compare bigB with bigD, and if the difference
- // is less than halfUlp, then we're satisfied. Otherwise,
- // use the ratio of difference to halfUlp to calculate a fudge
- // factor to add to the floating value, then go 'round again.
- //
- FDBigInt diff;
- int cmpResult;
- boolean overvalue;
- if ( (cmpResult = bigB.cmp( bigD ) ) > 0 ){
- overvalue = true; // our candidate is too big.
- diff = bigB.sub( bigD );
- if ( (bigIntNBits == 1) && (bigIntExp > -expBias+1) ){
- // candidate is a normalized exact power of 2 and
- // is too big. We will be subtracting.
- // For our purposes, ulp is the ulp of the
- // next smaller range.
- Ulp2 -= 1;
- if ( Ulp2 < 0 ){
- // rats. Cannot de-scale ulp this far.
- // must scale diff in other direction.
- Ulp2 = 0;
- diff.lshiftMe( 1 );
- }
- }
- } else if ( cmpResult < 0 ){
- overvalue = false; // our candidate is too small.
- diff = bigD.sub( bigB );
- } else {
- // the candidate is exactly right!
- // this happens with surprising frequency
- break correctionLoop;
- }
- FDBigInt halfUlp = constructPow52( B5, Ulp2 );
- if ( (cmpResult = diff.cmp( halfUlp ) ) < 0 ){
- // difference is small.
- // this is close enough
- if (mustSetRoundDir) {
- roundDir = overvalue ? -1 : 1;
- }
- break correctionLoop;
- } else if ( cmpResult == 0 ){
- // difference is exactly half an ULP
- // round to some other value maybe, then finish
- dValue += 0.5*ulp( dValue, overvalue );
- // should check for bigIntNBits == 1 here??
- if (mustSetRoundDir) {
- roundDir = overvalue ? -1 : 1;
- }
- break correctionLoop;
- } else {
- // difference is non-trivial.
- // could scale addend by ratio of difference to
- // halfUlp here, if we bothered to compute that difference.
- // Most of the time ( I hope ) it is about 1 anyway.
- dValue += ulp( dValue, overvalue );
- if ( dValue == 0.0 || dValue == Double.POSITIVE_INFINITY )
- break correctionLoop; // oops. Fell off end of range.
- continue; // try again.
- }
-
- }
- return (isNegative)? -dValue : dValue;
- }
- }
-
- /*
- * Take a FloatingDecimal, which we presumably just scanned in,
- * and find out what its value is, as a float.
- * This is distinct from doubleValue() to avoid the extremely
- * unlikely case of a double rounding error, wherein the conversion
- * to double has one rounding error, and the conversion of that double
- * to a float has another rounding error, IN THE WRONG DIRECTION,
- * ( because of the preference to a zero low-order bit ).
- */
-
- public strictfp float floatValue(){
- int kDigits = Math.min( nDigits, singleMaxDecimalDigits+1 );
- int iValue;
- float fValue;
-
- // First, check for NaN and Infinity values
- if(digits == infinity || digits == notANumber) {
- if(digits == notANumber)
- return Float.NaN;
- else
- return (isNegative?Float.NEGATIVE_INFINITY:Float.POSITIVE_INFINITY);
- }
- else {
- /*
- * convert the lead kDigits to an integer.
- */
- iValue = (int)digits[0]-(int)'0';
- for ( int i=1; i < kDigits; i++ ){
- iValue = iValue*10 + (int)digits[i]-(int)'0';
- }
- fValue = (float)iValue;
- int exp = decExponent-kDigits;
- /*
- * iValue now contains an integer with the value of
- * the first kDigits digits of the number.
- * fValue contains the (float) of the same.
- */
-
- if ( nDigits <= singleMaxDecimalDigits ){
- /*
- * possibly an easy case.
- * We know that the digits can be represented
- * exactly. And if the exponent isn't too outrageous,
- * the whole thing can be done with one operation,
- * thus one rounding error.
- * Note that all our constructors trim all leading and
- * trailing zeros, so simple values (including zero)
- * will always end up here.
- */
- if (exp == 0 || fValue == 0.0f)
- return (isNegative)? -fValue : fValue; // small floating integer
- else if ( exp >= 0 ){
- if ( exp <= singleMaxSmallTen ){
- /*
- * Can get the answer with one operation,
- * thus one roundoff.
- */
- fValue *= singleSmall10pow[exp];
- return (isNegative)? -fValue : fValue;
- }
- int slop = singleMaxDecimalDigits - kDigits;
- if ( exp <= singleMaxSmallTen+slop ){
- /*
- * We can multiply dValue by 10^(slop)
- * and it is still "small" and exact.
- * Then we can multiply by 10^(exp-slop)
- * with one rounding.
- */
- fValue *= singleSmall10pow[slop];
- fValue *= singleSmall10pow[exp-slop];
- return (isNegative)? -fValue : fValue;
- }
- /*
- * Else we have a hard case with a positive exp.
- */
- } else {
- if ( exp >= -singleMaxSmallTen ){
- /*
- * Can get the answer in one division.
- */
- fValue /= singleSmall10pow[-exp];
- return (isNegative)? -fValue : fValue;
- }
- /*
- * Else we have a hard case with a negative exp.
- */
- }
- } else if ( (decExponent >= nDigits) && (nDigits+decExponent <= maxDecimalDigits) ){
- /*
- * In double-precision, this is an exact floating integer.
- * So we can compute to double, then shorten to float
- * with one round, and get the right answer.
- *
- * First, finish accumulating digits.
- * Then convert that integer to a double, multiply
- * by the appropriate power of ten, and convert to float.
- */
- long lValue = (long)iValue;
- for ( int i=kDigits; i < nDigits; i++ ){
- lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
- }
- double dValue = (double)lValue;
- exp = decExponent-nDigits;
- dValue *= small10pow[exp];
- fValue = (float)dValue;
- return (isNegative)? -fValue : fValue;
-
- }
- /*
- * Harder cases:
- * The sum of digits plus exponent is greater than
- * what we think we can do with one error.
- *
- * Start by weeding out obviously out-of-range
- * results, then convert to double and go to
- * common hard-case code.
- */
- if ( decExponent > singleMaxDecimalExponent+1 ){
- /*
- * Lets face it. This is going to be
- * Infinity. Cut to the chase.
- */
- return (isNegative)? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
- } else if ( decExponent < singleMinDecimalExponent-1 ){
- /*
- * Lets face it. This is going to be
- * zero. Cut to the chase.
- */
- return (isNegative)? -0.0f : 0.0f;
- }
-
- /*
- * Here, we do 'way too much work, but throwing away
- * our partial results, and going and doing the whole
- * thing as double, then throwing away half the bits that computes
- * when we convert back to float.
- *
- * The alternative is to reproduce the whole multiple-precision
- * algorithm for float precision, or to try to parameterize it
- * for common usage. The former will take about 400 lines of code,
- * and the latter I tried without success. Thus the semi-hack
- * answer here.
- */
- mustSetRoundDir = !fromHex;
- double dValue = doubleValue();
- return stickyRound( dValue );
- }
- }
-
-
- /*
- * All the positive powers of 10 that can be
- * represented exactly in double/float.
- */
- private static final double small10pow[] = {
- 1.0e0,
- 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
- 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
- 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
- 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
- 1.0e21, 1.0e22
- };
-
- private static final float singleSmall10pow[] = {
- 1.0e0f,
- 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
- 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
- };
-
- private static final double big10pow[] = {
- 1e16, 1e32, 1e64, 1e128, 1e256 };
- private static final double tiny10pow[] = {
- 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
-
- private static final int maxSmallTen = small10pow.length-1;
- private static final int singleMaxSmallTen = singleSmall10pow.length-1;
-
- private static final int small5pow[] = {
- 1,
- 5,
- 5*5,
- 5*5*5,
- 5*5*5*5,
- 5*5*5*5*5,
- 5*5*5*5*5*5,
- 5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5*5
- };
-
-
- private static final long long5pow[] = {
- 1L,
- 5L,
- 5L*5,
- 5L*5*5,
- 5L*5*5*5,
- 5L*5*5*5*5,
- 5L*5*5*5*5*5,
- 5L*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- };
-
- // approximately ceil( log2( long5pow[i] ) )
- private static final int n5bits[] = {
- 0,
- 3,
- 5,
- 7,
- 10,
- 12,
- 14,
- 17,
- 19,
- 21,
- 24,
- 26,
- 28,
- 31,
- 33,
- 35,
- 38,
- 40,
- 42,
- 45,
- 47,
- 49,
- 52,
- 54,
- 56,
- 59,
- 61,
- };
-
- private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
- private static final char notANumber[] = { 'N', 'a', 'N' };
- private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
-
-
- /*
- * Grammar is compatible with hexadecimal floating-point constants
- * described in section 6.4.4.2 of the C99 specification.
- */
- private static Pattern hexFloatPattern = null;
- private static synchronized Pattern getHexFloatPattern() {
- if (hexFloatPattern == null) {
- hexFloatPattern = Pattern.compile(
- //1 234 56 7 8 9
- "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
- );
- }
- return hexFloatPattern;
- }
-
- /*
- * Convert string s to a suitable floating decimal; uses the
- * double constructor and set the roundDir variable appropriately
- * in case the value is later converted to a float.
- */
- FloatingDecimal parseHexString(String s) {
- // Verify string is a member of the hexadecimal floating-point
- // string language.
- Matcher m = getHexFloatPattern().matcher(s);
- boolean validInput = m.matches();
-
- if (!validInput) {
- // Input does not match pattern
- throw new NumberFormatException("For input string: \"" + s + "\"");
- } else { // validInput
- /*
- * We must isolate the sign, significand, and exponent
- * fields. The sign value is straightforward. Since
- * floating-point numbers are stored with a normalized
- * representation, the significand and exponent are
- * interrelated.
- *
- * After extracting the sign, we normalized the
- * significand as a hexadecimal value, calculating an
- * exponent adjust for any shifts made during
- * normalization. If the significand is zero, the
- * exponent doesn't need to be examined since the output
- * will be zero.
- *
- * Next the exponent in the input string is extracted.
- * Afterwards, the significand is normalized as a *binary*
- * value and the input value's normalized exponent can be
- * computed. The significand bits are copied into a
- * double significand; if the string has more logical bits
- * than can fit in a double, the extra bits affect the
- * round and sticky bits which are used to round the final
- * value.
- */
-
- // Extract significand sign
- String group1 = m.group(1);
- double sign = (( group1 == null ) || group1.equals("+"))? 1.0 : -1.0;
-
-
- // Extract Significand magnitude
- /*
- * Based on the form of the significand, calculate how the
- * binary exponent needs to be adjusted to create a
- * normalized *hexadecimal* floating-point number; that
- * is, a number where there is one nonzero hex digit to
- * the left of the (hexa)decimal point. Since we are
- * adjusting a binary, not hexadecimal exponent, the
- * exponent is adjusted by a multiple of 4.
- *
- * There are a number of significand scenarios to consider;
- * letters are used in indicate nonzero digits:
- *
- * 1. 000xxxx => x.xxx normalized
- * increase exponent by (number of x's - 1)*4
- *
- * 2. 000xxx.yyyy => x.xxyyyy normalized
- * increase exponent by (number of x's - 1)*4
- *
- * 3. .000yyy => y.yy normalized
- * decrease exponent by (number of zeros + 1)*4
- *
- * 4. 000.00000yyy => y.yy normalized
- * decrease exponent by (number of zeros to right of point + 1)*4
- *
- * If the significand is exactly zero, return a properly
- * signed zero.
- */
-
- String significandString =null;
- int signifLength = 0;
- int exponentAdjust = 0;
- {
- int leftDigits = 0; // number of meaningful digits to
- // left of "decimal" point
- // (leading zeros stripped)
- int rightDigits = 0; // number of digits to right of
- // "decimal" point; leading zeros
- // must always be accounted for
- /*
- * The significand is made up of either
- *
- * 1. group 4 entirely (integer portion only)
- *
- * OR
- *
- * 2. the fractional portion from group 7 plus any
- * (optional) integer portions from group 6.
- */
- String group4;
- if( (group4 = m.group(4)) != null) { // Integer-only significand
- // Leading zeros never matter on the integer portion
- significandString = stripLeadingZeros(group4);
- leftDigits = significandString.length();
- }
- else {
- // Group 6 is the optional integer; leading zeros
- // never matter on the integer portion
- String group6 = stripLeadingZeros(m.group(6));
- leftDigits = group6.length();
-
- // fraction
- String group7 = m.group(7);
- rightDigits = group7.length();
-
- // Turn "integer.fraction" into "integer"+"fraction"
- significandString =
- ((group6 == null)?"":group6) + // is the null
- // check necessary?
- group7;
- }
-
- significandString = stripLeadingZeros(significandString);
- signifLength = significandString.length();
-
- /*
- * Adjust exponent as described above
- */
- if (leftDigits >= 1) { // Cases 1 and 2
- exponentAdjust = 4*(leftDigits - 1);
- } else { // Cases 3 and 4
- exponentAdjust = -4*( rightDigits - signifLength + 1);
- }
-
- // If the significand is zero, the exponent doesn't
- // matter; return a properly signed zero.
-
- if (signifLength == 0) { // Only zeros in input
- return loadDouble(sign * 0.0);
- }
- }
-
- // Extract Exponent
- /*
- * Use an int to read in the exponent value; this should
- * provide more than sufficient range for non-contrived
- * inputs. If reading the exponent in as an int does
- * overflow, examine the sign of the exponent and
- * significand to determine what to do.
- */
- String group8 = m.group(8);
- boolean positiveExponent = ( group8 == null ) || group8.equals("+");
- long unsignedRawExponent;
- try {
- unsignedRawExponent = Integer.parseInt(m.group(9));
- }
- catch (NumberFormatException e) {
- // At this point, we know the exponent is
- // syntactically well-formed as a sequence of
- // digits. Therefore, if an NumberFormatException
- // is thrown, it must be due to overflowing int's
- // range. Also, at this point, we have already
- // checked for a zero significand. Thus the signs
- // of the exponent and significand determine the
- // final result:
- //
- // significand
- // + -
- // exponent + +infinity -infinity
- // - +0.0 -0.0
- return loadDouble(sign * (positiveExponent ?
- Double.POSITIVE_INFINITY : 0.0));
- }
-
- long rawExponent =
- (positiveExponent ? 1L : -1L) * // exponent sign
- unsignedRawExponent; // exponent magnitude
-
- // Calculate partially adjusted exponent
- long exponent = rawExponent + exponentAdjust ;
-
- // Starting copying non-zero bits into proper position in
- // a long; copy explicit bit too; this will be masked
- // later for normal values.
-
- boolean round = false;
- boolean sticky = false;
- int bitsCopied=0;
- int nextShift=0;
- long significand=0L;
- // First iteration is different, since we only copy
- // from the leading significand bit; one more exponent
- // adjust will be needed...
-
- // IMPORTANT: make leadingDigit a long to avoid
- // surprising shift semantics!
- long leadingDigit = getHexDigit(significandString, 0);
-
- /*
- * Left shift the leading digit (53 - (bit position of
- * leading 1 in digit)); this sets the top bit of the
- * significand to 1. The nextShift value is adjusted
- * to take into account the number of bit positions of
- * the leadingDigit actually used. Finally, the
- * exponent is adjusted to normalize the significand
- * as a binary value, not just a hex value.
- */
- if (leadingDigit == 1) {
- significand |= leadingDigit << 52;
- nextShift = 52 - 4;
- /* exponent += 0 */ }
- else if (leadingDigit <= 3) { // [2, 3]
- significand |= leadingDigit << 51;
- nextShift = 52 - 5;
- exponent += 1;
- }
- else if (leadingDigit <= 7) { // [4, 7]
- significand |= leadingDigit << 50;
- nextShift = 52 - 6;
- exponent += 2;
- }
- else if (leadingDigit <= 15) { // [8, f]
- significand |= leadingDigit << 49;
- nextShift = 52 - 7;
- exponent += 3;
- } else {
- throw new AssertionError("Result from digit conversion too large!");
- }
- // The preceding if-else could be replaced by a single
- // code block based on the high-order bit set in
- // leadingDigit. Given leadingOnePosition,
-
- // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
- // nextShift = 52 - (3 + leadingOnePosition);
- // exponent += (leadingOnePosition-1);
-
-
- /*
- * Now the exponent variable is equal to the normalized
- * binary exponent. Code below will make representation
- * adjustments if the exponent is incremented after
- * rounding (includes overflows to infinity) or if the
- * result is subnormal.
- */
-
- // Copy digit into significand until the significand can't
- // hold another full hex digit or there are no more input
- // hex digits.
- int i = 0;
- for(i = 1;
- i < signifLength && nextShift >= 0;
- i++) {
- long currentDigit = getHexDigit(significandString, i);
- significand |= (currentDigit << nextShift);
- nextShift-=4;
- }
-
- // After the above loop, the bulk of the string is copied.
- // Now, we must copy any partial hex digits into the
- // significand AND compute the round bit and start computing
- // sticky bit.
-
- if ( i < signifLength ) { // at least one hex input digit exists
- long currentDigit = getHexDigit(significandString, i);
-
- // from nextShift, figure out how many bits need
- // to be copied, if any
- switch(nextShift) { // must be negative
- case -1:
- // three bits need to be copied in; can
- // set round bit
- significand |= ((currentDigit & 0xEL) >> 1);
- round = (currentDigit & 0x1L) != 0L;
- break;
-
- case -2:
- // two bits need to be copied in; can
- // set round and start sticky
- significand |= ((currentDigit & 0xCL) >> 2);
- round = (currentDigit &0x2L) != 0L;
- sticky = (currentDigit & 0x1L) != 0;
- break;
-
- case -3:
- // one bit needs to be copied in
- significand |= ((currentDigit & 0x8L)>>3);
- // Now set round and start sticky, if possible
- round = (currentDigit &0x4L) != 0L;
- sticky = (currentDigit & 0x3L) != 0;
- break;
-
- case -4:
- // all bits copied into significand; set
- // round and start sticky
- round = ((currentDigit & 0x8L) != 0); // is top bit set?
- // nonzeros in three low order bits?
- sticky = (currentDigit & 0x7L) != 0;
- break;
-
- default:
- throw new AssertionError("Unexpected shift distance remainder.");
- // break;
- }
-
- // Round is set; sticky might be set.
-
- // For the sticky bit, it suffices to check the
- // current digit and test for any nonzero digits in
- // the remaining unprocessed input.
- i++;
- while(i < signifLength && !sticky) {
- currentDigit = getHexDigit(significandString,i);
- sticky = sticky || (currentDigit != 0);
- i++;
- }
-
- }
- // else all of string was seen, round and sticky are
- // correct as false.
-
-
- // Check for overflow and update exponent accordingly.
-
- if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result
- // overflow to properly signed infinity
- return loadDouble(sign * Double.POSITIVE_INFINITY);
- } else { // Finite return value
- if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
- exponent >= DoubleConsts.MIN_EXPONENT) {
-
- // The result returned in this block cannot be a
- // zero or subnormal; however after the
- // significand is adjusted from rounding, we could
- // still overflow in infinity.
-
- // AND exponent bits into significand; if the
- // significand is incremented and overflows from
- // rounding, this combination will update the
- // exponent correctly, even in the case of
- // Double.MAX_VALUE overflowing to infinity.
-
- significand = (( ((long)exponent +
- (long)DoubleConsts.EXP_BIAS) <<
- (DoubleConsts.SIGNIFICAND_WIDTH-1))
- & DoubleConsts.EXP_BIT_MASK) |
- (DoubleConsts.SIGNIF_BIT_MASK & significand);
-
- } else { // Subnormal or zero
- // (exponent < DoubleConsts.MIN_EXPONENT)
-
- if (exponent < (DoubleConsts.MIN_SUB_EXPONENT -1 )) {
- // No way to round back to nonzero value
- // regardless of significand if the exponent is
- // less than -1075.
- return loadDouble(sign * 0.0);
- } else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023
- /*
- * Find bit position to round to; recompute
- * round and sticky bits, and shift
- * significand right appropriately.
- */
-
- sticky = sticky || round;
- round = false;
-
- // Number of bits of significand to preserve is
- // exponent - abs_min_exp +1
- // check:
- // -1075 +1074 + 1 = 0
- // -1023 +1074 + 1 = 52
-
- int bitsDiscarded = 53 -
- ((int)exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
- assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
-
- // What to do here:
- // First, isolate the new round bit
- round = (significand & (1L << (bitsDiscarded -1))) != 0L;
- if (bitsDiscarded > 1) {
- // create mask to update sticky bits; low
- // order bitsDiscarded bits should be 1
- long mask = ~((~0L) << (bitsDiscarded -1));
- sticky = sticky || ((significand & mask) != 0L ) ;
- }
-
- // Now, discard the bits
- significand = significand >> bitsDiscarded;
-
- significand = (( ((long)(DoubleConsts.MIN_EXPONENT -1) + // subnorm exp.
- (long)DoubleConsts.EXP_BIAS) <<
- (DoubleConsts.SIGNIFICAND_WIDTH-1))
- & DoubleConsts.EXP_BIT_MASK) |
- (DoubleConsts.SIGNIF_BIT_MASK & significand);
- }
- }
-
- // The significand variable now contains the currently
- // appropriate exponent bits too.
-
- /*
- * Determine if significand should be incremented;
- * making this determination depends on the least
- * significant bit and the round and sticky bits.
- *
- * Round to nearest even rounding table, adapted from
- * table 4.7 in "Computer Arithmetic" by IsraelKoren.
- * The digit to the left of the "decimal" point is the
- * least significant bit, the digits to the right of
- * the point are the round and sticky bits
- *
- * Number Round(x)
- * x0.00 x0.
- * x0.01 x0.
- * x0.10 x0.
- * x0.11 x1. = x0. +1
- * x1.00 x1.
- * x1.01 x1.
- * x1.10 x1. + 1
- * x1.11 x1. + 1
- */
- boolean incremented = false;
- boolean leastZero = ((significand & 1L) == 0L);
- if( ( leastZero && round && sticky ) ||
- ((!leastZero) && round )) {
- incremented = true;
- significand++;
- }
-
- loadDouble(FpUtils.rawCopySign(
- Double.longBitsToDouble(significand),
- sign));
-
- /*
- * Set roundingDir variable field of fd properly so
- * that the input string can be properly rounded to a
- * float value. There are two cases to consider:
- *
- * 1. rounding to double discards sticky bit
- * information that would change the result of a float
- * rounding (near halfway case between two floats)
- *
- * 2. rounding to double rounds up when rounding up
- * would not occur when rounding to float.
- *
- * For former case only needs to be considered when
- * the bits rounded away when casting to float are all
- * zero; otherwise, float round bit is properly set
- * and sticky will already be true.
- *
- * The lower exponent bound for the code below is the
- * minimum (normalized) subnormal exponent - 1 since a
- * value with that exponent can round up to the
- * minimum subnormal value and the sticky bit
- * information must be preserved (i.e. case 1).
- */
- if ((exponent >= FloatConsts.MIN_SUB_EXPONENT-1) &&
- (exponent <= FloatConsts.MAX_EXPONENT ) ){
- // Outside above exponent range, the float value
- // will be zero or infinity.
-
- /*
- * If the low-order 28 bits of a rounded double
- * significand are 0, the double could be a
- * half-way case for a rounding to float. If the
- * double value is a half-way case, the double
- * significand may have to be modified to round
- * the the right float value (see the stickyRound
- * method). If the rounding to double has lost
- * what would be float sticky bit information, the
- * double significand must be incremented. If the
- * double value's significand was itself
- * incremented, the float value may end up too
- * large so the increment should be undone.
- */
- if ((significand & 0xfffffffL) == 0x0L) {
- // For negative values, the sign of the
- // roundDir is the same as for positive values
- // since adding 1 increasing the significand's
- // magnitude and subtracting 1 decreases the
- // significand's magnitude. If neither round
- // nor sticky is true, the double value is
- // exact and no adjustment is required for a
- // proper float rounding.
- if( round || sticky) {
- if (leastZero) { // prerounding lsb is 0
- // If round and sticky were both true,
- // and the least significant
- // significand bit were 0, the rounded
- // significand would not have its
- // low-order bits be zero. Therefore,
- // we only need to adjust the
- // significand if round XOR sticky is
- // true.
- if (round ^ sticky) {
- this.roundDir = 1;
- }
- }
- else { // prerounding lsb is 1
- // If the prerounding lsb is 1 and the
- // resulting significand has its
- // low-order bits zero, the significand
- // was incremented. Here, we undo the
- // increment, which will ensure the
- // right guard and sticky bits for the
- // float rounding.
- if (round)
- this.roundDir = -1;
- }
- }
- }
- }
-
- this.fromHex = true;
- return this;
- }
- }
- }
-
- /**
- * Return <code>s</code> with any leading zeros removed.
- */
- static String stripLeadingZeros(String s) {
- return s.replaceFirst("^0+", "");
- }
-
- /**
- * Extract a hexadecimal digit from position <code>position</code>
- * of string <code>s</code>.
- */
- static int getHexDigit(String s, int position) {
- int value = Character.digit(s.charAt(position), 16);
- if (value <= -1 || value >= 16) {
- throw new AssertionError("Unexpected failure of digit conversion of " +
- s.charAt(position));
- }
- return value;
- }
-
-
-}
diff --git a/ojluni/src/main/java/java/lang/Runtime.java b/ojluni/src/main/java/java/lang/Runtime.java
index 61c2502..eb01061 100755
--- a/ojluni/src/main/java/java/lang/Runtime.java
+++ b/ojluni/src/main/java/java/lang/Runtime.java
@@ -868,7 +868,7 @@
*/
@CallerSensitive
public void load(String filename) {
- load0(VMStack.getStackClass2(), filename);
+ load0(VMStack.getStackClass1(), filename);
}
// Fixes b/25859957 regression. Depending on private methods is bad, mkay.
diff --git a/ojluni/src/main/java/java/lang/String.java b/ojluni/src/main/java/java/lang/String.java
index 94b949e..ea5a642 100755
--- a/ojluni/src/main/java/java/lang/String.java
+++ b/ojluni/src/main/java/java/lang/String.java
@@ -34,6 +34,8 @@
import java.util.Comparator;
import java.util.Formatter;
import java.util.Locale;
+import java.util.Objects;
+import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@@ -42,23 +44,23 @@
import libcore.util.EmptyArray;
/**
- * The <code>String</code> class represents character strings. All
- * string literals in Java programs, such as <code>"abc"</code>, are
+ * The {@code String} class represents character strings. All
+ * string literals in Java programs, such as {@code "abc"}, are
* implemented as instances of this class.
* <p>
* Strings are constant; their values cannot be changed after they
* are created. String buffers support mutable strings.
* Because String objects are immutable they can be shared. For example:
- * <p><blockquote><pre>
+ * <blockquote><pre>
* String str = "abc";
* </pre></blockquote><p>
* is equivalent to:
- * <p><blockquote><pre>
+ * <blockquote><pre>
* char data[] = {'a', 'b', 'c'};
* String str = new String(data);
* </pre></blockquote><p>
* Here are some more examples of how strings can be used:
- * <p><blockquote><pre>
+ * <blockquote><pre>
* System.out.println("abc");
* String cde = "cde";
* System.out.println("abc" + cde);
@@ -66,7 +68,7 @@
* String d = cde.substring(1, 2);
* </pre></blockquote>
* <p>
- * The class <code>String</code> includes methods for examining
+ * The class {@code String} includes methods for examining
* individual characters of the sequence, for comparing strings, for
* searching strings, for extracting substrings, and for creating a
* copy of a string with all characters translated to uppercase or to
@@ -76,10 +78,10 @@
* The Java language provides special support for the string
* concatenation operator ( + ), and for conversion of
* other objects to strings. String concatenation is implemented
- * through the <code>StringBuilder</code>(or <code>StringBuffer</code>)
- * class and its <code>append</code> method.
+ * through the {@code StringBuilder}(or {@code StringBuffer})
+ * class and its {@code append} method.
* String conversions are implemented through the method
- * <code>toString</code>, defined by <code>Object</code> and
+ * {@code toString}, defined by {@code Object} and
* inherited by all classes in Java. For additional information on
* string concatenation and conversion, see Gosling, Joy, and Steele,
* <i>The Java Language Specification</i>.
@@ -88,16 +90,16 @@
* or method in this class will cause a {@link NullPointerException} to be
* thrown.
*
- * <p>A <code>String</code> represents a string in the UTF-16 format
+ * <p>A {@code String} represents a string in the UTF-16 format
* in which <em>supplementary characters</em> are represented by <em>surrogate
* pairs</em> (see the section <a href="Character.html#unicode">Unicode
- * Character Representations</a> in the <code>Character</code> class for
+ * Character Representations</a> in the {@code Character} class for
* more information).
- * Index values refer to <code>char</code> code units, so a supplementary
- * character uses two positions in a <code>String</code>.
- * <p>The <code>String</code> class provides methods for dealing with
+ * Index values refer to {@code char} code units, so a supplementary
+ * character uses two positions in a {@code String}.
+ * <p>The {@code String} class provides methods for dealing with
* Unicode code points (i.e., characters), in addition to those for
- * dealing with Unicode code units (i.e., <code>char</code> values).
+ * dealing with Unicode code units (i.e., {@code char} values).
*
* @author Lee Boynton
* @author Arthur van Hoff
@@ -113,7 +115,7 @@
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
- // The associated character storage is managed by the runtime. We only
+ // dThe associated character storage is managed by the runtime. We only
// keep track of the length here.
//
// private final char value[];
@@ -128,17 +130,12 @@
/**
* Class String is special cased within the Serialization Stream Protocol.
*
- * A String instance is written initially into an ObjectOutputStream in the
- * following format:
- * <pre>
- * <code>TC_STRING</code> (utf String)
- * </pre>
- * The String is written by method <code>DataOutput.writeUTF</code>.
- * A new handle is generated to refer to all future references to the
- * string instance within the stream.
+ * A String instance is written into an ObjectOutputStream according to
+ * <a href="{@docRoot}/../platform/serialization/spec/output.html">
+ * Object Serialization Specification, Section 6.2, "Stream Elements"</a>
*/
private static final ObjectStreamField[] serialPersistentFields =
- new ObjectStreamField[0];
+ new ObjectStreamField[0];
/**
* Initializes a newly created {@code String} object so that it represents
@@ -542,10 +539,10 @@
}
/**
- * Returns <tt>true</tt> if, and only if, {@link #length()} is <tt>0</tt>.
+ * Returns {@code true} if, and only if, {@link #length()} is {@code 0}.
*
- * @return <tt>true</tt> if {@link #length()} is <tt>0</tt>, otherwise
- * <tt>false</tt>
+ * @return {@code true} if {@link #length()} is {@code 0}, otherwise
+ * {@code false}
*
* @since 1.6
*/
@@ -554,20 +551,20 @@
}
/**
- * Returns the <code>char</code> value at the
- * specified index. An index ranges from <code>0</code> to
- * <code>length() - 1</code>. The first <code>char</code> value of the sequence
- * is at index <code>0</code>, the next at index <code>1</code>,
+ * Returns the {@code char} value at the
+ * specified index. An index ranges from {@code 0} to
+ * {@code length() - 1}. The first {@code char} value of the sequence
+ * is at index {@code 0}, the next at index {@code 1},
* and so on, as for array indexing.
*
- * <p>If the <code>char</code> value specified by the index is a
+ * <p>If the {@code char} value specified by the index is a
* <a href="Character.html#unicode">surrogate</a>, the surrogate
* value is returned.
*
- * @param index the index of the <code>char</code> value.
- * @return the <code>char</code> value at the specified index of this string.
- * The first <code>char</code> value is at index <code>0</code>.
- * @exception IndexOutOfBoundsException if the <code>index</code>
+ * @param index the index of the {@code char} value.
+ * @return the {@code char} value at the specified index of this string.
+ * The first {@code char} value is at index {@code 0}.
+ * @exception IndexOutOfBoundsException if the {@code index}
* argument is negative or not less than the length of this
* string.
*/
@@ -577,22 +574,22 @@
/**
* Returns the character (Unicode code point) at the specified
- * index. The index refers to <code>char</code> values
- * (Unicode code units) and ranges from <code>0</code> to
- * {@link #length()}<code> - 1</code>.
+ * index. The index refers to {@code char} values
+ * (Unicode code units) and ranges from {@code 0} to
+ * {@link #length()}{@code - 1}.
*
- * <p> If the <code>char</code> value specified at the given index
+ * <p> If the {@code char} value specified at the given index
* is in the high-surrogate range, the following index is less
- * than the length of this <code>String</code>, and the
- * <code>char</code> value at the following index is in the
+ * than the length of this {@code String}, and the
+ * {@code char} value at the following index is in the
* low-surrogate range, then the supplementary code point
* corresponding to this surrogate pair is returned. Otherwise,
- * the <code>char</code> value at the given index is returned.
+ * the {@code char} value at the given index is returned.
*
- * @param index the index to the <code>char</code> values
+ * @param index the index to the {@code char} values
* @return the code point value of the character at the
- * <code>index</code>
- * @exception IndexOutOfBoundsException if the <code>index</code>
+ * {@code index}
+ * @exception IndexOutOfBoundsException if the {@code index}
* argument is negative or not less than the length of this
* string.
* @since 1.5
@@ -606,22 +603,22 @@
/**
* Returns the character (Unicode code point) before the specified
- * index. The index refers to <code>char</code> values
- * (Unicode code units) and ranges from <code>1</code> to {@link
+ * index. The index refers to {@code char} values
+ * (Unicode code units) and ranges from {@code 1} to {@link
* CharSequence#length() length}.
*
- * <p> If the <code>char</code> value at <code>(index - 1)</code>
- * is in the low-surrogate range, <code>(index - 2)</code> is not
- * negative, and the <code>char</code> value at <code>(index -
- * 2)</code> is in the high-surrogate range, then the
+ * <p> If the {@code char} value at {@code (index - 1)}
+ * is in the low-surrogate range, {@code (index - 2)} is not
+ * negative, and the {@code char} value at {@code (index -
+ * 2)} is in the high-surrogate range, then the
* supplementary code point value of the surrogate pair is
- * returned. If the <code>char</code> value at <code>index -
- * 1</code> is an unpaired low-surrogate or a high-surrogate, the
+ * returned. If the {@code char} value at {@code index -
+ * 1} is an unpaired low-surrogate or a high-surrogate, the
* surrogate value is returned.
*
* @param index the index following the code point that should be returned
* @return the Unicode code point value before the given index.
- * @exception IndexOutOfBoundsException if the <code>index</code>
+ * @exception IndexOutOfBoundsException if the {@code index}
* argument is less than 1 or greater than the length
* of this string.
* @since 1.5
@@ -636,23 +633,23 @@
/**
* Returns the number of Unicode code points in the specified text
- * range of this <code>String</code>. The text range begins at the
- * specified <code>beginIndex</code> and extends to the
- * <code>char</code> at index <code>endIndex - 1</code>. Thus the
- * length (in <code>char</code>s) of the text range is
- * <code>endIndex-beginIndex</code>. Unpaired surrogates within
+ * range of this {@code String}. The text range begins at the
+ * specified {@code beginIndex} and extends to the
+ * {@code char} at index {@code endIndex - 1}. Thus the
+ * length (in {@code char}s) of the text range is
+ * {@code endIndex-beginIndex}. Unpaired surrogates within
* the text range count as one code point each.
*
- * @param beginIndex the index to the first <code>char</code> of
+ * @param beginIndex the index to the first {@code char} of
* the text range.
- * @param endIndex the index after the last <code>char</code> of
+ * @param endIndex the index after the last {@code char} of
* the text range.
* @return the number of Unicode code points in the specified text
* range
* @exception IndexOutOfBoundsException if the
- * <code>beginIndex</code> is negative, or <code>endIndex</code>
- * is larger than the length of this <code>String</code>, or
- * <code>beginIndex</code> is larger than <code>endIndex</code>.
+ * {@code beginIndex} is negative, or {@code endIndex}
+ * is larger than the length of this {@code String}, or
+ * {@code beginIndex} is larger than {@code endIndex}.
* @since 1.5
*/
public int codePointCount(int beginIndex, int endIndex) {
@@ -663,23 +660,23 @@
}
/**
- * Returns the index within this <code>String</code> that is
- * offset from the given <code>index</code> by
- * <code>codePointOffset</code> code points. Unpaired surrogates
- * within the text range given by <code>index</code> and
- * <code>codePointOffset</code> count as one code point each.
+ * Returns the index within this {@code String} that is
+ * offset from the given {@code index} by
+ * {@code codePointOffset} code points. Unpaired surrogates
+ * within the text range given by {@code index} and
+ * {@code codePointOffset} count as one code point each.
*
* @param index the index to be offset
* @param codePointOffset the offset in code points
- * @return the index within this <code>String</code>
- * @exception IndexOutOfBoundsException if <code>index</code>
+ * @return the index within this {@code String}
+ * @exception IndexOutOfBoundsException if {@code index}
* is negative or larger then the length of this
- * <code>String</code>, or if <code>codePointOffset</code> is positive
- * and the substring starting with <code>index</code> has fewer
- * than <code>codePointOffset</code> code points,
- * or if <code>codePointOffset</code> is negative and the substring
- * before <code>index</code> has fewer than the absolute value
- * of <code>codePointOffset</code> code points.
+ * {@code String}, or if {@code codePointOffset} is positive
+ * and the substring starting with {@code index} has fewer
+ * than {@code codePointOffset} code points,
+ * or if {@code codePointOffset} is negative and the substring
+ * before {@code index} has fewer than the absolute value
+ * of {@code codePointOffset} code points.
* @since 1.5
*/
public int offsetByCodePoints(int index, int codePointOffset) {
@@ -690,17 +687,25 @@
}
/**
+ * Copy characters from this string into dst starting at dstBegin.
+ * This method doesn't perform any range checking.
+ */
+ void getChars(char dst[], int dstBegin) {
+ getCharsNoCheck(0, count, dst, dstBegin);
+ }
+
+ /**
* Copies characters from this string into the destination character
* array.
* <p>
- * The first character to be copied is at index <code>srcBegin</code>;
- * the last character to be copied is at index <code>srcEnd-1</code>
+ * The first character to be copied is at index {@code srcBegin};
+ * the last character to be copied is at index {@code srcEnd-1}
* (thus the total number of characters to be copied is
- * <code>srcEnd-srcBegin</code>). The characters are copied into the
- * subarray of <code>dst</code> starting at index <code>dstBegin</code>
+ * {@code srcEnd-srcBegin}). The characters are copied into the
+ * subarray of {@code dst} starting at index {@code dstBegin}
* and ending at index:
- * <p><blockquote><pre>
- * dstbegin + (srcEnd-srcBegin) - 1
+ * <blockquote><pre>
+ * dstBegin + (srcEnd-srcBegin) - 1
* </pre></blockquote>
*
* @param srcBegin index of the first character in the string
@@ -711,13 +716,13 @@
* @param dstBegin the start offset in the destination array.
* @exception IndexOutOfBoundsException If any of the following
* is true:
- * <ul><li><code>srcBegin</code> is negative.
- * <li><code>srcBegin</code> is greater than <code>srcEnd</code>
- * <li><code>srcEnd</code> is greater than the length of this
+ * <ul><li>{@code srcBegin} is negative.
+ * <li>{@code srcBegin} is greater than {@code srcEnd}
+ * <li>{@code srcEnd} is greater than the length of this
* string
- * <li><code>dstBegin</code> is negative
- * <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than
- * <code>dst.length</code></ul>
+ * <li>{@code dstBegin} is negative
+ * <li>{@code dstBegin+(srcEnd-srcBegin)} is larger than
+ * {@code dst.length}</ul>
*/
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (dst == null) {
@@ -775,7 +780,7 @@
* dst} starting at index {@code dstBegin} and ending at index:
*
* <blockquote><pre>
- * dstbegin + (srcEnd-srcBegin) - 1
+ * dstBegin + (srcEnd-srcBegin) - 1
* </pre></blockquote>
*
* @deprecated This method does not properly convert characters into
@@ -848,6 +853,7 @@
*/
public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException {
+ if (charsetName == null) throw new NullPointerException();
return getBytes(Charset.forNameUEE(charsetName));
}
@@ -943,7 +949,8 @@
/**
* Compares this string to the specified {@code StringBuffer}. The result
* is {@code true} if and only if this {@code String} represents the same
- * sequence of characters as the specified {@code StringBuffer}.
+ * sequence of characters as the specified {@code StringBuffer}. This method
+ * synchronizes on the {@code StringBuffer}.
*
* @param sb
* The {@code StringBuffer} to compare this {@code String} against
@@ -955,15 +962,29 @@
* @since 1.4
*/
public boolean contentEquals(StringBuffer sb) {
- synchronized (sb) {
- return contentEquals((CharSequence) sb);
+ return contentEquals((CharSequence)sb);
+ }
+
+ private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
+ char v2[] = sb.getValue();
+ int n = count;
+ if (n != sb.length()) {
+ return false;
}
+ for (int i = 0; i < n; i++) {
+ if (charAt(i) != v2[i]) {
+ return false;
+ }
+ }
+ return true;
}
/**
- * Compares this string to the specified {@code CharSequence}. The result
- * is {@code true} if and only if this {@code String} represents the same
- * sequence of char values as the specified sequence.
+ * Compares this string to the specified {@code CharSequence}. The
+ * result is {@code true} if and only if this {@code String} represents the
+ * same sequence of char values as the specified sequence. Note that if the
+ * {@code CharSequence} is a {@code StringBuffer} then the method
+ * synchronizes on it.
*
* @param cs
* The sequence to compare this {@code String} against
@@ -975,30 +996,29 @@
* @since 1.5
*/
public boolean contentEquals(CharSequence cs) {
- if (count != cs.length())
- return false;
// Argument is a StringBuffer, StringBuilder
if (cs instanceof AbstractStringBuilder) {
- char v2[] = ((AbstractStringBuilder) cs).getValue();
- int i = 0;
- int n = count;
- while (n-- != 0) {
- if (charAt(i) != v2[i])
- return false;
- i++;
+ if (cs instanceof StringBuffer) {
+ synchronized(cs) {
+ return nonSyncContentEquals((AbstractStringBuilder)cs);
+ }
+ } else {
+ return nonSyncContentEquals((AbstractStringBuilder)cs);
}
- return true;
}
// Argument is a String
- if (cs.equals(this))
- return true;
+ if (cs instanceof String) {
+ return equals(cs);
+ }
// Argument is a generic CharSequence
- int i = 0;
int n = count;
- while (n-- != 0) {
- if (charAt(i) != cs.charAt(i))
+ if (n != cs.length()) {
+ return false;
+ }
+ for (int i = 0; i < n; i++) {
+ if (charAt(i) != cs.charAt(i)) {
return false;
- i++;
+ }
}
return true;
}
@@ -1042,14 +1062,14 @@
* Compares two strings lexicographically.
* The comparison is based on the Unicode value of each character in
* the strings. The character sequence represented by this
- * <code>String</code> object is compared lexicographically to the
+ * {@code String} object is compared lexicographically to the
* character sequence represented by the argument string. The result is
- * a negative integer if this <code>String</code> object
+ * a negative integer if this {@code String} object
* lexicographically precedes the argument string. The result is a
- * positive integer if this <code>String</code> object lexicographically
+ * positive integer if this {@code String} object lexicographically
* follows the argument string. The result is zero if the strings
- * are equal; <code>compareTo</code> returns <code>0</code> exactly when
- * the {@link #equals(Object)} method would return <code>true</code>.
+ * are equal; {@code compareTo} returns {@code 0} exactly when
+ * the {@link #equals(Object)} method would return {@code true}.
* <p>
* This is the definition of lexicographic ordering. If two strings are
* different, then either they have different characters at some index
@@ -1058,32 +1078,32 @@
* positions, let <i>k</i> be the smallest such index; then the string
* whose character at position <i>k</i> has the smaller value, as
* determined by using the < operator, lexicographically precedes the
- * other string. In this case, <code>compareTo</code> returns the
- * difference of the two character values at position <code>k</code> in
+ * other string. In this case, {@code compareTo} returns the
+ * difference of the two character values at position {@code k} in
* the two string -- that is, the value:
* <blockquote><pre>
* this.charAt(k)-anotherString.charAt(k)
* </pre></blockquote>
* If there is no index position at which they differ, then the shorter
* string lexicographically precedes the longer string. In this case,
- * <code>compareTo</code> returns the difference of the lengths of the
+ * {@code compareTo} returns the difference of the lengths of the
* strings -- that is, the value:
* <blockquote><pre>
* this.length()-anotherString.length()
* </pre></blockquote>
*
- * @param anotherString the <code>String</code> to be compared.
- * @return the value <code>0</code> if the argument string is equal to
- * this string; a value less than <code>0</code> if this string
+ * @param anotherString the {@code String} to be compared.
+ * @return the value {@code 0} if the argument string is equal to
+ * this string; a value less than {@code 0} if this string
* is lexicographically less than the string argument; and a
- * value greater than <code>0</code> if this string is
+ * value greater than {@code 0} if this string is
* lexicographically greater than the string argument.
*/
public native int compareTo(String anotherString);
/**
- * A Comparator that orders <code>String</code> objects as by
- * <code>compareToIgnoreCase</code>. This comparator is serializable.
+ * A Comparator that orders {@code String} objects as by
+ * {@code compareToIgnoreCase}. This comparator is serializable.
* <p>
* Note that this Comparator does <em>not</em> take locale into account,
* and will result in an unsatisfactory ordering for certain locales.
@@ -1122,14 +1142,17 @@
}
return n1 - n2;
}
+
+ /** Replaces the de-serialized object. */
+ private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}
/**
* Compares two strings lexicographically, ignoring case
* differences. This method returns an integer whose sign is that of
- * calling <code>compareTo</code> with normalized versions of the strings
+ * calling {@code compareTo} with normalized versions of the strings
* where case differences have been eliminated by calling
- * <code>Character.toLowerCase(Character.toUpperCase(character))</code> on
+ * {@code Character.toLowerCase(Character.toUpperCase(character))} on
* each character.
* <p>
* Note that this method does <em>not</em> take locale into account,
@@ -1137,7 +1160,7 @@
* The java.text package provides <em>collators</em> to allow
* locale-sensitive ordering.
*
- * @param str the <code>String</code> to be compared.
+ * @param str the {@code String} to be compared.
* @return a negative integer, zero, or a positive integer as the
* specified String is greater than, equal to, or less
* than this String, ignoring case considerations.
@@ -1151,23 +1174,24 @@
/**
* Tests if two string regions are equal.
* <p>
- * A substring of this <tt>String</tt> object is compared to a substring
+ * A substring of this {@code String} object is compared to a substring
* of the argument other. The result is true if these substrings
* represent identical character sequences. The substring of this
- * <tt>String</tt> object to be compared begins at index <tt>toffset</tt>
- * and has length <tt>len</tt>. The substring of other to be compared
- * begins at index <tt>ooffset</tt> and has length <tt>len</tt>. The
- * result is <tt>false</tt> if and only if at least one of the following
+ * {@code String} object to be compared begins at index {@code toffset}
+ * and has length {@code len}. The substring of other to be compared
+ * begins at index {@code ooffset} and has length {@code len}. The
+ * result is {@code false} if and only if at least one of the following
* is true:
- * <ul><li><tt>toffset</tt> is negative.
- * <li><tt>ooffset</tt> is negative.
- * <li><tt>toffset+len</tt> is greater than the length of this
- * <tt>String</tt> object.
- * <li><tt>ooffset+len</tt> is greater than the length of the other
+ * <ul><li>{@code toffset} is negative.
+ * <li>{@code ooffset} is negative.
+ * <li>{@code toffset+len} is greater than the length of this
+ * {@code String} object.
+ * <li>{@code ooffset+len} is greater than the length of the other
* argument.
- * <li>There is some nonnegative integer <i>k</i> less than <tt>len</tt>
+ * <li>There is some nonnegative integer <i>k</i> less than {@code len}
* such that:
- * <tt>this.charAt(toffset+<i>k</i>) != other.charAt(ooffset+<i>k</i>)</tt>
+ * {@code this.charAt(toffset + }<i>k</i>{@code ) != other.charAt(ooffset + }
+ * <i>k</i>{@code )}
* </ul>
*
* @param toffset the starting offset of the subregion in this string.
@@ -1175,9 +1199,9 @@
* @param ooffset the starting offset of the subregion in the string
* argument.
* @param len the number of characters to compare.
- * @return <code>true</code> if the specified subregion of this string
+ * @return {@code true} if the specified subregion of this string
* exactly matches the specified subregion of the string argument;
- * <code>false</code> otherwise.
+ * {@code false} otherwise.
*/
public boolean regionMatches(int toffset, String other, int ooffset,
int len) {
@@ -1200,28 +1224,28 @@
/**
* Tests if two string regions are equal.
* <p>
- * A substring of this <tt>String</tt> object is compared to a substring
- * of the argument <tt>other</tt>. The result is <tt>true</tt> if these
+ * A substring of this {@code String} object is compared to a substring
+ * of the argument {@code other}. The result is {@code true} if these
* substrings represent character sequences that are the same, ignoring
- * case if and only if <tt>ignoreCase</tt> is true. The substring of
- * this <tt>String</tt> object to be compared begins at index
- * <tt>toffset</tt> and has length <tt>len</tt>. The substring of
- * <tt>other</tt> to be compared begins at index <tt>ooffset</tt> and
- * has length <tt>len</tt>. The result is <tt>false</tt> if and only if
+ * case if and only if {@code ignoreCase} is true. The substring of
+ * this {@code String} object to be compared begins at index
+ * {@code toffset} and has length {@code len}. The substring of
+ * {@code other} to be compared begins at index {@code ooffset} and
+ * has length {@code len}. The result is {@code false} if and only if
* at least one of the following is true:
- * <ul><li><tt>toffset</tt> is negative.
- * <li><tt>ooffset</tt> is negative.
- * <li><tt>toffset+len</tt> is greater than the length of this
- * <tt>String</tt> object.
- * <li><tt>ooffset+len</tt> is greater than the length of the other
+ * <ul><li>{@code toffset} is negative.
+ * <li>{@code ooffset} is negative.
+ * <li>{@code toffset+len} is greater than the length of this
+ * {@code String} object.
+ * <li>{@code ooffset+len} is greater than the length of the other
* argument.
- * <li><tt>ignoreCase</tt> is <tt>false</tt> and there is some nonnegative
- * integer <i>k</i> less than <tt>len</tt> such that:
+ * <li>{@code ignoreCase} is {@code false} and there is some nonnegative
+ * integer <i>k</i> less than {@code len} such that:
* <blockquote><pre>
* this.charAt(toffset+k) != other.charAt(ooffset+k)
* </pre></blockquote>
- * <li><tt>ignoreCase</tt> is <tt>true</tt> and there is some nonnegative
- * integer <i>k</i> less than <tt>len</tt> such that:
+ * <li>{@code ignoreCase} is {@code true} and there is some nonnegative
+ * integer <i>k</i> less than {@code len} such that:
* <blockquote><pre>
* Character.toLowerCase(this.charAt(toffset+k)) !=
Character.toLowerCase(other.charAt(ooffset+k))
@@ -1233,7 +1257,7 @@
* </pre></blockquote>
* </ul>
*
- * @param ignoreCase if <code>true</code>, ignore case when comparing
+ * @param ignoreCase if {@code true}, ignore case when comparing
* characters.
* @param toffset the starting offset of the subregion in this
* string.
@@ -1241,10 +1265,10 @@
* @param ooffset the starting offset of the subregion in the string
* argument.
* @param len the number of characters to compare.
- * @return <code>true</code> if the specified subregion of this string
+ * @return {@code true} if the specified subregion of this string
* matches the specified subregion of the string argument;
- * <code>false</code> otherwise. Whether the matching is exact
- * or case insensitive depends on the <code>ignoreCase</code>
+ * {@code false} otherwise. Whether the matching is exact
+ * or case insensitive depends on the {@code ignoreCase}
* argument.
*/
public boolean regionMatches(boolean ignoreCase, int toffset,
@@ -1292,12 +1316,12 @@
*
* @param prefix the prefix.
* @param toffset where to begin looking in this string.
- * @return <code>true</code> if the character sequence represented by the
+ * @return {@code true} if the character sequence represented by the
* argument is a prefix of the substring of this object starting
- * at index <code>toffset</code>; <code>false</code> otherwise.
- * The result is <code>false</code> if <code>toffset</code> is
+ * at index {@code toffset}; {@code false} otherwise.
+ * The result is {@code false} if {@code toffset} is
* negative or greater than the length of this
- * <code>String</code> object; otherwise the result is the same
+ * {@code String} object; otherwise the result is the same
* as the result of the expression
* <pre>
* this.substring(toffset).startsWith(prefix)
@@ -1323,12 +1347,12 @@
* Tests if this string starts with the specified prefix.
*
* @param prefix the prefix.
- * @return <code>true</code> if the character sequence represented by the
+ * @return {@code true} if the character sequence represented by the
* argument is a prefix of the character sequence represented by
- * this string; <code>false</code> otherwise.
- * Note also that <code>true</code> will be returned if the
+ * this string; {@code false} otherwise.
+ * Note also that {@code true} will be returned if the
* argument is an empty string or is equal to this
- * <code>String</code> object as determined by the
+ * {@code String} object as determined by the
* {@link #equals(Object)} method.
* @since 1. 0
*/
@@ -1340,11 +1364,11 @@
* Tests if this string ends with the specified suffix.
*
* @param suffix the suffix.
- * @return <code>true</code> if the character sequence represented by the
+ * @return {@code true} if the character sequence represented by the
* argument is a suffix of the character sequence represented by
- * this object; <code>false</code> otherwise. Note that the
- * result will be <code>true</code> if the argument is the
- * empty string or is equal to this <code>String</code> object
+ * this object; {@code false} otherwise. Note that the
+ * result will be {@code true} if the argument is the
+ * empty string or is equal to this {@code String} object
* as determined by the {@link #equals(Object)} method.
*/
public boolean endsWith(String suffix) {
@@ -1353,13 +1377,13 @@
/**
* Returns a hash code for this string. The hash code for a
- * <code>String</code> object is computed as
+ * {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
- * using <code>int</code> arithmetic, where <code>s[i]</code> is the
- * <i>i</i>th character of the string, <code>n</code> is the length of
- * the string, and <code>^</code> indicates exponentiation.
+ * using {@code int} arithmetic, where {@code s[i]} is the
+ * <i>i</i>th character of the string, {@code n} is the length of
+ * the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
@@ -1378,26 +1402,26 @@
/**
* Returns the index within this string of the first occurrence of
* the specified character. If a character with value
- * <code>ch</code> occurs in the character sequence represented by
- * this <code>String</code> object, then the index (in Unicode
+ * {@code ch} occurs in the character sequence represented by
+ * this {@code String} object, then the index (in Unicode
* code units) of the first such occurrence is returned. For
- * values of <code>ch</code> in the range from 0 to 0xFFFF
+ * values of {@code ch} in the range from 0 to 0xFFFF
* (inclusive), this is the smallest value <i>k</i> such that:
* <blockquote><pre>
* this.charAt(<i>k</i>) == ch
* </pre></blockquote>
- * is true. For other values of <code>ch</code>, it is the
+ * is true. For other values of {@code ch}, it is the
* smallest value <i>k</i> such that:
* <blockquote><pre>
* this.codePointAt(<i>k</i>) == ch
* </pre></blockquote>
* is true. In either case, if no such character occurs in this
- * string, then <code>-1</code> is returned.
+ * string, then {@code -1} is returned.
*
* @param ch a character (Unicode code point).
* @return the index of the first occurrence of the character in the
* character sequence represented by this object, or
- * <code>-1</code> if the character does not occur.
+ * {@code -1} if the character does not occur.
*/
public int indexOf(int ch) {
return indexOf(ch, 0);
@@ -1407,39 +1431,39 @@
* Returns the index within this string of the first occurrence of the
* specified character, starting the search at the specified index.
* <p>
- * If a character with value <code>ch</code> occurs in the
- * character sequence represented by this <code>String</code>
- * object at an index no smaller than <code>fromIndex</code>, then
+ * If a character with value {@code ch} occurs in the
+ * character sequence represented by this {@code String}
+ * object at an index no smaller than {@code fromIndex}, then
* the index of the first such occurrence is returned. For values
- * of <code>ch</code> in the range from 0 to 0xFFFF (inclusive),
+ * of {@code ch} in the range from 0 to 0xFFFF (inclusive),
* this is the smallest value <i>k</i> such that:
* <blockquote><pre>
- * (this.charAt(<i>k</i>) == ch) && (<i>k</i> >= fromIndex)
+ * (this.charAt(<i>k</i>) == ch) {@code &&} (<i>k</i> >= fromIndex)
* </pre></blockquote>
- * is true. For other values of <code>ch</code>, it is the
+ * is true. For other values of {@code ch}, it is the
* smallest value <i>k</i> such that:
* <blockquote><pre>
- * (this.codePointAt(<i>k</i>) == ch) && (<i>k</i> >= fromIndex)
+ * (this.codePointAt(<i>k</i>) == ch) {@code &&} (<i>k</i> >= fromIndex)
* </pre></blockquote>
* is true. In either case, if no such character occurs in this
- * string at or after position <code>fromIndex</code>, then
- * <code>-1</code> is returned.
+ * string at or after position {@code fromIndex}, then
+ * {@code -1} is returned.
*
* <p>
- * There is no restriction on the value of <code>fromIndex</code>. If it
+ * There is no restriction on the value of {@code fromIndex}. If it
* is negative, it has the same effect as if it were zero: this entire
* string may be searched. If it is greater than the length of this
* string, it has the same effect as if it were equal to the length of
- * this string: <code>-1</code> is returned.
+ * this string: {@code -1} is returned.
*
- * <p>All indices are specified in <code>char</code> values
+ * <p>All indices are specified in {@code char} values
* (Unicode code units).
*
* @param ch a character (Unicode code point).
* @param fromIndex the index to start the search from.
* @return the index of the first occurrence of the character in the
* character sequence represented by this object that is greater
- * than or equal to <code>fromIndex</code>, or <code>-1</code>
+ * than or equal to {@code fromIndex}, or {@code -1}
* if the character does not occur.
*/
public int indexOf(int ch, int fromIndex) {
@@ -1486,26 +1510,26 @@
/**
* Returns the index within this string of the last occurrence of
- * the specified character. For values of <code>ch</code> in the
+ * the specified character. For values of {@code ch} in the
* range from 0 to 0xFFFF (inclusive), the index (in Unicode code
* units) returned is the largest value <i>k</i> such that:
* <blockquote><pre>
* this.charAt(<i>k</i>) == ch
* </pre></blockquote>
- * is true. For other values of <code>ch</code>, it is the
+ * is true. For other values of {@code ch}, it is the
* largest value <i>k</i> such that:
* <blockquote><pre>
* this.codePointAt(<i>k</i>) == ch
* </pre></blockquote>
* is true. In either case, if no such character occurs in this
- * string, then <code>-1</code> is returned. The
- * <code>String</code> is searched backwards starting at the last
+ * string, then {@code -1} is returned. The
+ * {@code String} is searched backwards starting at the last
* character.
*
* @param ch a character (Unicode code point).
* @return the index of the last occurrence of the character in the
* character sequence represented by this object, or
- * <code>-1</code> if the character does not occur.
+ * {@code -1} if the character does not occur.
*/
public int lastIndexOf(int ch) {
return lastIndexOf(ch, count - 1);
@@ -1514,27 +1538,27 @@
/**
* Returns the index within this string of the last occurrence of
* the specified character, searching backward starting at the
- * specified index. For values of <code>ch</code> in the range
+ * specified index. For values of {@code ch} in the range
* from 0 to 0xFFFF (inclusive), the index returned is the largest
* value <i>k</i> such that:
* <blockquote><pre>
- * (this.charAt(<i>k</i>) == ch) && (<i>k</i> <= fromIndex)
+ * (this.charAt(<i>k</i>) == ch) {@code &&} (<i>k</i> <= fromIndex)
* </pre></blockquote>
- * is true. For other values of <code>ch</code>, it is the
+ * is true. For other values of {@code ch}, it is the
* largest value <i>k</i> such that:
* <blockquote><pre>
- * (this.codePointAt(<i>k</i>) == ch) && (<i>k</i> <= fromIndex)
+ * (this.codePointAt(<i>k</i>) == ch) {@code &&} (<i>k</i> <= fromIndex)
* </pre></blockquote>
* is true. In either case, if no such character occurs in this
- * string at or before position <code>fromIndex</code>, then
- * <code>-1</code> is returned.
+ * string at or before position {@code fromIndex}, then
+ * {@code -1} is returned.
*
- * <p>All indices are specified in <code>char</code> values
+ * <p>All indices are specified in {@code char} values
* (Unicode code units).
*
* @param ch a character (Unicode code point).
* @param fromIndex the index to start the search from. There is no
- * restriction on the value of <code>fromIndex</code>. If it is
+ * restriction on the value of {@code fromIndex}. If it is
* greater than or equal to the length of this string, it has
* the same effect as if it were equal to one less than the
* length of this string: this entire string may be searched.
@@ -1542,7 +1566,7 @@
* -1 is returned.
* @return the index of the last occurrence of the character in the
* character sequence represented by this object that is less
- * than or equal to <code>fromIndex</code>, or <code>-1</code>
+ * than or equal to {@code fromIndex}, or {@code -1}
* if the character does not occur before that point.
*/
public int lastIndexOf(int ch, int fromIndex) {
@@ -1602,7 +1626,7 @@
*
* <p>The returned index is the smallest value <i>k</i> for which:
* <blockquote><pre>
- * <i>k</i> >= fromIndex && this.startsWith(str, <i>k</i>)
+ * <i>k</i> >= fromIndex {@code &&} this.startsWith(str, <i>k</i>)
* </pre></blockquote>
* If no such value of <i>k</i> exists, then {@code -1} is returned.
*
@@ -1617,7 +1641,7 @@
}
/**
- * Code shared by String and StringBuffer to do searches. The
+ * Code shared by String and AbstractStringBuilder to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
@@ -1739,7 +1763,7 @@
*
* <p>The returned index is the largest value <i>k</i> for which:
* <blockquote><pre>
- * <i>k</i> <= fromIndex && this.startsWith(str, <i>k</i>)
+ * <i>k</i> {@code <=} fromIndex {@code &&} this.startsWith(str, <i>k</i>)
* </pre></blockquote>
* If no such value of <i>k</i> exists, then {@code -1} is returned.
*
@@ -1754,16 +1778,12 @@
}
/**
- * Code shared by String and StringBuffer to do searches. The
+ * Code shared by String and AbstractStringBuilder to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* @param source the characters being searched.
- * @param sourceOffset offset of the source string.
- * @param sourceCount count of the source string.
* @param target the characters being searched for.
- * @param targetOffset offset of the target string.
- * @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
static int lastIndexOf(String source,
@@ -1849,7 +1869,7 @@
int min = sourceOffset + targetCount - 1;
int i = min + fromIndex;
- startSearchForLastChar:
+ startSearchForLastChar:
while (true) {
while (i >= min && source[i] != strLastChar) {
i--;
@@ -1872,7 +1892,7 @@
}
/**
- * Returns a new string that is a substring of this string. The
+ * Returns a string that is a substring of this string. The
* substring begins with the character at the specified index and
* extends to the end of this string. <p>
* Examples:
@@ -1885,8 +1905,8 @@
* @param beginIndex the beginning index, inclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if
- * <code>beginIndex</code> is negative or larger than the
- * length of this <code>String</code> object.
+ * {@code beginIndex} is negative or larger than the
+ * length of this {@code String} object.
*/
public String substring(int beginIndex) {
if (beginIndex < 0) {
@@ -1900,10 +1920,10 @@
}
/**
- * Returns a new string that is a substring of this string. The
- * substring begins at the specified <code>beginIndex</code> and
- * extends to the character at index <code>endIndex - 1</code>.
- * Thus the length of the substring is <code>endIndex-beginIndex</code>.
+ * Returns a string that is a substring of this string. The
+ * substring begins at the specified {@code beginIndex} and
+ * extends to the character at index {@code endIndex - 1}.
+ * Thus the length of the substring is {@code endIndex-beginIndex}.
* <p>
* Examples:
* <blockquote><pre>
@@ -1915,20 +1935,22 @@
* @param endIndex the ending index, exclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if the
- * <code>beginIndex</code> is negative, or
- * <code>endIndex</code> is larger than the length of
- * this <code>String</code> object, or
- * <code>beginIndex</code> is larger than
- * <code>endIndex</code>.
+ * {@code beginIndex} is negative, or
+ * {@code endIndex} is larger than the length of
+ * this {@code String} object, or
+ * {@code beginIndex} is larger than
+ * {@code endIndex}.
*/
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(this, beginIndex);
}
-
+ if (endIndex > count) {
+ throw new StringIndexOutOfBoundsException(this, endIndex);
+ }
int subLen = endIndex - beginIndex;
- if (endIndex > count || subLen < 0) {
- throw new StringIndexOutOfBoundsException(this, beginIndex, subLen);
+ if (subLen < 0) {
+ throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == count)) ? this
@@ -1938,7 +1960,7 @@
private native String fastSubstring(int start, int length);
/**
- * Returns a new character sequence that is a subsequence of this sequence.
+ * Returns a character sequence that is a subsequence of this sequence.
*
* <p> An invocation of this method of the form
*
@@ -1950,17 +1972,18 @@
* <blockquote><pre>
* str.substring(begin, end)</pre></blockquote>
*
- * This method is defined so that the <tt>String</tt> class can implement
- * the {@link CharSequence} interface. </p>
+ * @apiNote
+ * This method is defined so that the {@code String} class can implement
+ * the {@link CharSequence} interface.
*
- * @param beginIndex the begin index, inclusive.
- * @param endIndex the end index, exclusive.
- * @return the specified subsequence.
+ * @param beginIndex the begin index, inclusive.
+ * @param endIndex the end index, exclusive.
+ * @return the specified subsequence.
*
* @throws IndexOutOfBoundsException
- * if <tt>beginIndex</tt> or <tt>endIndex</tt> are negative,
- * if <tt>endIndex</tt> is greater than <tt>length()</tt>,
- * or if <tt>beginIndex</tt> is greater than <tt>startIndex</tt>
+ * if {@code beginIndex} or {@code endIndex} is negative,
+ * if {@code endIndex} is greater than {@code length()},
+ * or if {@code beginIndex} is greater than {@code endIndex}
*
* @since 1.4
* @spec JSR-51
@@ -1972,11 +1995,11 @@
/**
* Concatenates the specified string to the end of this string.
* <p>
- * If the length of the argument string is <code>0</code>, then this
- * <code>String</code> object is returned. Otherwise, a new
- * <code>String</code> object is created, representing a character
+ * If the length of the argument string is {@code 0}, then this
+ * {@code String} object is returned. Otherwise, a
+ * {@code String} object is returned that represents a character
* sequence that is the concatenation of the character sequence
- * represented by this <code>String</code> object and the character
+ * represented by this {@code String} object and the character
* sequence represented by the argument string.<p>
* Examples:
* <blockquote><pre>
@@ -1984,25 +2007,25 @@
* "to".concat("get").concat("her") returns "together"
* </pre></blockquote>
*
- * @param str the <code>String</code> that is concatenated to the end
- * of this <code>String</code>.
+ * @param str the {@code String} that is concatenated to the end
+ * of this {@code String}.
* @return a string that represents the concatenation of this object's
* characters followed by the string argument's characters.
*/
public native String concat(String str);
/**
- * Returns a new string resulting from replacing all occurrences of
- * <code>oldChar</code> in this string with <code>newChar</code>.
+ * Returns a string resulting from replacing all occurrences of
+ * {@code oldChar} in this string with {@code newChar}.
* <p>
- * If the character <code>oldChar</code> does not occur in the
- * character sequence represented by this <code>String</code> object,
- * then a reference to this <code>String</code> object is returned.
- * Otherwise, a new <code>String</code> object is created that
+ * If the character {@code oldChar} does not occur in the
+ * character sequence represented by this {@code String} object,
+ * then a reference to this {@code String} object is returned.
+ * Otherwise, a {@code String} object is returned that
* represents a character sequence identical to the character sequence
- * represented by this <code>String</code> object, except that every
- * occurrence of <code>oldChar</code> is replaced by an occurrence
- * of <code>newChar</code>.
+ * represented by this {@code String} object, except that every
+ * occurrence of {@code oldChar} is replaced by an occurrence
+ * of {@code newChar}.
* <p>
* Examples:
* <blockquote><pre>
@@ -2018,7 +2041,7 @@
* @param oldChar the old character.
* @param newChar the new character.
* @return a string derived from this string by replacing every
- * occurrence of <code>oldChar</code> with <code>newChar</code>.
+ * occurrence of {@code oldChar} with {@code newChar}.
*/
public String replace(char oldChar, char newChar) {
String replaced = this;
@@ -2040,17 +2063,18 @@
* href="../util/regex/Pattern.html#sum">regular expression</a>.
*
* <p> An invocation of this method of the form
- * <i>str</i><tt>.matches(</tt><i>regex</i><tt>)</tt> yields exactly the
+ * <i>str</i>{@code .matches(}<i>regex</i>{@code )} yields exactly the
* same result as the expression
*
- * <blockquote><tt> {@link java.util.regex.Pattern}.{@link
- * java.util.regex.Pattern#matches(String,CharSequence)
- * matches}(</tt><i>regex</i><tt>,</tt> <i>str</i><tt>)</tt></blockquote>
+ * <blockquote>
+ * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#matches(String,CharSequence)
+ * matches(<i>regex</i>, <i>str</i>)}
+ * </blockquote>
*
* @param regex
* the regular expression to which this string is to be matched
*
- * @return <tt>true</tt> if, and only if, this string matches the
+ * @return {@code true} if, and only if, this string matches the
* given regular expression
*
* @throws PatternSyntaxException
@@ -2070,8 +2094,7 @@
* sequence of char values.
*
* @param s the sequence to search for
- * @return true if this string contains <code>s</code>, false otherwise
- * @throws NullPointerException if <code>s</code> is <code>null</code>
+ * @return true if this string contains {@code s}, false otherwise
* @since 1.5
*/
public boolean contains(CharSequence s) {
@@ -2084,18 +2107,20 @@
* given replacement.
*
* <p> An invocation of this method of the form
- * <i>str</i><tt>.replaceFirst(</tt><i>regex</i><tt>,</tt> <i>repl</i><tt>)</tt>
+ * <i>str</i>{@code .replaceFirst(}<i>regex</i>{@code ,} <i>repl</i>{@code )}
* yields exactly the same result as the expression
*
- * <blockquote><tt>
- * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile
- * compile}(</tt><i>regex</i><tt>).{@link
- * java.util.regex.Pattern#matcher(java.lang.CharSequence)
- * matcher}(</tt><i>str</i><tt>).{@link java.util.regex.Matcher#replaceFirst
- * replaceFirst}(</tt><i>repl</i><tt>)</tt></blockquote>
+ * <blockquote>
+ * <code>
+ * {@link java.util.regex.Pattern}.{@link
+ * java.util.regex.Pattern#compile compile}(<i>regex</i>).{@link
+ * java.util.regex.Pattern#matcher(java.lang.CharSequence) matcher}(<i>str</i>).{@link
+ * java.util.regex.Matcher#replaceFirst replaceFirst}(<i>repl</i>)
+ * </code>
+ * </blockquote>
*
*<p>
- * Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in the
+ * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
* replacement string may cause the results to be different than if it were
* being treated as a literal replacement string; see
* {@link java.util.regex.Matcher#replaceFirst}.
@@ -2107,7 +2132,7 @@
* @param replacement
* the string to be substituted for the first match
*
- * @return The resulting <tt>String</tt>
+ * @return The resulting {@code String}
*
* @throws PatternSyntaxException
* if the regular expression's syntax is invalid
@@ -2127,18 +2152,20 @@
* given replacement.
*
* <p> An invocation of this method of the form
- * <i>str</i><tt>.replaceAll(</tt><i>regex</i><tt>,</tt> <i>repl</i><tt>)</tt>
+ * <i>str</i>{@code .replaceAll(}<i>regex</i>{@code ,} <i>repl</i>{@code )}
* yields exactly the same result as the expression
*
- * <blockquote><tt>
- * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile
- * compile}(</tt><i>regex</i><tt>).{@link
- * java.util.regex.Pattern#matcher(java.lang.CharSequence)
- * matcher}(</tt><i>str</i><tt>).{@link java.util.regex.Matcher#replaceAll
- * replaceAll}(</tt><i>repl</i><tt>)</tt></blockquote>
+ * <blockquote>
+ * <code>
+ * {@link java.util.regex.Pattern}.{@link
+ * java.util.regex.Pattern#compile compile}(<i>regex</i>).{@link
+ * java.util.regex.Pattern#matcher(java.lang.CharSequence) matcher}(<i>str</i>).{@link
+ * java.util.regex.Matcher#replaceAll replaceAll}(<i>repl</i>)
+ * </code>
+ * </blockquote>
*
*<p>
- * Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in the
+ * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
* replacement string may cause the results to be different than if it were
* being treated as a literal replacement string; see
* {@link java.util.regex.Matcher#replaceAll Matcher.replaceAll}.
@@ -2150,7 +2177,7 @@
* @param replacement
* the string to be substituted for each match
*
- * @return The resulting <tt>String</tt>
+ * @return The resulting {@code String}
*
* @throws PatternSyntaxException
* if the regular expression's syntax is invalid
@@ -2246,7 +2273,12 @@
* expression does not match any part of the input then the resulting array
* has just one element, namely this string.
*
- * <p> The <tt>limit</tt> parameter controls the number of times the
+ * <p> When there is a positive-width match at the beginning of this
+ * string then an empty leading substring is included at the beginning
+ * of the resulting array. A zero-width match at the beginning however
+ * never produces such empty leading substring.
+ *
+ * <p> The {@code limit} parameter controls the number of times the
* pattern is applied and therefore affects the length of the resulting
* array. If the limit <i>n</i> is greater than zero then the pattern
* will be applied at most <i>n</i> - 1 times, the array's
@@ -2257,7 +2289,7 @@
* the pattern will be applied as many times as possible, the array can
* have any length, and trailing empty strings will be discarded.
*
- * <p> The string <tt>"boo:and:foo"</tt>, for example, yields the
+ * <p> The string {@code "boo:and:foo"}, for example, yields the
* following results with these parameters:
*
* <blockquote><table cellpadding=1 cellspacing=0 summary="Split example showing regex, limit, and result">
@@ -2268,33 +2300,34 @@
* </tr>
* <tr><td align=center>:</td>
* <td align=center>2</td>
- * <td><tt>{ "boo", "and:foo" }</tt></td></tr>
+ * <td>{@code { "boo", "and:foo" }}</td></tr>
* <tr><td align=center>:</td>
* <td align=center>5</td>
- * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+ * <td>{@code { "boo", "and", "foo" }}</td></tr>
* <tr><td align=center>:</td>
* <td align=center>-2</td>
- * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+ * <td>{@code { "boo", "and", "foo" }}</td></tr>
* <tr><td align=center>o</td>
* <td align=center>5</td>
- * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
+ * <td>{@code { "b", "", ":and:f", "", "" }}</td></tr>
* <tr><td align=center>o</td>
* <td align=center>-2</td>
- * <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
+ * <td>{@code { "b", "", ":and:f", "", "" }}</td></tr>
* <tr><td align=center>o</td>
* <td align=center>0</td>
- * <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
+ * <td>{@code { "b", "", ":and:f" }}</td></tr>
* </table></blockquote>
*
* <p> An invocation of this method of the form
- * <i>str.</i><tt>split(</tt><i>regex</i><tt>,</tt> <i>n</i><tt>)</tt>
+ * <i>str.</i>{@code split(}<i>regex</i>{@code ,} <i>n</i>{@code )}
* yields the same result as the expression
*
* <blockquote>
- * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#compile
- * compile}<tt>(</tt><i>regex</i><tt>)</tt>.{@link
- * java.util.regex.Pattern#split(java.lang.CharSequence,int)
- * split}<tt>(</tt><i>str</i><tt>,</tt> <i>n</i><tt>)</tt>
+ * <code>
+ * {@link java.util.regex.Pattern}.{@link
+ * java.util.regex.Pattern#compile compile}(<i>regex</i>).{@link
+ * java.util.regex.Pattern#split(java.lang.CharSequence,int) split}(<i>str</i>, <i>n</i>)
+ * </code>
* </blockquote>
*
*
@@ -2334,7 +2367,7 @@
* argument of zero. Trailing empty strings are therefore not included in
* the resulting array.
*
- * <p> The string <tt>"boo:and:foo"</tt>, for example, yields the following
+ * <p> The string {@code "boo:and:foo"}, for example, yields the following
* results with these expressions:
*
* <blockquote><table cellpadding=1 cellspacing=0 summary="Split examples showing regex and result">
@@ -2343,9 +2376,9 @@
* <th>Result</th>
* </tr>
* <tr><td align=center>:</td>
- * <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+ * <td>{@code { "boo", "and", "foo" }}</td></tr>
* <tr><td align=center>o</td>
- * <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
+ * <td>{@code { "b", "", ":and:f" }}</td></tr>
* </table></blockquote>
*
*
@@ -2368,11 +2401,95 @@
}
/**
- * Converts all of the characters in this <code>String</code> to lower
- * case using the rules of the given <code>Locale</code>. Case mapping is based
+ * Returns a new String composed of copies of the
+ * {@code CharSequence elements} joined together with a copy of
+ * the specified {@code delimiter}.
+ *
+ * <blockquote>For example,
+ * <pre>{@code
+ * String message = String.join("-", "Java", "is", "cool");
+ * // message returned is: "Java-is-cool"
+ * }</pre></blockquote>
+ *
+ * Note that if an element is null, then {@code "null"} is added.
+ *
+ * @param delimiter the delimiter that separates each element
+ * @param elements the elements to join together.
+ *
+ * @return a new {@code String} that is composed of the {@code elements}
+ * separated by the {@code delimiter}
+ *
+ * @throws NullPointerException If {@code delimiter} or {@code elements}
+ * is {@code null}
+ *
+ * @see java.util.StringJoiner
+ * @since 1.8
+ */
+ public static String join(CharSequence delimiter, CharSequence... elements) {
+ Objects.requireNonNull(delimiter);
+ Objects.requireNonNull(elements);
+ // Number of elements not likely worth Arrays.stream overhead.
+ StringJoiner joiner = new StringJoiner(delimiter);
+ for (CharSequence cs: elements) {
+ joiner.add(cs);
+ }
+ return joiner.toString();
+ }
+
+ /**
+ * Returns a new {@code String} composed of copies of the
+ * {@code CharSequence elements} joined together with a copy of the
+ * specified {@code delimiter}.
+ *
+ * <blockquote>For example,
+ * <pre>{@code
+ * List<String> strings = new LinkedList<>();
+ * strings.add("Java");strings.add("is");
+ * strings.add("cool");
+ * String message = String.join(" ", strings);
+ * //message returned is: "Java is cool"
+ *
+ * Set<String> strings = new LinkedHashSet<>();
+ * strings.add("Java"); strings.add("is");
+ * strings.add("very"); strings.add("cool");
+ * String message = String.join("-", strings);
+ * //message returned is: "Java-is-very-cool"
+ * }</pre></blockquote>
+ *
+ * Note that if an individual element is {@code null}, then {@code "null"} is added.
+ *
+ * @param delimiter a sequence of characters that is used to separate each
+ * of the {@code elements} in the resulting {@code String}
+ * @param elements an {@code Iterable} that will have its {@code elements}
+ * joined together.
+ *
+ * @return a new {@code String} that is composed from the {@code elements}
+ * argument
+ *
+ * @throws NullPointerException If {@code delimiter} or {@code elements}
+ * is {@code null}
+ *
+ * @see #join(CharSequence,CharSequence...)
+ * @see java.util.StringJoiner
+ * @since 1.8
+ */
+ public static String join(CharSequence delimiter,
+ Iterable<? extends CharSequence> elements) {
+ Objects.requireNonNull(delimiter);
+ Objects.requireNonNull(elements);
+ StringJoiner joiner = new StringJoiner(delimiter);
+ for (CharSequence cs: elements) {
+ joiner.add(cs);
+ }
+ return joiner.toString();
+ }
+
+ /**
+ * Converts all of the characters in this {@code String} to lower
+ * case using the rules of the given {@code Locale}. Case mapping is based
* on the Unicode Standard version specified by the {@link java.lang.Character Character}
* class. Since case mappings are not always 1:1 char mappings, the resulting
- * <code>String</code> may be a different length than the original <code>String</code>.
+ * {@code String} may be a different length than the original {@code String}.
* <p>
* Examples of lowercase mappings are in the following table:
* <table border="1" summary="Lowercase mapping examples showing language code of locale, upper case, lower case, and description">
@@ -2413,7 +2530,7 @@
* </table>
*
* @param locale use the case transformation rules for this locale
- * @return the <code>String</code>, converted to lowercase.
+ * @return the {@code String}, converted to lowercase.
* @see java.lang.String#toLowerCase()
* @see java.lang.String#toUpperCase()
* @see java.lang.String#toUpperCase(Locale)
@@ -2424,22 +2541,22 @@
}
/**
- * Converts all of the characters in this <code>String</code> to lower
+ * Converts all of the characters in this {@code String} to lower
* case using the rules of the default locale. This is equivalent to calling
- * <code>toLowerCase(Locale.getDefault())</code>.
+ * {@code toLowerCase(Locale.getDefault())}.
* <p>
* <b>Note:</b> This method is locale sensitive, and may produce unexpected
* results if used for strings that are intended to be interpreted locale
* independently.
* Examples are programming language identifiers, protocol keys, and HTML
* tags.
- * For instance, <code>"TITLE".toLowerCase()</code> in a Turkish locale
- * returns <code>"t\u005Cu0131tle"</code>, where '\u005Cu0131' is the
+ * For instance, {@code "TITLE".toLowerCase()} in a Turkish locale
+ * returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
* LATIN SMALL LETTER DOTLESS I character.
* To obtain correct results for locale insensitive strings, use
- * <code>toLowerCase(Locale.ENGLISH)</code>.
+ * {@code toLowerCase(Locale.ROOT)}.
* <p>
- * @return the <code>String</code>, converted to lowercase.
+ * @return the {@code String}, converted to lowercase.
* @see java.lang.String#toLowerCase(Locale)
*/
public String toLowerCase() {
@@ -2447,14 +2564,14 @@
}
/**
- * Converts all of the characters in this <code>String</code> to upper
- * case using the rules of the given <code>Locale</code>. Case mapping is based
+ * Converts all of the characters in this {@code String} to upper
+ * case using the rules of the given {@code Locale}. Case mapping is based
* on the Unicode Standard version specified by the {@link java.lang.Character Character}
* class. Since case mappings are not always 1:1 char mappings, the resulting
- * <code>String</code> may be a different length than the original <code>String</code>.
+ * {@code String} may be a different length than the original {@code String}.
* <p>
* Examples of locale-sensitive and 1:M case mappings are in the following table.
- * <p>
+ *
* <table border="1" summary="Examples of locale-sensitive and 1:M case mappings. Shows Language code of locale, lower case, upper case, and description.">
* <tr>
* <th>Language Code of Locale</th>
@@ -2488,7 +2605,7 @@
* </tr>
* </table>
* @param locale use the case transformation rules for this locale
- * @return the <code>String</code>, converted to uppercase.
+ * @return the {@code String}, converted to uppercase.
* @see java.lang.String#toUpperCase()
* @see java.lang.String#toLowerCase()
* @see java.lang.String#toLowerCase(Locale)
@@ -2499,22 +2616,22 @@
}
/**
- * Converts all of the characters in this <code>String</code> to upper
+ * Converts all of the characters in this {@code String} to upper
* case using the rules of the default locale. This method is equivalent to
- * <code>toUpperCase(Locale.getDefault())</code>.
+ * {@code toUpperCase(Locale.getDefault())}.
* <p>
* <b>Note:</b> This method is locale sensitive, and may produce unexpected
* results if used for strings that are intended to be interpreted locale
* independently.
* Examples are programming language identifiers, protocol keys, and HTML
* tags.
- * For instance, <code>"title".toUpperCase()</code> in a Turkish locale
- * returns <code>"T\u005Cu0130TLE"</code>, where '\u005Cu0130' is the
+ * For instance, {@code "title".toUpperCase()} in a Turkish locale
+ * returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the
* LATIN CAPITAL LETTER I WITH DOT ABOVE character.
* To obtain correct results for locale insensitive strings, use
- * <code>toUpperCase(Locale.ENGLISH)</code>.
+ * {@code toUpperCase(Locale.ROOT)}.
* <p>
- * @return the <code>String</code>, converted to uppercase.
+ * @return the {@code String}, converted to uppercase.
* @see java.lang.String#toUpperCase(Locale)
*/
public String toUpperCase() {
@@ -2522,33 +2639,33 @@
}
/**
- * Returns a copy of the string, with leading and trailing whitespace
- * omitted.
+ * Returns a string whose value is this string, with any leading and trailing
+ * whitespace removed.
* <p>
- * If this <code>String</code> object represents an empty character
+ * If this {@code String} object represents an empty character
* sequence, or the first and last characters of character sequence
- * represented by this <code>String</code> object both have codes
- * greater than <code>'\u0020'</code> (the space character), then a
- * reference to this <code>String</code> object is returned.
+ * represented by this {@code String} object both have codes
+ * greater than {@code '\u005Cu0020'} (the space character), then a
+ * reference to this {@code String} object is returned.
* <p>
* Otherwise, if there is no character with a code greater than
- * <code>'\u0020'</code> in the string, then a new
- * <code>String</code> object representing an empty string is created
- * and returned.
+ * {@code '\u005Cu0020'} in the string, then a
+ * {@code String} object representing an empty string is
+ * returned.
* <p>
* Otherwise, let <i>k</i> be the index of the first character in the
- * string whose code is greater than <code>'\u0020'</code>, and let
+ * string whose code is greater than {@code '\u005Cu0020'}, and let
* <i>m</i> be the index of the last character in the string whose code
- * is greater than <code>'\u0020'</code>. A new <code>String</code>
- * object is created, representing the substring of this string that
+ * is greater than {@code '\u005Cu0020'}. A {@code String}
+ * object is returned, representing the substring of this string that
* begins with the character at index <i>k</i> and ends with the
* character at index <i>m</i>-that is, the result of
- * <code>this.substring(<i>k</i>, <i>m</i>+1)</code>.
+ * {@code this.substring(k, m + 1)}.
* <p>
* This method may be used to trim whitespace (as defined above) from
* the beginning and end of a string.
*
- * @return A copy of this string with leading and trailing white
+ * @return A string whose value is this string, with any leading and trailing white
* space removed, or this string if it has no leading or
* trailing white space.
*/
@@ -2602,10 +2719,10 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
+ * {@code null} argument depends on the <a
* href="../util/Formatter.html#syntax">conversion</a>.
*
- * @throws IllegalFormatException
+ * @throws java.util.IllegalFormatException
* If a format string contains an illegal syntax, a format
* specifier that is incompatible with the given arguments,
* insufficient arguments given the format string, or other
@@ -2632,7 +2749,7 @@
*
* @param l
* The {@linkplain java.util.Locale locale} to apply during
- * formatting. If <tt>l</tt> is <tt>null</tt> then no localization
+ * formatting. If {@code l} is {@code null} then no localization
* is applied.
*
* @param format
@@ -2646,10 +2763,10 @@
* limited by the maximum dimension of a Java array as defined by
* <cite>The Java™ Virtual Machine Specification</cite>.
* The behaviour on a
- * <tt>null</tt> argument depends on the <a
- * href="../util/Formatter.html#syntax">conversion</a>.
+ * {@code null} argument depends on the
+ * <a href="../util/Formatter.html#syntax">conversion</a>.
*
- * @throws IllegalFormatException
+ * @throws java.util.IllegalFormatException
* If a format string contains an illegal syntax, a format
* specifier that is incompatible with the given arguments,
* insufficient arguments given the format string, or other
@@ -2671,12 +2788,12 @@
}
/**
- * Returns the string representation of the <code>Object</code> argument.
+ * Returns the string representation of the {@code Object} argument.
*
- * @param obj an <code>Object</code>.
- * @return if the argument is <code>null</code>, then a string equal to
- * <code>"null"</code>; otherwise, the value of
- * <code>obj.toString()</code> is returned.
+ * @param obj an {@code Object}.
+ * @return if the argument is {@code null}, then a string equal to
+ * {@code "null"}; otherwise, the value of
+ * {@code obj.toString()} is returned.
* @see java.lang.Object#toString()
*/
public static String valueOf(Object obj) {
@@ -2684,14 +2801,14 @@
}
/**
- * Returns the string representation of the <code>char</code> array
+ * Returns the string representation of the {@code char} array
* argument. The contents of the character array are copied; subsequent
- * modification of the character array does not affect the newly
- * created string.
+ * modification of the character array does not affect the returned
+ * string.
*
- * @param data a <code>char</code> array.
- * @return a newly allocated string representing the same sequence of
- * characters contained in the character array argument.
+ * @param data the character array.
+ * @return a {@code String} that contains the characters of the
+ * character array.
*/
public static String valueOf(char data[]) {
return StringFactory.newStringFromChars(data);
@@ -2699,38 +2816,40 @@
/**
* Returns the string representation of a specific subarray of the
- * <code>char</code> array argument.
+ * {@code char} array argument.
* <p>
- * The <code>offset</code> argument is the index of the first
- * character of the subarray. The <code>count</code> argument
+ * The {@code offset} argument is the index of the first
+ * character of the subarray. The {@code count} argument
* specifies the length of the subarray. The contents of the subarray
* are copied; subsequent modification of the character array does not
- * affect the newly created string.
+ * affect the returned string.
*
* @param data the character array.
- * @param offset the initial offset into the value of the
- * <code>String</code>.
- * @param count the length of the value of the <code>String</code>.
- * @return a string representing the sequence of characters contained
- * in the subarray of the character array argument.
- * @exception IndexOutOfBoundsException if <code>offset</code> is
- * negative, or <code>count</code> is negative, or
- * <code>offset+count</code> is larger than
- * <code>data.length</code>.
+ * @param offset initial offset of the subarray.
+ * @param count length of the subarray.
+ * @return a {@code String} that contains the characters of the
+ * specified subarray of the character array.
+ * @exception IndexOutOfBoundsException if {@code offset} is
+ * negative, or {@code count} is negative, or
+ * {@code offset+count} is larger than
+ * {@code data.length}.
*/
public static String valueOf(char data[], int offset, int count) {
return StringFactory.newStringFromChars(data, offset, count);
}
/**
- * Returns a String that represents the character sequence in the
- * array specified.
+ * Equivalent to {@link #valueOf(char[], int, int)}.
*
* @param data the character array.
* @param offset initial offset of the subarray.
* @param count length of the subarray.
- * @return a <code>String</code> that contains the characters of the
+ * @return a {@code String} that contains the characters of the
* specified subarray of the character array.
+ * @exception IndexOutOfBoundsException if {@code offset} is
+ * negative, or {@code count} is negative, or
+ * {@code offset+count} is larger than
+ * {@code data.length}.
*/
public static String copyValueOf(char data[], int offset, int count) {
// All public String constructors now copy the data.
@@ -2738,11 +2857,10 @@
}
/**
- * Returns a String that represents the character sequence in the
- * array specified.
+ * Equivalent to {@link #valueOf(char[])}.
*
* @param data the character array.
- * @return a <code>String</code> that contains the characters of the
+ * @return a {@code String} that contains the characters of the
* character array.
*/
public static String copyValueOf(char data[]) {
@@ -2750,37 +2868,37 @@
}
/**
- * Returns the string representation of the <code>boolean</code> argument.
+ * Returns the string representation of the {@code boolean} argument.
*
- * @param b a <code>boolean</code>.
- * @return if the argument is <code>true</code>, a string equal to
- * <code>"true"</code> is returned; otherwise, a string equal to
- * <code>"false"</code> is returned.
+ * @param b a {@code boolean}.
+ * @return if the argument is {@code true}, a string equal to
+ * {@code "true"} is returned; otherwise, a string equal to
+ * {@code "false"} is returned.
*/
public static String valueOf(boolean b) {
return b ? "true" : "false";
}
/**
- * Returns the string representation of the <code>char</code>
+ * Returns the string representation of the {@code char}
* argument.
*
- * @param c a <code>char</code>.
- * @return a string of length <code>1</code> containing
- * as its single character the argument <code>c</code>.
+ * @param c a {@code char}.
+ * @return a string of length {@code 1} containing
+ * as its single character the argument {@code c}.
*/
public static String valueOf(char c) {
return StringFactory.newStringFromChars(0, 1, new char[] { c });
}
/**
- * Returns the string representation of the <code>int</code> argument.
+ * Returns the string representation of the {@code int} argument.
* <p>
* The representation is exactly the one returned by the
- * <code>Integer.toString</code> method of one argument.
+ * {@code Integer.toString} method of one argument.
*
- * @param i an <code>int</code>.
- * @return a string representation of the <code>int</code> argument.
+ * @param i an {@code int}.
+ * @return a string representation of the {@code int} argument.
* @see java.lang.Integer#toString(int, int)
*/
public static String valueOf(int i) {
@@ -2788,13 +2906,13 @@
}
/**
- * Returns the string representation of the <code>long</code> argument.
+ * Returns the string representation of the {@code long} argument.
* <p>
* The representation is exactly the one returned by the
- * <code>Long.toString</code> method of one argument.
+ * {@code Long.toString} method of one argument.
*
- * @param l a <code>long</code>.
- * @return a string representation of the <code>long</code> argument.
+ * @param l a {@code long}.
+ * @return a string representation of the {@code long} argument.
* @see java.lang.Long#toString(long)
*/
public static String valueOf(long l) {
@@ -2802,13 +2920,13 @@
}
/**
- * Returns the string representation of the <code>float</code> argument.
+ * Returns the string representation of the {@code float} argument.
* <p>
* The representation is exactly the one returned by the
- * <code>Float.toString</code> method of one argument.
+ * {@code Float.toString} method of one argument.
*
- * @param f a <code>float</code>.
- * @return a string representation of the <code>float</code> argument.
+ * @param f a {@code float}.
+ * @return a string representation of the {@code float} argument.
* @see java.lang.Float#toString(float)
*/
public static String valueOf(float f) {
@@ -2816,13 +2934,13 @@
}
/**
- * Returns the string representation of the <code>double</code> argument.
+ * Returns the string representation of the {@code double} argument.
* <p>
* The representation is exactly the one returned by the
- * <code>Double.toString</code> method of one argument.
+ * {@code Double.toString} method of one argument.
*
- * @param d a <code>double</code>.
- * @return a string representation of the <code>double</code> argument.
+ * @param d a {@code double}.
+ * @return a string representation of the {@code double} argument.
* @see java.lang.Double#toString(double)
*/
public static String valueOf(double d) {
@@ -2833,17 +2951,17 @@
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
- * class <code>String</code>.
+ * class {@code String}.
* <p>
* When the intern method is invoked, if the pool already contains a
- * string equal to this <code>String</code> object as determined by
+ * string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
- * returned. Otherwise, this <code>String</code> object is added to the
- * pool and a reference to this <code>String</code> object is returned.
+ * returned. Otherwise, this {@code String} object is added to the
+ * pool and a reference to this {@code String} object is returned.
* <p>
- * It follows that for any two strings <code>s</code> and <code>t</code>,
- * <code>s.intern() == t.intern()</code> is <code>true</code>
- * if and only if <code>s.equals(t)</code> is <code>true</code>.
+ * It follows that for any two strings {@code s} and {@code t},
+ * {@code s.intern() == t.intern()} is {@code true}
+ * if and only if {@code s.equals(t)} is {@code true}.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
diff --git a/ojluni/src/main/java/java/lang/StringBuffer.java b/ojluni/src/main/java/java/lang/StringBuffer.java
old mode 100755
new mode 100644
index d832881..95a583d
--- a/ojluni/src/main/java/java/lang/StringBuffer.java
+++ b/ojluni/src/main/java/java/lang/StringBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
package java.lang;
+import java.util.Arrays;
/**
* A thread-safe, mutable sequence of characters.
@@ -39,39 +40,52 @@
* that is consistent with the order of the method calls made by each of
* the individual threads involved.
* <p>
- * The principal operations on a <code>StringBuffer</code> are the
- * <code>append</code> and <code>insert</code> methods, which are
+ * The principal operations on a {@code StringBuffer} are the
+ * {@code append} and {@code insert} methods, which are
* overloaded so as to accept data of any type. Each effectively
* converts a given datum to a string and then appends or inserts the
* characters of that string to the string buffer. The
- * <code>append</code> method always adds these characters at the end
- * of the buffer; the <code>insert</code> method adds the characters at
+ * {@code append} method always adds these characters at the end
+ * of the buffer; the {@code insert} method adds the characters at
* a specified point.
* <p>
- * For example, if <code>z</code> refers to a string buffer object
- * whose current contents are "<code>start</code>", then
- * the method call <code>z.append("le")</code> would cause the string
- * buffer to contain "<code>startle</code>", whereas
- * <code>z.insert(4, "le")</code> would alter the string buffer to
- * contain "<code>starlet</code>".
+ * For example, if {@code z} refers to a string buffer object
+ * whose current contents are {@code "start"}, then
+ * the method call {@code z.append("le")} would cause the string
+ * buffer to contain {@code "startle"}, whereas
+ * {@code z.insert(4, "le")} would alter the string buffer to
+ * contain {@code "starlet"}.
* <p>
- * In general, if sb refers to an instance of a <code>StringBuffer</code>,
- * then <code>sb.append(x)</code> has the same effect as
- * <code>sb.insert(sb.length(), x)</code>.
+ * In general, if sb refers to an instance of a {@code StringBuffer},
+ * then {@code sb.append(x)} has the same effect as
+ * {@code sb.insert(sb.length(), x)}.
* <p>
* Whenever an operation occurs involving a source sequence (such as
- * appending or inserting from a source sequence) this class synchronizes
+ * appending or inserting from a source sequence), this class synchronizes
* only on the string buffer performing the operation, not on the source.
+ * Note that while {@code StringBuffer} is designed to be safe to use
+ * concurrently from multiple threads, if the constructor or the
+ * {@code append} or {@code insert} operation is passed a source sequence
+ * that is shared across threads, the calling code must ensure
+ * that the operation has a consistent and unchanging view of the source
+ * sequence for the duration of the operation.
+ * This could be satisfied by the caller holding a lock during the
+ * operation's call, by using an immutable source sequence, or by not
+ * sharing the source sequence across threads.
* <p>
* Every string buffer has a capacity. As long as the length of the
* character sequence contained in the string buffer does not exceed
* the capacity, it is not necessary to allocate a new internal
* buffer array. If the internal buffer overflows, it is
* automatically made larger.
- *
+ * <p>
+ * Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ * <p>
* As of release JDK 5, this class has been supplemented with an equivalent
* class designed for use by a single thread, {@link StringBuilder}. The
- * <tt>StringBuilder</tt> class should generally be used in preference to
+ * {@code StringBuilder} class should generally be used in preference to
* this one, as it supports all of the same operations but it is faster, as
* it performs no synchronization.
*
@@ -82,9 +96,15 @@
*/
public final class StringBuffer
extends AbstractStringBuilder
- implements java.io.Serializable, Appendable, CharSequence
+ implements java.io.Serializable, CharSequence
{
+ /**
+ * A cache of the last value returned by toString. Cleared
+ * whenever the StringBuffer is modified.
+ */
+ private transient char[] toStringCache;
+
/** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L;
@@ -101,8 +121,8 @@
* the specified initial capacity.
*
* @param capacity the initial capacity.
- * @exception NegativeArraySizeException if the <code>capacity</code>
- * argument is less than <code>0</code>.
+ * @exception NegativeArraySizeException if the {@code capacity}
+ * argument is less than {@code 0}.
*/
public StringBuffer(int capacity) {
super(capacity);
@@ -111,10 +131,9 @@
/**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
- * <code>16</code> plus the length of the string argument.
+ * {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
- * @exception NullPointerException if <code>str</code> is <code>null</code>
*/
public StringBuffer(String str) {
super(str.length() + 16);
@@ -123,16 +142,15 @@
/**
* Constructs a string buffer that contains the same characters
- * as the specified <code>CharSequence</code>. The initial capacity of
- * the string buffer is <code>16</code> plus the length of the
- * <code>CharSequence</code> argument.
+ * as the specified {@code CharSequence}. The initial capacity of
+ * the string buffer is {@code 16} plus the length of the
+ * {@code CharSequence} argument.
* <p>
- * If the length of the specified <code>CharSequence</code> is
+ * If the length of the specified {@code CharSequence} is
* less than or equal to zero, then an empty buffer of capacity
- * <code>16</code> is returned.
+ * {@code 16} is returned.
*
* @param seq the sequence to copy.
- * @exception NullPointerException if <code>seq</code> is <code>null</code>
* @since 1.5
*/
public StringBuffer(CharSequence seq) {
@@ -140,15 +158,18 @@
append(seq);
}
+ @Override
public synchronized int length() {
return count;
}
+ @Override
public synchronized int capacity() {
return value.length;
}
+ @Override
public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
@@ -158,6 +179,7 @@
/**
* @since 1.5
*/
+ @Override
public synchronized void trimToSize() {
super.trimToSize();
}
@@ -166,7 +188,9 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
+ @Override
public synchronized void setLength(int newLength) {
+ toStringCache = null;
super.setLength(newLength);
}
@@ -174,6 +198,7 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
+ @Override
public synchronized char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
@@ -183,6 +208,7 @@
/**
* @since 1.5
*/
+ @Override
public synchronized int codePointAt(int index) {
return super.codePointAt(index);
}
@@ -190,6 +216,7 @@
/**
* @since 1.5
*/
+ @Override
public synchronized int codePointBefore(int index) {
return super.codePointBefore(index);
}
@@ -197,6 +224,7 @@
/**
* @since 1.5
*/
+ @Override
public synchronized int codePointCount(int beginIndex, int endIndex) {
return super.codePointCount(beginIndex, endIndex);
}
@@ -204,14 +232,15 @@
/**
* @since 1.5
*/
+ @Override
public synchronized int offsetByCodePoints(int index, int codePointOffset) {
return super.offsetByCodePoints(index, codePointOffset);
}
/**
- * @throws NullPointerException {@inheritDoc}
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
int dstBegin)
{
@@ -222,95 +251,111 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
* @see #length()
*/
+ @Override
public synchronized void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
+ toStringCache = null;
value[index] = ch;
}
+ @Override
public synchronized StringBuffer append(Object obj) {
+ toStringCache = null;
super.append(String.valueOf(obj));
return this;
}
+ @Override
public synchronized StringBuffer append(String str) {
+ toStringCache = null;
super.append(str);
return this;
}
/**
- * Appends the specified <tt>StringBuffer</tt> to this sequence.
+ * Appends the specified {@code StringBuffer} to this sequence.
* <p>
- * The characters of the <tt>StringBuffer</tt> argument are appended,
- * in order, to the contents of this <tt>StringBuffer</tt>, increasing the
- * length of this <tt>StringBuffer</tt> by the length of the argument.
- * If <tt>sb</tt> is <tt>null</tt>, then the four characters
- * <tt>"null"</tt> are appended to this <tt>StringBuffer</tt>.
+ * The characters of the {@code StringBuffer} argument are appended,
+ * in order, to the contents of this {@code StringBuffer}, increasing the
+ * length of this {@code StringBuffer} by the length of the argument.
+ * If {@code sb} is {@code null}, then the four characters
+ * {@code "null"} are appended to this {@code StringBuffer}.
* <p>
* Let <i>n</i> be the length of the old character sequence, the one
- * contained in the <tt>StringBuffer</tt> just prior to execution of the
- * <tt>append</tt> method. Then the character at index <i>k</i> in
+ * contained in the {@code StringBuffer} just prior to execution of the
+ * {@code append} method. Then the character at index <i>k</i> in
* the new character sequence is equal to the character at index <i>k</i>
* in the old character sequence, if <i>k</i> is less than <i>n</i>;
* otherwise, it is equal to the character at index <i>k-n</i> in the
- * argument <code>sb</code>.
+ * argument {@code sb}.
* <p>
- * This method synchronizes on <code>this</code> (the destination)
- * object but does not synchronize on the source (<code>sb</code>).
+ * This method synchronizes on {@code this}, the destination
+ * object, but does not synchronize on the source ({@code sb}).
*
- * @param sb the <tt>StringBuffer</tt> to append.
+ * @param sb the {@code StringBuffer} to append.
* @return a reference to this object.
* @since 1.4
*/
public synchronized StringBuffer append(StringBuffer sb) {
+ toStringCache = null;
super.append(sb);
return this;
}
+ /**
+ * @since 1.8
+ */
+ @Override
+ synchronized StringBuffer append(AbstractStringBuilder asb) {
+ toStringCache = null;
+ super.append(asb);
+ return this;
+ }
/**
- * Appends the specified <code>CharSequence</code> to this
+ * Appends the specified {@code CharSequence} to this
* sequence.
* <p>
- * The characters of the <code>CharSequence</code> argument are appended,
+ * The characters of the {@code CharSequence} argument are appended,
* in order, increasing the length of this sequence by the length of the
* argument.
*
* <p>The result of this method is exactly the same as if it were an
* invocation of this.append(s, 0, s.length());
*
- * <p>This method synchronizes on this (the destination)
- * object but does not synchronize on the source (<code>s</code>).
+ * <p>This method synchronizes on {@code this}, the destination
+ * object, but does not synchronize on the source ({@code s}).
*
- * <p>If <code>s</code> is <code>null</code>, then the four characters
- * <code>"null"</code> are appended.
+ * <p>If {@code s} is {@code null}, then the four characters
+ * {@code "null"} are appended.
*
- * @param s the <code>CharSequence</code> to append.
+ * @param s the {@code CharSequence} to append.
* @return a reference to this object.
* @since 1.5
*/
- public StringBuffer append(CharSequence s) {
- // Note, synchronization achieved via other invocations
- if (s == null)
- s = "null";
- if (s instanceof String)
- return this.append((String)s);
- if (s instanceof StringBuffer)
- return this.append((StringBuffer)s);
- return this.append(s, 0, s.length());
+ @Override
+ public synchronized StringBuffer append(CharSequence s) {
+ toStringCache = null;
+ super.append(s);
+ return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @since 1.5
*/
+ @Override
public synchronized StringBuffer append(CharSequence s, int start, int end)
{
+ toStringCache = null;
super.append(s, start, end);
return this;
}
+ @Override
public synchronized StringBuffer append(char[] str) {
+ toStringCache = null;
super.append(str);
return this;
}
@@ -318,22 +363,30 @@
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public synchronized StringBuffer append(char[] str, int offset, int len) {
+ toStringCache = null;
super.append(str, offset, len);
return this;
}
+ @Override
public synchronized StringBuffer append(boolean b) {
+ toStringCache = null;
super.append(b);
return this;
}
+ @Override
public synchronized StringBuffer append(char c) {
+ toStringCache = null;
super.append(c);
return this;
}
+ @Override
public synchronized StringBuffer append(int i) {
+ toStringCache = null;
super.append(i);
return this;
}
@@ -341,22 +394,30 @@
/**
* @since 1.5
*/
+ @Override
public synchronized StringBuffer appendCodePoint(int codePoint) {
+ toStringCache = null;
super.appendCodePoint(codePoint);
return this;
}
+ @Override
public synchronized StringBuffer append(long lng) {
+ toStringCache = null;
super.append(lng);
return this;
}
+ @Override
public synchronized StringBuffer append(float f) {
+ toStringCache = null;
super.append(f);
return this;
}
+ @Override
public synchronized StringBuffer append(double d) {
+ toStringCache = null;
super.append(d);
return this;
}
@@ -365,7 +426,9 @@
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
+ @Override
public synchronized StringBuffer delete(int start, int end) {
+ toStringCache = null;
super.delete(start, end);
return this;
}
@@ -374,7 +437,9 @@
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
+ @Override
public synchronized StringBuffer deleteCharAt(int index) {
+ toStringCache = null;
super.deleteCharAt(index);
return this;
}
@@ -383,7 +448,9 @@
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
+ @Override
public synchronized StringBuffer replace(int start, int end, String str) {
+ toStringCache = null;
super.replace(start, end, str);
return this;
}
@@ -392,6 +459,7 @@
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
+ @Override
public synchronized String substring(int start) {
return substring(start, count);
}
@@ -400,6 +468,7 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
* @since 1.4
*/
+ @Override
public synchronized CharSequence subSequence(int start, int end) {
return super.substring(start, end);
}
@@ -408,6 +477,7 @@
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
+ @Override
public synchronized String substring(int start, int end) {
return super.substring(start, end);
}
@@ -416,9 +486,11 @@
* @throws StringIndexOutOfBoundsException {@inheritDoc}
* @since 1.2
*/
+ @Override
public synchronized StringBuffer insert(int index, char[] str, int offset,
int len)
{
+ toStringCache = null;
super.insert(index, str, offset, len);
return this;
}
@@ -426,7 +498,9 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public synchronized StringBuffer insert(int offset, Object obj) {
+ toStringCache = null;
super.insert(offset, String.valueOf(obj));
return this;
}
@@ -434,7 +508,9 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public synchronized StringBuffer insert(int offset, String str) {
+ toStringCache = null;
super.insert(offset, str);
return this;
}
@@ -442,7 +518,9 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public synchronized StringBuffer insert(int offset, char[] str) {
+ toStringCache = null;
super.insert(offset, str);
return this;
}
@@ -451,22 +529,24 @@
* @throws IndexOutOfBoundsException {@inheritDoc}
* @since 1.5
*/
+ @Override
public StringBuffer insert(int dstOffset, CharSequence s) {
- // Note, synchronization achieved via other invocations
- if (s == null)
- s = "null";
- if (s instanceof String)
- return this.insert(dstOffset, (String)s);
- return this.insert(dstOffset, s, 0, s.length());
+ // Note, synchronization achieved via invocations of other StringBuffer methods
+ // after narrowing of s to specific type
+ // Ditto for toStringCache clearing
+ super.insert(dstOffset, s);
+ return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @since 1.5
*/
+ @Override
public synchronized StringBuffer insert(int dstOffset, CharSequence s,
- int start, int end)
+ int start, int end)
{
+ toStringCache = null;
super.insert(dstOffset, s, start, end);
return this;
}
@@ -474,14 +554,21 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
- public StringBuffer insert(int offset, boolean b) {
- return insert(offset, String.valueOf(b));
+ @Override
+ public StringBuffer insert(int offset, boolean b) {
+ // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+ // after conversion of b to String by super class method
+ // Ditto for toStringCache clearing
+ super.insert(offset, b);
+ return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public synchronized StringBuffer insert(int offset, char c) {
+ toStringCache = null;
super.insert(offset, c);
return this;
}
@@ -489,76 +576,101 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuffer insert(int offset, int i) {
- return insert(offset, String.valueOf(i));
+ // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+ // after conversion of i to String by super class method
+ // Ditto for toStringCache clearing
+ super.insert(offset, i);
+ return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuffer insert(int offset, long l) {
- return insert(offset, String.valueOf(l));
+ // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+ // after conversion of l to String by super class method
+ // Ditto for toStringCache clearing
+ super.insert(offset, l);
+ return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuffer insert(int offset, float f) {
- return insert(offset, String.valueOf(f));
+ // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+ // after conversion of f to String by super class method
+ // Ditto for toStringCache clearing
+ super.insert(offset, f);
+ return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuffer insert(int offset, double d) {
- return insert(offset, String.valueOf(d));
+ // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+ // after conversion of d to String by super class method
+ // Ditto for toStringCache clearing
+ super.insert(offset, d);
+ return this;
}
/**
- * @throws NullPointerException {@inheritDoc}
* @since 1.4
*/
+ @Override
public int indexOf(String str) {
- return indexOf(str, 0);
+ // Note, synchronization achieved via invocations of other StringBuffer methods
+ return super.indexOf(str);
}
/**
- * @throws NullPointerException {@inheritDoc}
* @since 1.4
*/
+ @Override
public synchronized int indexOf(String str, int fromIndex) {
- return String.indexOf(value, 0, count,
- str.toCharArray(), 0, str.length(), fromIndex);
+ return super.indexOf(str, fromIndex);
}
/**
- * @throws NullPointerException {@inheritDoc}
* @since 1.4
*/
+ @Override
public int lastIndexOf(String str) {
- // Note, synchronization achieved via other invocations
+ // Note, synchronization achieved via invocations of other StringBuffer methods
return lastIndexOf(str, count);
}
/**
- * @throws NullPointerException {@inheritDoc}
* @since 1.4
*/
+ @Override
public synchronized int lastIndexOf(String str, int fromIndex) {
- return String.lastIndexOf(value, 0, count,
- str.toCharArray(), 0, str.length(), fromIndex);
+ return super.lastIndexOf(str, fromIndex);
}
/**
* @since JDK1.0.2
*/
+ @Override
public synchronized StringBuffer reverse() {
+ toStringCache = null;
super.reverse();
return this;
}
+ @Override
public synchronized String toString() {
- return new String(value, 0, count);
+ if (toStringCache == null) {
+ toStringCache = Arrays.copyOfRange(value, 0, count);
+ }
+ return new String(toStringCache, 0, count);
}
/**
diff --git a/ojluni/src/main/java/java/lang/StringBuilder.java b/ojluni/src/main/java/java/lang/StringBuilder.java
old mode 100755
new mode 100644
index e16522d..42642c7
--- a/ojluni/src/main/java/java/lang/StringBuilder.java
+++ b/ojluni/src/main/java/java/lang/StringBuilder.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,42 +29,46 @@
/**
* A mutable sequence of characters. This class provides an API compatible
- * with <code>StringBuffer</code>, but with no guarantee of synchronization.
+ * with {@code StringBuffer}, but with no guarantee of synchronization.
* This class is designed for use as a drop-in replacement for
- * <code>StringBuffer</code> in places where the string buffer was being
+ * {@code StringBuffer} in places where the string buffer was being
* used by a single thread (as is generally the case). Where possible,
* it is recommended that this class be used in preference to
- * <code>StringBuffer</code> as it will be faster under most implementations.
+ * {@code StringBuffer} as it will be faster under most implementations.
*
- * <p>The principal operations on a <code>StringBuilder</code> are the
- * <code>append</code> and <code>insert</code> methods, which are
+ * <p>The principal operations on a {@code StringBuilder} are the
+ * {@code append} and {@code insert} methods, which are
* overloaded so as to accept data of any type. Each effectively
* converts a given datum to a string and then appends or inserts the
* characters of that string to the string builder. The
- * <code>append</code> method always adds these characters at the end
- * of the builder; the <code>insert</code> method adds the characters at
+ * {@code append} method always adds these characters at the end
+ * of the builder; the {@code insert} method adds the characters at
* a specified point.
* <p>
- * For example, if <code>z</code> refers to a string builder object
- * whose current contents are "<code>start</code>", then
- * the method call <code>z.append("le")</code> would cause the string
- * builder to contain "<code>startle</code>", whereas
- * <code>z.insert(4, "le")</code> would alter the string builder to
- * contain "<code>starlet</code>".
+ * For example, if {@code z} refers to a string builder object
+ * whose current contents are "{@code start}", then
+ * the method call {@code z.append("le")} would cause the string
+ * builder to contain "{@code startle}", whereas
+ * {@code z.insert(4, "le")} would alter the string builder to
+ * contain "{@code starlet}".
* <p>
- * In general, if sb refers to an instance of a <code>StringBuilder</code>,
- * then <code>sb.append(x)</code> has the same effect as
- * <code>sb.insert(sb.length(), x)</code>.
- *
+ * In general, if sb refers to an instance of a {@code StringBuilder},
+ * then {@code sb.append(x)} has the same effect as
+ * {@code sb.insert(sb.length(), x)}.
+ * <p>
* Every string builder has a capacity. As long as the length of the
* character sequence contained in the string builder does not exceed
* the capacity, it is not necessary to allocate a new internal
* buffer. If the internal buffer overflows, it is automatically made larger.
*
- * <p>Instances of <code>StringBuilder</code> are not safe for
+ * <p>Instances of {@code StringBuilder} are not safe for
* use by multiple threads. If such synchronization is required then it is
* recommended that {@link java.lang.StringBuffer} be used.
*
+ * <p>Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
* @author Michael McCloskey
* @see java.lang.StringBuffer
* @see java.lang.String
@@ -72,7 +76,7 @@
*/
public final class StringBuilder
extends AbstractStringBuilder
- implements java.io.Serializable, Appendable, CharSequence
+ implements java.io.Serializable, CharSequence
{
/** use serialVersionUID for interoperability */
@@ -88,11 +92,11 @@
/**
* Constructs a string builder with no characters in it and an
- * initial capacity specified by the <code>capacity</code> argument.
+ * initial capacity specified by the {@code capacity} argument.
*
* @param capacity the initial capacity.
- * @throws NegativeArraySizeException if the <code>capacity</code>
- * argument is less than <code>0</code>.
+ * @throws NegativeArraySizeException if the {@code capacity}
+ * argument is less than {@code 0}.
*/
public StringBuilder(int capacity) {
super(capacity);
@@ -101,10 +105,9 @@
/**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
- * <code>16</code> plus the length of the string argument.
+ * {@code 16} plus the length of the string argument.
*
* @param str the initial contents of the buffer.
- * @throws NullPointerException if <code>str</code> is <code>null</code>
*/
public StringBuilder(String str) {
super(str.length() + 16);
@@ -113,57 +116,45 @@
/**
* Constructs a string builder that contains the same characters
- * as the specified <code>CharSequence</code>. The initial capacity of
- * the string builder is <code>16</code> plus the length of the
- * <code>CharSequence</code> argument.
+ * as the specified {@code CharSequence}. The initial capacity of
+ * the string builder is {@code 16} plus the length of the
+ * {@code CharSequence} argument.
*
* @param seq the sequence to copy.
- * @throws NullPointerException if <code>seq</code> is <code>null</code>
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
+ @Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
+ @Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
- // Appends the specified string builder to this sequence.
- private StringBuilder append(StringBuilder sb) {
- if (sb == null)
- return append("null");
- int len = sb.length();
- int newcount = count + len;
- if (newcount > value.length)
- expandCapacity(newcount);
- sb.getChars(0, len, value, count);
- count = newcount;
- return this;
- }
-
/**
- * Appends the specified <tt>StringBuffer</tt> to this sequence.
+ * Appends the specified {@code StringBuffer} to this sequence.
* <p>
- * The characters of the <tt>StringBuffer</tt> argument are appended,
+ * The characters of the {@code StringBuffer} argument are appended,
* in order, to this sequence, increasing the
* length of this sequence by the length of the argument.
- * If <tt>sb</tt> is <tt>null</tt>, then the four characters
- * <tt>"null"</tt> are appended to this sequence.
+ * If {@code sb} is {@code null}, then the four characters
+ * {@code "null"} are appended to this sequence.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
- * execution of the <tt>append</tt> method. Then the character at index
+ * execution of the {@code append} method. Then the character at index
* <i>k</i> in the new character sequence is equal to the character at
* index <i>k</i> in the old character sequence, if <i>k</i> is less than
* <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i>
- * in the argument <code>sb</code>.
+ * in the argument {@code sb}.
*
- * @param sb the <tt>StringBuffer</tt> to append.
+ * @param sb the {@code StringBuffer} to append.
* @return a reference to this object.
*/
public StringBuilder append(StringBuffer sb) {
@@ -171,28 +162,22 @@
return this;
}
- /**
- */
+ @Override
public StringBuilder append(CharSequence s) {
- if (s == null)
- s = "null";
- if (s instanceof String)
- return this.append((String)s);
- if (s instanceof StringBuffer)
- return this.append((StringBuffer)s);
- if (s instanceof StringBuilder)
- return this.append((StringBuilder)s);
- return this.append(s, 0, s.length());
+ super.append(s);
+ return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
+ @Override
public StringBuilder append(char[] str) {
super.append(str);
return this;
@@ -201,36 +186,43 @@
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
+ @Override
public StringBuilder append(boolean b) {
super.append(b);
return this;
}
+ @Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
+ @Override
public StringBuilder append(int i) {
super.append(i);
return this;
}
+ @Override
public StringBuilder append(long lng) {
super.append(lng);
return this;
}
+ @Override
public StringBuilder append(float f) {
super.append(f);
return this;
}
+ @Override
public StringBuilder append(double d) {
super.append(d);
return this;
@@ -239,6 +231,7 @@
/**
* @since 1.5
*/
+ @Override
public StringBuilder appendCodePoint(int codePoint) {
super.appendCodePoint(codePoint);
return this;
@@ -247,6 +240,7 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
@@ -255,6 +249,7 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder deleteCharAt(int index) {
super.deleteCharAt(index);
return this;
@@ -263,6 +258,7 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder replace(int start, int end, String str) {
super.replace(start, end, str);
return this;
@@ -271,6 +267,7 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int index, char[] str, int offset,
int len)
{
@@ -281,13 +278,16 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, Object obj) {
- return insert(offset, String.valueOf(obj));
+ super.insert(offset, obj);
+ return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);
return this;
@@ -296,6 +296,7 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, char[] str) {
super.insert(offset, str);
return this;
@@ -304,17 +305,16 @@
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int dstOffset, CharSequence s) {
- if (s == null)
- s = "null";
- if (s instanceof String)
- return this.insert(dstOffset, (String)s);
- return this.insert(dstOffset, s, 0, s.length());
+ super.insert(dstOffset, s);
+ return this;
}
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int dstOffset, CharSequence s,
int start, int end)
{
@@ -325,6 +325,7 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, boolean b) {
super.insert(offset, b);
return this;
@@ -333,6 +334,7 @@
/**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, char c) {
super.insert(offset, c);
return this;
@@ -341,66 +343,66 @@
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, int i) {
- return insert(offset, String.valueOf(i));
+ super.insert(offset, i);
+ return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, long l) {
- return insert(offset, String.valueOf(l));
+ super.insert(offset, l);
+ return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, float f) {
- return insert(offset, String.valueOf(f));
+ super.insert(offset, f);
+ return this;
}
/**
* @throws StringIndexOutOfBoundsException {@inheritDoc}
*/
+ @Override
public StringBuilder insert(int offset, double d) {
- return insert(offset, String.valueOf(d));
+ super.insert(offset, d);
+ return this;
}
- /**
- * @throws NullPointerException {@inheritDoc}
- */
+ @Override
public int indexOf(String str) {
- return indexOf(str, 0);
+ return super.indexOf(str);
}
- /**
- * @throws NullPointerException {@inheritDoc}
- */
+ @Override
public int indexOf(String str, int fromIndex) {
- return String.indexOf(value, 0, count,
- str.toCharArray(), 0, str.length(), fromIndex);
+ return super.indexOf(str, fromIndex);
}
- /**
- * @throws NullPointerException {@inheritDoc}
- */
+ @Override
public int lastIndexOf(String str) {
- return lastIndexOf(str, count);
+ return super.lastIndexOf(str);
}
- /**
- * @throws NullPointerException {@inheritDoc}
- */
+ @Override
public int lastIndexOf(String str, int fromIndex) {
- return String.lastIndexOf(value, 0, count,
- str.toCharArray(), 0, str.length(), fromIndex);
+ return super.lastIndexOf(str, fromIndex);
}
+ @Override
public StringBuilder reverse() {
super.reverse();
return this;
}
+ @Override
public String toString() {
if (count == 0) {
return "";
@@ -409,13 +411,13 @@
}
/**
- * Save the state of the <tt>StringBuilder</tt> instance to a stream
+ * Save the state of the {@code StringBuilder} instance to a stream
* (that is, serialize it).
*
* @serialData the number of characters currently stored in the string
- * builder (<tt>int</tt>), followed by the characters in the
- * string builder (<tt>char[]</tt>). The length of the
- * <tt>char</tt> array may be greater than the number of
+ * builder ({@code int}), followed by the characters in the
+ * string builder ({@code char[]}). The length of the
+ * {@code char} array may be greater than the number of
* characters currently stored in the string builder, in which
* case extra characters are ignored.
*/
diff --git a/ojluni/src/main/java/java/lang/annotation/Native.java b/ojluni/src/main/java/java/lang/annotation/Native.java
index 2f2a5a8..861c1ff 100644
--- a/ojluni/src/main/java/java/lang/annotation/Native.java
+++ b/ojluni/src/main/java/java/lang/annotation/Native.java
@@ -35,7 +35,6 @@
* if so, what declarations it should contain.
*
* @since 1.8
- * @hide TODO unhide
*/
@Documented
@Target(ElementType.FIELD)
diff --git a/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java b/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java
index 8311f76..4ecad5b 100755
--- a/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java
+++ b/ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java
@@ -65,6 +65,14 @@
private final static boolean connectDisabled = os.contains("OS X");
/**
+ * Load net library into runtime.
+ * TODO(yikong): Move clinit code to registration function
+ */
+ static {
+ init();
+ }
+
+ /**
* Creates a datagram socket
*/
protected synchronized void create() throws SocketException {
@@ -386,4 +394,7 @@
protected boolean nativeConnectDisabled() {
return connectDisabled;
}
+
+ native int dataAvailable();
+ private static native void init();
}
diff --git a/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java b/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
index 746c19e..330e014 100755
--- a/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
+++ b/ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java
@@ -647,7 +647,3 @@
public final static int SHUT_RD = 0;
public final static int SHUT_WR = 1;
}
-
-class InetAddressContainer {
- InetAddress addr;
-}
diff --git a/ojluni/src/main/java/java/net/DatagramPacket.java b/ojluni/src/main/java/java/net/DatagramPacket.java
index 62001d7..1ce7cad 100755
--- a/ojluni/src/main/java/java/net/DatagramPacket.java
+++ b/ojluni/src/main/java/java/net/DatagramPacket.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -133,8 +133,7 @@
*
* @since 1.4
*/
- public DatagramPacket(byte buf[], int offset, int length,
- SocketAddress address) throws SocketException {
+ public DatagramPacket(byte buf[], int offset, int length, SocketAddress address) {
setData(buf, offset, length);
setSocketAddress(address);
}
@@ -169,8 +168,7 @@
* @since 1.4
* @see java.net.InetAddress
*/
- public DatagramPacket(byte buf[], int length,
- SocketAddress address) throws SocketException {
+ public DatagramPacket(byte buf[], int length, SocketAddress address) {
this(buf, 0, length, address);
}
diff --git a/ojluni/src/main/java/java/net/DatagramSocket.java b/ojluni/src/main/java/java/net/DatagramSocket.java
index 03ecf94..6d43ad0 100755
--- a/ojluni/src/main/java/java/net/DatagramSocket.java
+++ b/ojluni/src/main/java/java/net/DatagramSocket.java
@@ -89,6 +89,17 @@
*/
boolean oldImpl = false;
+ /**
+ * Set when a socket is ST_CONNECTED until we are certain
+ * that any packets which might have been received prior
+ * to calling connect() but not read by the application
+ * have been read. During this time we check the source
+ * address of all packets received to be sure they are from
+ * the connected destination. Other packets are read but
+ * silently dropped.
+ */
+ private boolean explicitFilter = false;
+ private int bytesLeftToFilter;
/*
* Connection state:
* ST_NOT_CONNECTED = socket not connected
@@ -166,6 +177,15 @@
// socket is now connected by the impl
connectState = ST_CONNECTED;
+ // Do we need to filter some packets?
+ int avail = getImpl().dataAvailable();
+ if (avail == -1) {
+ throw new SocketException();
+ }
+ explicitFilter = avail > 0;
+ if (explicitFilter) {
+ bytesLeftToFilter = getReceiveBufferSize();
+ }
// ----- END android -----
}
@@ -512,6 +532,7 @@
connectedAddress = null;
connectedPort = -1;
connectState = ST_NOT_CONNECTED;
+ explicitFilter = false;
}
}
@@ -777,10 +798,12 @@
} // end of while
}
}
- if (connectState == ST_CONNECTED_NO_IMPL) {
+ if ((connectState == ST_CONNECTED_NO_IMPL) || explicitFilter) {
// We have to do the filtering the old fashioned way since
// the native impl doesn't support connect or the connect
- // via the impl failed.
+ // via the impl failed, or .. "explicitFilter" may be set when
+ // a socket is connected via the impl, for a period of time
+ // when packets from other sources might be queued on socket.
boolean stop = false;
while (!stop) {
InetAddress peekAddress = null;
@@ -799,8 +822,12 @@
if ((!connectedAddress.equals(peekAddress)) ||
(connectedPort != peekPort)) {
// throw the packet away and silently continue
- DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
+ DatagramPacket tmp = new DatagramPacket(
+ new byte[1024], 1024);
getImpl().receive(tmp);
+ if (explicitFilter) {
+ bytesLeftToFilter -= tmp.getLength();
+ }
} else {
stop = true;
}
@@ -809,6 +836,15 @@
// If the security check succeeds, or the datagram is
// connected then receive the packet
getImpl().receive(p);
+ if (explicitFilter) {
+ bytesLeftToFilter -= p.getLength();
+ if (bytesLeftToFilter <= 0) {
+ explicitFilter = false;
+ } else {
+ // break out of filter, if there is no more data queued
+ explicitFilter = getImpl().dataAvailable() > 0;
+ }
+ }
}
}
diff --git a/ojluni/src/main/java/java/net/DatagramSocketImpl.java b/ojluni/src/main/java/java/net/DatagramSocketImpl.java
index 0f0bf81..bbabc03 100755
--- a/ojluni/src/main/java/java/net/DatagramSocketImpl.java
+++ b/ojluni/src/main/java/java/net/DatagramSocketImpl.java
@@ -47,6 +47,12 @@
*/
protected FileDescriptor fd;
+ int dataAvailable() {
+ // default impl returns zero, which disables the calling
+ // functionality
+ return 0;
+ }
+
/**
* Creates a datagram socket.
* @exception SocketException if there is an error in the
diff --git a/ojluni/src/main/java/sun/net/www/ApplicationLaunchException.java b/ojluni/src/main/java/java/net/InetAddressContainer.java
old mode 100755
new mode 100644
similarity index 70%
rename from ojluni/src/main/java/sun/net/www/ApplicationLaunchException.java
rename to ojluni/src/main/java/java/net/InetAddressContainer.java
index 3394cd3..28b6402
--- a/ojluni/src/main/java/sun/net/www/ApplicationLaunchException.java
+++ b/ojluni/src/main/java/java/net/InetAddressContainer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,19 +23,8 @@
* questions.
*/
-package sun.net.www;
+package java.net;
-/**
- * An exception thrown by the MimeLauncher when it is unable to launch
- * an external content viewer.
- *
- * @author Sunita Mani
- */
-
-public class ApplicationLaunchException extends Exception {
- private static final long serialVersionUID = -4782286141289536883L;
-
- public ApplicationLaunchException(String reason) {
- super(reason);
- }
+class InetAddressContainer {
+ InetAddress addr;
}
diff --git a/ojluni/src/main/java/java/net/URL.java b/ojluni/src/main/java/java/net/URL.java
index 8af827c..15d09d1 100755
--- a/ojluni/src/main/java/java/net/URL.java
+++ b/ojluni/src/main/java/java/net/URL.java
@@ -1193,15 +1193,15 @@
// Makes okhttp the default http/https handler
if (handler == null) {
try {
+ // BEGIN android-changed
+ // Use of okhttp for http and https
+ // Removed unnecessary use of reflection for sun classes
if (protocol.equals("file")) {
- handler = (URLStreamHandler)Class.
- forName("sun.net.www.protocol.file.Handler").newInstance();
+ handler = new sun.net.www.protocol.file.Handler();
} else if (protocol.equals("ftp")) {
- handler = (URLStreamHandler)Class.
- forName("sun.net.www.protocol.ftp.Handler").newInstance();
+ handler = new sun.net.www.protocol.ftp.Handler();
} else if (protocol.equals("jar")) {
- handler = (URLStreamHandler)Class.
- forName("sun.net.www.protocol.jar.Handler").newInstance();
+ handler = new sun.net.www.protocol.jar.Handler();
} else if (protocol.equals("http")) {
handler = (URLStreamHandler)Class.
forName("com.android.okhttp.HttpHandler").newInstance();
@@ -1209,6 +1209,7 @@
handler = (URLStreamHandler)Class.
forName("com.android.okhttp.HttpsHandler").newInstance();
}
+ // END android-changed
} catch (Exception e) {
throw new AssertionError(e);
}
diff --git a/ojluni/src/main/java/java/text/RuleBasedCollator.java b/ojluni/src/main/java/java/text/RuleBasedCollator.java
index c54de11..3c82624 100755
--- a/ojluni/src/main/java/java/text/RuleBasedCollator.java
+++ b/ojluni/src/main/java/java/text/RuleBasedCollator.java
@@ -307,6 +307,9 @@
/**
* Gets the table-based rules for the collation object.
*
+ * <p>On Android, the returned string will be empty unless this instance was
+ * constructed using {@link #RuleBasedCollator(String)}.
+ *
* @return returns the collation rules that the table collation object
* was created from.
*/
diff --git a/ojluni/src/main/java/java/util/Formatter.java b/ojluni/src/main/java/java/util/Formatter.java
index 9a4e234..ebfdd2d 100755
--- a/ojluni/src/main/java/java/util/Formatter.java
+++ b/ojluni/src/main/java/java/util/Formatter.java
@@ -3299,13 +3299,10 @@
int prec = (precision == -1 ? 6 : precision);
FormattedFloatingDecimal fd
- = new FormattedFloatingDecimal(value, prec,
+ = FormattedFloatingDecimal.valueOf(value, prec,
FormattedFloatingDecimal.Form.SCIENTIFIC);
- char[] v = new char[MAX_FD_CHARS];
- int len = fd.getChars(v);
-
- char[] mant = addZeros(mantissa(v, len), prec);
+ char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
@@ -3313,7 +3310,7 @@
mant = addDot(mant);
char[] exp = (value == 0.0)
- ? new char[] {'+','0','0'} : exponent(v, len);
+ ? new char[] {'+','0','0'} : fd.getExponent();
int newW = width;
if (width != -1)
@@ -3340,15 +3337,10 @@
int prec = (precision == -1 ? 6 : precision);
FormattedFloatingDecimal fd
- = new FormattedFloatingDecimal(value, prec,
- FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
+ = FormattedFloatingDecimal.valueOf(value, prec,
+ FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
- // MAX_FD_CHARS + 1 (round?)
- char[] v = new char[MAX_FD_CHARS + 1
- + Math.abs(fd.getExponent())];
- int len = fd.getChars(v);
-
- char[] mant = addZeros(mantissa(v, len), prec);
+ char[] mant = addZeros(fd.getMantissa(), prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
@@ -3366,23 +3358,29 @@
else if (precision == 0)
prec = 1;
- FormattedFloatingDecimal fd
- = new FormattedFloatingDecimal(value, prec,
- FormattedFloatingDecimal.Form.GENERAL);
+ char[] exp;
+ char[] mant;
+ int expRounded;
+ if (value == 0.0) {
+ exp = null;
+ mant = new char[] {'0'};
+ expRounded = 0;
+ } else {
+ FormattedFloatingDecimal fd
+ = FormattedFloatingDecimal.valueOf(value, prec,
+ FormattedFloatingDecimal.Form.GENERAL);
+ exp = fd.getExponent();
+ mant = fd.getMantissa();
+ expRounded = fd.getExponentRounded();
+ }
- // MAX_FD_CHARS + 1 (round?)
- char[] v = new char[MAX_FD_CHARS + 1
- + Math.abs(fd.getExponent())];
- int len = fd.getChars(v);
-
- char[] exp = exponent(v, len);
if (exp != null) {
prec -= 1;
} else {
- prec = prec - (value == 0 ? 0 : fd.getExponentRounded()) - 1;
+ prec -= expRounded + 1;
}
- char[] mant = addZeros(mantissa(v, len), prec);
+ mant = addZeros(mant, prec);
// If the precision is zero and the '#' flag is set, add the
// requested decimal point.
if (f.contains(Flags.ALTERNATE) && (prec == 0))
diff --git a/ojluni/src/main/java/java/util/stream/ReferencePipeline.java b/ojluni/src/main/java/java/util/stream/ReferencePipeline.java
index 8957ee5..ddec43e 100644
--- a/ojluni/src/main/java/java/util/stream/ReferencePipeline.java
+++ b/ojluni/src/main/java/java/util/stream/ReferencePipeline.java
@@ -436,8 +436,9 @@
// super type of U an ArrayStoreException will be thrown.
@SuppressWarnings("rawtypes")
IntFunction rawGenerator = (IntFunction) generator;
- return (A[]) Nodes.flatten(evaluateToArrayNode(rawGenerator), rawGenerator)
- .asArray(rawGenerator);
+ // TODO(b/29399275): Eclipse compiler requires explicit (Node<A[]>) cast below.
+ return (A[]) Nodes.flatten((Node<A[]>) evaluateToArrayNode(rawGenerator), rawGenerator)
+ .asArray(rawGenerator);
}
@Override
diff --git a/ojluni/src/main/java/sun/misc/FDBigInteger.java b/ojluni/src/main/java/sun/misc/FDBigInteger.java
new file mode 100644
index 0000000..77d6fbc
--- /dev/null
+++ b/ojluni/src/main/java/sun/misc/FDBigInteger.java
@@ -0,0 +1,1508 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.misc;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+//@ model import org.jmlspecs.models.JMLMath;
+
+/**
+ * A simple big integer package specifically for floating point base conversion.
+ */
+public /*@ spec_bigint_math @*/ class FDBigInteger {
+
+ //
+ // This class contains many comments that start with "/*@" mark.
+ // They are behavourial specification in
+ // the Java Modelling Language (JML):
+ // http://www.eecs.ucf.edu/~leavens/JML//index.shtml
+ //
+
+ /*@
+ @ public pure model static \bigint UNSIGNED(int v) {
+ @ return v >= 0 ? v : v + (((\bigint)1) << 32);
+ @ }
+ @
+ @ public pure model static \bigint UNSIGNED(long v) {
+ @ return v >= 0 ? v : v + (((\bigint)1) << 64);
+ @ }
+ @
+ @ public pure model static \bigint AP(int[] data, int len) {
+ @ return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32));
+ @ }
+ @
+ @ public pure model static \bigint pow52(int p5, int p2) {
+ @ ghost \bigint v = 1;
+ @ for (int i = 0; i < p5; i++) v *= 5;
+ @ return v << p2;
+ @ }
+ @
+ @ public pure model static \bigint pow10(int p10) {
+ @ return pow52(p10, p10);
+ @ }
+ @*/
+
+ static final int[] SMALL_5_POW = {
+ 1,
+ 5,
+ 5 * 5,
+ 5 * 5 * 5,
+ 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+ };
+
+ static final long[] LONG_5_POW = {
+ 1L,
+ 5L,
+ 5L * 5,
+ 5L * 5 * 5,
+ 5L * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ };
+
+ // Maximum size of cache of powers of 5 as FDBigIntegers.
+ private static final int MAX_FIVE_POW = 340;
+
+ // Cache of big powers of 5 as FDBigIntegers.
+ private static final FDBigInteger POW_5_CACHE[];
+
+ // Initialize FDBigInteger cache of powers of 5.
+ static {
+ POW_5_CACHE = new FDBigInteger[MAX_FIVE_POW];
+ int i = 0;
+ while (i < SMALL_5_POW.length) {
+ FDBigInteger pow5 = new FDBigInteger(new int[]{SMALL_5_POW[i]}, 0);
+ pow5.makeImmutable();
+ POW_5_CACHE[i] = pow5;
+ i++;
+ }
+ FDBigInteger prev = POW_5_CACHE[i - 1];
+ while (i < MAX_FIVE_POW) {
+ POW_5_CACHE[i] = prev = prev.mult(5);
+ prev.makeImmutable();
+ i++;
+ }
+ }
+
+ // Zero as an FDBigInteger.
+ public static final FDBigInteger ZERO = new FDBigInteger(new int[0], 0);
+
+ // Ensure ZERO is immutable.
+ static {
+ ZERO.makeImmutable();
+ }
+
+ // Constant for casting an int to a long via bitwise AND.
+ private final static long LONG_MASK = 0xffffffffL;
+
+ //@ spec_public non_null;
+ private int data[]; // value: data[0] is least significant
+ //@ spec_public;
+ private int offset; // number of least significant zero padding ints
+ //@ spec_public;
+ private int nWords; // data[nWords-1]!=0, all values above are zero
+ // if nWords==0 -> this FDBigInteger is zero
+ //@ spec_public;
+ private boolean isImmutable = false;
+
+ /*@
+ @ public invariant 0 <= nWords && nWords <= data.length && offset >= 0;
+ @ public invariant nWords == 0 ==> offset == 0;
+ @ public invariant nWords > 0 ==> data[nWords - 1] != 0;
+ @ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0);
+ @ public pure model \bigint value() {
+ @ return AP(data, nWords) << (offset*32);
+ @ }
+ @*/
+
+ /**
+ * Constructs an <code>FDBigInteger</code> from data and padding. The
+ * <code>data</code> parameter has the least significant <code>int</code> at
+ * the zeroth index. The <code>offset</code> parameter gives the number of
+ * zero <code>int</code>s to be inferred below the least significant element
+ * of <code>data</code>.
+ *
+ * @param data An array containing all non-zero <code>int</code>s of the value.
+ * @param offset An offset indicating the number of zero <code>int</code>s to pad
+ * below the least significant element of <code>data</code>.
+ */
+ /*@
+ @ requires data != null && offset >= 0;
+ @ ensures this.value() == \old(AP(data, data.length) << (offset*32));
+ @ ensures this.data == \old(data);
+ @*/
+ private FDBigInteger(int[] data, int offset) {
+ this.data = data;
+ this.offset = offset;
+ this.nWords = data.length;
+ trimLeadingZeros();
+ }
+
+ /**
+ * Constructs an <code>FDBigInteger</code> from a starting value and some
+ * decimal digits.
+ *
+ * @param lValue The starting value.
+ * @param digits The decimal digits.
+ * @param kDigits The initial index into <code>digits</code>.
+ * @param nDigits The final index into <code>digits</code>.
+ */
+ /*@
+ @ requires digits != null;
+ @ requires 0 <= kDigits && kDigits <= nDigits && nDigits <= digits.length;
+ @ requires (\forall int i; 0 <= i && i < nDigits; '0' <= digits[i] && digits[i] <= '9');
+ @ ensures this.value() == \old(lValue * pow10(nDigits - kDigits) + (\sum int i; kDigits <= i && i < nDigits; (digits[i] - '0') * pow10(nDigits - i - 1)));
+ @*/
+ public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) {
+ int n = Math.max((nDigits + 8) / 9, 2); // estimate size needed.
+ data = new int[n]; // allocate enough space
+ data[0] = (int) lValue; // starting value
+ data[1] = (int) (lValue >>> 32);
+ offset = 0;
+ nWords = 2;
+ int i = kDigits;
+ int limit = nDigits - 5; // slurp digits 5 at a time.
+ int v;
+ while (i < limit) {
+ int ilim = i + 5;
+ v = (int) digits[i++] - (int) '0';
+ while (i < ilim) {
+ v = 10 * v + (int) digits[i++] - (int) '0';
+ }
+ multAddMe(100000, v); // ... where 100000 is 10^5.
+ }
+ int factor = 1;
+ v = 0;
+ while (i < nDigits) {
+ v = 10 * v + (int) digits[i++] - (int) '0';
+ factor *= 10;
+ }
+ if (factor != 1) {
+ multAddMe(factor, v);
+ }
+ trimLeadingZeros();
+ }
+
+ /**
+ * Returns an <code>FDBigInteger</code> with the numerical value
+ * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>.
+ *
+ * @param p5 The exponent of the power-of-five factor.
+ * @param p2 The exponent of the power-of-two factor.
+ * @return <code>5<sup>p5</sup> * 2<sup>p2</sup></code>
+ */
+ /*@
+ @ requires p5 >= 0 && p2 >= 0;
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(pow52(p5, p2));
+ @*/
+ public static FDBigInteger valueOfPow52(int p5, int p2) {
+ if (p5 != 0) {
+ if (p2 == 0) {
+ return big5pow(p5);
+ } else if (p5 < SMALL_5_POW.length) {
+ int pow5 = SMALL_5_POW[p5];
+ int wordcount = p2 >> 5;
+ int bitcount = p2 & 0x1f;
+ if (bitcount == 0) {
+ return new FDBigInteger(new int[]{pow5}, wordcount);
+ } else {
+ return new FDBigInteger(new int[]{
+ pow5 << bitcount,
+ pow5 >>> (32 - bitcount)
+ }, wordcount);
+ }
+ } else {
+ return big5pow(p5).leftShift(p2);
+ }
+ } else {
+ return valueOfPow2(p2);
+ }
+ }
+
+ /**
+ * Returns an <code>FDBigInteger</code> with the numerical value
+ * <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>.
+ *
+ * @param value The constant factor.
+ * @param p5 The exponent of the power-of-five factor.
+ * @param p2 The exponent of the power-of-two factor.
+ * @return <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>
+ */
+ /*@
+ @ requires p5 >= 0 && p2 >= 0;
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(UNSIGNED(value) * pow52(p5, p2));
+ @*/
+ public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) {
+ assert p5 >= 0 : p5;
+ assert p2 >= 0 : p2;
+ int v0 = (int) value;
+ int v1 = (int) (value >>> 32);
+ int wordcount = p2 >> 5;
+ int bitcount = p2 & 0x1f;
+ if (p5 != 0) {
+ if (p5 < SMALL_5_POW.length) {
+ long pow5 = SMALL_5_POW[p5] & LONG_MASK;
+ long carry = (v0 & LONG_MASK) * pow5;
+ v0 = (int) carry;
+ carry >>>= 32;
+ carry = (v1 & LONG_MASK) * pow5 + carry;
+ v1 = (int) carry;
+ int v2 = (int) (carry >>> 32);
+ if (bitcount == 0) {
+ return new FDBigInteger(new int[]{v0, v1, v2}, wordcount);
+ } else {
+ return new FDBigInteger(new int[]{
+ v0 << bitcount,
+ (v1 << bitcount) | (v0 >>> (32 - bitcount)),
+ (v2 << bitcount) | (v1 >>> (32 - bitcount)),
+ v2 >>> (32 - bitcount)
+ }, wordcount);
+ }
+ } else {
+ FDBigInteger pow5 = big5pow(p5);
+ int[] r;
+ if (v1 == 0) {
+ r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)];
+ mult(pow5.data, pow5.nWords, v0, r);
+ } else {
+ r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)];
+ mult(pow5.data, pow5.nWords, v0, v1, r);
+ }
+ return (new FDBigInteger(r, pow5.offset)).leftShift(p2);
+ }
+ } else if (p2 != 0) {
+ if (bitcount == 0) {
+ return new FDBigInteger(new int[]{v0, v1}, wordcount);
+ } else {
+ return new FDBigInteger(new int[]{
+ v0 << bitcount,
+ (v1 << bitcount) | (v0 >>> (32 - bitcount)),
+ v1 >>> (32 - bitcount)
+ }, wordcount);
+ }
+ }
+ return new FDBigInteger(new int[]{v0, v1}, 0);
+ }
+
+ /**
+ * Returns an <code>FDBigInteger</code> with the numerical value
+ * <code>2<sup>p2</sup></code>.
+ *
+ * @param p2 The exponent of 2.
+ * @return <code>2<sup>p2</sup></code>
+ */
+ /*@
+ @ requires p2 >= 0;
+ @ assignable \nothing;
+ @ ensures \result.value() == pow52(0, p2);
+ @*/
+ private static FDBigInteger valueOfPow2(int p2) {
+ int wordcount = p2 >> 5;
+ int bitcount = p2 & 0x1f;
+ return new FDBigInteger(new int[]{1 << bitcount}, wordcount);
+ }
+
+ /**
+ * Removes all leading zeros from this <code>FDBigInteger</code> adjusting
+ * the offset and number of non-zero leading words accordingly.
+ */
+ /*@
+ @ requires data != null;
+ @ requires 0 <= nWords && nWords <= data.length && offset >= 0;
+ @ requires nWords == 0 ==> offset == 0;
+ @ ensures nWords == 0 ==> offset == 0;
+ @ ensures nWords > 0 ==> data[nWords - 1] != 0;
+ @*/
+ private /*@ helper @*/ void trimLeadingZeros() {
+ int i = nWords;
+ if (i > 0 && (data[--i] == 0)) {
+ //for (; i > 0 && data[i - 1] == 0; i--) ;
+ while(i > 0 && data[i - 1] == 0) {
+ i--;
+ }
+ this.nWords = i;
+ if (i == 0) { // all words are zero
+ this.offset = 0;
+ }
+ }
+ }
+
+ /**
+ * Retrieves the normalization bias of the <code>FDBigIntger</code>. The
+ * normalization bias is a left shift such that after it the highest word
+ * of the value will have the 4 highest bits equal to zero:
+ * <code>(highestWord & 0xf0000000) == 0</code>, but the next bit should be 1
+ * <code>(highestWord & 0x08000000) != 0</code>.
+ *
+ * @return The normalization bias.
+ */
+ /*@
+ @ requires this.value() > 0;
+ @*/
+ public /*@ pure @*/ int getNormalizationBias() {
+ if (nWords == 0) {
+ throw new IllegalArgumentException("Zero value cannot be normalized");
+ }
+ int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]);
+ return (zeros < 4) ? 28 + zeros : zeros - 4;
+ }
+
+ // TODO: Why is anticount param needed if it is always 32 - bitcount?
+ /**
+ * Left shifts the contents of one int array into another.
+ *
+ * @param src The source array.
+ * @param idx The initial index of the source array.
+ * @param result The destination array.
+ * @param bitcount The left shift.
+ * @param anticount The left anti-shift, e.g., <code>32-bitcount</code>.
+ * @param prev The prior source value.
+ */
+ /*@
+ @ requires 0 < bitcount && bitcount < 32 && anticount == 32 - bitcount;
+ @ requires src.length >= idx && result.length > idx;
+ @ assignable result[*];
+ @ ensures AP(result, \old(idx + 1)) == \old((AP(src, idx) + UNSIGNED(prev) << (idx*32)) << bitcount);
+ @*/
+ private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){
+ for (; idx > 0; idx--) {
+ int v = (prev << bitcount);
+ prev = src[idx - 1];
+ v |= (prev >>> anticount);
+ result[idx] = v;
+ }
+ int v = prev << bitcount;
+ result[0] = v;
+ }
+
+ /**
+ * Shifts this <code>FDBigInteger</code> to the left. The shift is performed
+ * in-place unless the <code>FDBigInteger</code> is immutable in which case
+ * a new instance of <code>FDBigInteger</code> is returned.
+ *
+ * @param shift The number of bits to shift left.
+ * @return The shifted <code>FDBigInteger</code>.
+ */
+ /*@
+ @ requires this.value() == 0 || shift == 0;
+ @ assignable \nothing;
+ @ ensures \result == this;
+ @
+ @ also
+ @
+ @ requires this.value() > 0 && shift > 0 && this.isImmutable;
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() << shift);
+ @
+ @ also
+ @
+ @ requires this.value() > 0 && shift > 0 && this.isImmutable;
+ @ assignable \nothing;
+ @ ensures \result == this;
+ @ ensures \result.value() == \old(this.value() << shift);
+ @*/
+ public FDBigInteger leftShift(int shift) {
+ if (shift == 0 || nWords == 0) {
+ return this;
+ }
+ int wordcount = shift >> 5;
+ int bitcount = shift & 0x1f;
+ if (this.isImmutable) {
+ if (bitcount == 0) {
+ return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount);
+ } else {
+ int anticount = 32 - bitcount;
+ int idx = nWords - 1;
+ int prev = data[idx];
+ int hi = prev >>> anticount;
+ int[] result;
+ if (hi != 0) {
+ result = new int[nWords + 1];
+ result[nWords] = hi;
+ } else {
+ result = new int[nWords];
+ }
+ leftShift(data,idx,result,bitcount,anticount,prev);
+ return new FDBigInteger(result, offset + wordcount);
+ }
+ } else {
+ if (bitcount != 0) {
+ int anticount = 32 - bitcount;
+ if ((data[0] << bitcount) == 0) {
+ int idx = 0;
+ int prev = data[idx];
+ for (; idx < nWords - 1; idx++) {
+ int v = (prev >>> anticount);
+ prev = data[idx + 1];
+ v |= (prev << bitcount);
+ data[idx] = v;
+ }
+ int v = prev >>> anticount;
+ data[idx] = v;
+ if(v==0) {
+ nWords--;
+ }
+ offset++;
+ } else {
+ int idx = nWords - 1;
+ int prev = data[idx];
+ int hi = prev >>> anticount;
+ int[] result = data;
+ int[] src = data;
+ if (hi != 0) {
+ if(nWords == data.length) {
+ data = result = new int[nWords + 1];
+ }
+ result[nWords++] = hi;
+ }
+ leftShift(src,idx,result,bitcount,anticount,prev);
+ }
+ }
+ offset += wordcount;
+ return this;
+ }
+ }
+
+ /**
+ * Returns the number of <code>int</code>s this <code>FDBigInteger</code> represents.
+ *
+ * @return Number of <code>int</code>s required to represent this <code>FDBigInteger</code>.
+ */
+ /*@
+ @ requires this.value() == 0;
+ @ ensures \result == 0;
+ @
+ @ also
+ @
+ @ requires this.value() > 0;
+ @ ensures ((\bigint)1) << (\result - 1) <= this.value() && this.value() <= ((\bigint)1) << \result;
+ @*/
+ private /*@ pure @*/ int size() {
+ return nWords + offset;
+ }
+
+
+ /**
+ * Computes
+ * <pre>
+ * q = (int)( this / S )
+ * this = 10 * ( this mod S )
+ * Return q.
+ * </pre>
+ * This is the iteration step of digit development for output.
+ * We assume that S has been normalized, as above, and that
+ * "this" has been left-shifted accordingly.
+ * Also assumed, of course, is that the result, q, can be expressed
+ * as an integer, 0 <= q < 10.
+ *
+ * @param The divisor of this <code>FDBigInteger</code>.
+ * @return <code>q = (int)(this / S)</code>.
+ */
+ /*@
+ @ requires !this.isImmutable;
+ @ requires this.size() <= S.size();
+ @ requires this.data.length + this.offset >= S.size();
+ @ requires S.value() >= ((\bigint)1) << (S.size()*32 - 4);
+ @ assignable this.nWords, this.offset, this.data, this.data[*];
+ @ ensures \result == \old(this.value() / S.value());
+ @ ensures this.value() == \old(10 * (this.value() % S.value()));
+ @*/
+ public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException {
+ assert !this.isImmutable : "cannot modify immutable value";
+ // ensure that this and S have the same number of
+ // digits. If S is properly normalized and q < 10 then
+ // this must be so.
+ int thSize = this.size();
+ int sSize = S.size();
+ if (thSize < sSize) {
+ // this value is significantly less than S, result of division is zero.
+ // just mult this by 10.
+ int p = multAndCarryBy10(this.data, this.nWords, this.data);
+ if(p!=0) {
+ this.data[nWords++] = p;
+ } else {
+ trimLeadingZeros();
+ }
+ return 0;
+ } else if (thSize > sSize) {
+ throw new IllegalArgumentException("disparate values");
+ }
+ // estimate q the obvious way. We will usually be
+ // right. If not, then we're only off by a little and
+ // will re-add.
+ long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK);
+ long diff = multDiffMe(q, S);
+ if (diff != 0L) {
+ //@ assert q != 0;
+ //@ assert this.offset == \old(Math.min(this.offset, S.offset));
+ //@ assert this.offset <= S.offset;
+
+ // q is too big.
+ // add S back in until this turns +. This should
+ // not be very many times!
+ long sum = 0L;
+ int tStart = S.offset - this.offset;
+ //@ assert tStart >= 0;
+ int[] sd = S.data;
+ int[] td = this.data;
+ while (sum == 0L) {
+ for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) {
+ sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK);
+ td[tIndex] = (int) sum;
+ sum >>>= 32; // Signed or unsigned, answer is 0 or 1
+ }
+ //
+ // Originally the following line read
+ // "if ( sum !=0 && sum != -1 )"
+ // but that would be wrong, because of the
+ // treatment of the two values as entirely unsigned,
+ // it would be impossible for a carry-out to be interpreted
+ // as -1 -- it would have to be a single-bit carry-out, or +1.
+ //
+ assert sum == 0 || sum == 1 : sum; // carry out of division correction
+ q -= 1;
+ }
+ }
+ // finally, we can multiply this by 10.
+ // it cannot overflow, right, as the high-order word has
+ // at least 4 high-order zeros!
+ int p = multAndCarryBy10(this.data, this.nWords, this.data);
+ assert p == 0 : p; // Carry out of *10
+ trimLeadingZeros();
+ return (int) q;
+ }
+
+ /**
+ * Multiplies this <code>FDBigInteger</code> by 10. The operation will be
+ * performed in place unless the <code>FDBigInteger</code> is immutable in
+ * which case a new <code>FDBigInteger</code> will be returned.
+ *
+ * @return The <code>FDBigInteger</code> multiplied by 10.
+ */
+ /*@
+ @ requires this.value() == 0;
+ @ assignable \nothing;
+ @ ensures \result == this;
+ @
+ @ also
+ @
+ @ requires this.value() > 0 && this.isImmutable;
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() * 10);
+ @
+ @ also
+ @
+ @ requires this.value() > 0 && !this.isImmutable;
+ @ assignable this.nWords, this.data, this.data[*];
+ @ ensures \result == this;
+ @ ensures \result.value() == \old(this.value() * 10);
+ @*/
+ public FDBigInteger multBy10() {
+ if (nWords == 0) {
+ return this;
+ }
+ if (isImmutable) {
+ int[] res = new int[nWords + 1];
+ res[nWords] = multAndCarryBy10(data, nWords, res);
+ return new FDBigInteger(res, offset);
+ } else {
+ int p = multAndCarryBy10(this.data, this.nWords, this.data);
+ if (p != 0) {
+ if (nWords == data.length) {
+ if (data[0] == 0) {
+ System.arraycopy(data, 1, data, 0, --nWords);
+ offset++;
+ } else {
+ data = Arrays.copyOf(data, data.length + 1);
+ }
+ }
+ data[nWords++] = p;
+ } else {
+ trimLeadingZeros();
+ }
+ return this;
+ }
+ }
+
+ /**
+ * Multiplies this <code>FDBigInteger</code> by
+ * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. The operation will be
+ * performed in place if possible, otherwise a new <code>FDBigInteger</code>
+ * will be returned.
+ *
+ * @param p5 The exponent of the power-of-five factor.
+ * @param p2 The exponent of the power-of-two factor.
+ * @return
+ */
+ /*@
+ @ requires this.value() == 0 || p5 == 0 && p2 == 0;
+ @ assignable \nothing;
+ @ ensures \result == this;
+ @
+ @ also
+ @
+ @ requires this.value() > 0 && (p5 > 0 && p2 >= 0 || p5 == 0 && p2 > 0 && this.isImmutable);
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() * pow52(p5, p2));
+ @
+ @ also
+ @
+ @ requires this.value() > 0 && p5 == 0 && p2 > 0 && !this.isImmutable;
+ @ assignable this.nWords, this.data, this.data[*];
+ @ ensures \result == this;
+ @ ensures \result.value() == \old(this.value() * pow52(p5, p2));
+ @*/
+ public FDBigInteger multByPow52(int p5, int p2) {
+ if (this.nWords == 0) {
+ return this;
+ }
+ FDBigInteger res = this;
+ if (p5 != 0) {
+ int[] r;
+ int extraSize = (p2 != 0) ? 1 : 0;
+ if (p5 < SMALL_5_POW.length) {
+ r = new int[this.nWords + 1 + extraSize];
+ mult(this.data, this.nWords, SMALL_5_POW[p5], r);
+ res = new FDBigInteger(r, this.offset);
+ } else {
+ FDBigInteger pow5 = big5pow(p5);
+ r = new int[this.nWords + pow5.size() + extraSize];
+ mult(this.data, this.nWords, pow5.data, pow5.nWords, r);
+ res = new FDBigInteger(r, this.offset + pow5.offset);
+ }
+ }
+ return res.leftShift(p2);
+ }
+
+ /**
+ * Multiplies two big integers represented as int arrays.
+ *
+ * @param s1 The first array factor.
+ * @param s1Len The number of elements of <code>s1</code> to use.
+ * @param s2 The second array factor.
+ * @param s2Len The number of elements of <code>s2</code> to use.
+ * @param dst The product array.
+ */
+ /*@
+ @ requires s1 != dst && s2 != dst;
+ @ requires s1.length >= s1Len && s2.length >= s2Len && dst.length >= s1Len + s2Len;
+ @ assignable dst[0 .. s1Len + s2Len - 1];
+ @ ensures AP(dst, s1Len + s2Len) == \old(AP(s1, s1Len) * AP(s2, s2Len));
+ @*/
+ private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) {
+ for (int i = 0; i < s1Len; i++) {
+ long v = s1[i] & LONG_MASK;
+ long p = 0L;
+ for (int j = 0; j < s2Len; j++) {
+ p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK);
+ dst[i + j] = (int) p;
+ p >>>= 32;
+ }
+ dst[i + s2Len] = (int) p;
+ }
+ }
+
+ /**
+ * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this
+ * <code>FDBigInteger</code>. Assert that the result is positive.
+ * If the subtrahend is immutable, store the result in this(minuend).
+ * If this(minuend) is immutable a new <code>FDBigInteger</code> is created.
+ *
+ * @param subtrahend The <code>FDBigInteger</code> to be subtracted.
+ * @return This <code>FDBigInteger</code> less the subtrahend.
+ */
+ /*@
+ @ requires this.isImmutable;
+ @ requires this.value() >= subtrahend.value();
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() - subtrahend.value());
+ @
+ @ also
+ @
+ @ requires !subtrahend.isImmutable;
+ @ requires this.value() >= subtrahend.value();
+ @ assignable this.nWords, this.offset, this.data, this.data[*];
+ @ ensures \result == this;
+ @ ensures \result.value() == \old(this.value() - subtrahend.value());
+ @*/
+ public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) {
+ assert this.size() >= subtrahend.size() : "result should be positive";
+ FDBigInteger minuend;
+ if (this.isImmutable) {
+ minuend = new FDBigInteger(this.data.clone(), this.offset);
+ } else {
+ minuend = this;
+ }
+ int offsetDiff = subtrahend.offset - minuend.offset;
+ int[] sData = subtrahend.data;
+ int[] mData = minuend.data;
+ int subLen = subtrahend.nWords;
+ int minLen = minuend.nWords;
+ if (offsetDiff < 0) {
+ // need to expand minuend
+ int rLen = minLen - offsetDiff;
+ if (rLen < mData.length) {
+ System.arraycopy(mData, 0, mData, -offsetDiff, minLen);
+ Arrays.fill(mData, 0, -offsetDiff, 0);
+ } else {
+ int[] r = new int[rLen];
+ System.arraycopy(mData, 0, r, -offsetDiff, minLen);
+ minuend.data = mData = r;
+ }
+ minuend.offset = subtrahend.offset;
+ minuend.nWords = minLen = rLen;
+ offsetDiff = 0;
+ }
+ long borrow = 0L;
+ int mIndex = offsetDiff;
+ for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) {
+ long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow;
+ mData[mIndex] = (int) diff;
+ borrow = diff >> 32; // signed shift
+ }
+ for (; borrow != 0 && mIndex < minLen; mIndex++) {
+ long diff = (mData[mIndex] & LONG_MASK) + borrow;
+ mData[mIndex] = (int) diff;
+ borrow = diff >> 32; // signed shift
+ }
+ assert borrow == 0L : borrow; // borrow out of subtract,
+ // result should be positive
+ minuend.trimLeadingZeros();
+ return minuend;
+ }
+
+ /**
+ * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this
+ * <code>FDBigInteger</code>. Assert that the result is positive.
+ * If the this(minuend) is immutable, store the result in subtrahend.
+ * If subtrahend is immutable a new <code>FDBigInteger</code> is created.
+ *
+ * @param subtrahend The <code>FDBigInteger</code> to be subtracted.
+ * @return This <code>FDBigInteger</code> less the subtrahend.
+ */
+ /*@
+ @ requires subtrahend.isImmutable;
+ @ requires this.value() >= subtrahend.value();
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() - subtrahend.value());
+ @
+ @ also
+ @
+ @ requires !subtrahend.isImmutable;
+ @ requires this.value() >= subtrahend.value();
+ @ assignable subtrahend.nWords, subtrahend.offset, subtrahend.data, subtrahend.data[*];
+ @ ensures \result == subtrahend;
+ @ ensures \result.value() == \old(this.value() - subtrahend.value());
+ @*/
+ public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) {
+ assert this.size() >= subtrahend.size() : "result should be positive";
+ FDBigInteger minuend = this;
+ if (subtrahend.isImmutable) {
+ subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset);
+ }
+ int offsetDiff = minuend.offset - subtrahend.offset;
+ int[] sData = subtrahend.data;
+ int[] mData = minuend.data;
+ int subLen = subtrahend.nWords;
+ int minLen = minuend.nWords;
+ if (offsetDiff < 0) {
+ int rLen = minLen;
+ if (rLen < sData.length) {
+ System.arraycopy(sData, 0, sData, -offsetDiff, subLen);
+ Arrays.fill(sData, 0, -offsetDiff, 0);
+ } else {
+ int[] r = new int[rLen];
+ System.arraycopy(sData, 0, r, -offsetDiff, subLen);
+ subtrahend.data = sData = r;
+ }
+ subtrahend.offset = minuend.offset;
+ subLen -= offsetDiff;
+ offsetDiff = 0;
+ } else {
+ int rLen = minLen + offsetDiff;
+ if (rLen >= sData.length) {
+ subtrahend.data = sData = Arrays.copyOf(sData, rLen);
+ }
+ }
+ //@ assert minuend == this && minuend.value() == \old(this.value());
+ //@ assert mData == minuend.data && minLen == minuend.nWords;
+ //@ assert subtrahend.offset + subtrahend.data.length >= minuend.size();
+ //@ assert sData == subtrahend.data;
+ //@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value());
+ //@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset);
+ //@ assert offsetDiff == minuend.offset - subtrahend.offset;
+ //@ assert 0 <= offsetDiff && offsetDiff + minLen <= sData.length;
+ int sIndex = 0;
+ long borrow = 0L;
+ for (; sIndex < offsetDiff; sIndex++) {
+ long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow;
+ sData[sIndex] = (int) diff;
+ borrow = diff >> 32; // signed shift
+ }
+ //@ assert sIndex == offsetDiff;
+ for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) {
+ //@ assert sIndex == offsetDiff + mIndex;
+ long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow;
+ sData[sIndex] = (int) diff;
+ borrow = diff >> 32; // signed shift
+ }
+ assert borrow == 0L : borrow; // borrow out of subtract,
+ // result should be positive
+ subtrahend.nWords = sIndex;
+ subtrahend.trimLeadingZeros();
+ return subtrahend;
+
+ }
+
+ /**
+ * Determines whether all elements of an array are zero for all indices less
+ * than a given index.
+ *
+ * @param a The array to be examined.
+ * @param from The index strictly below which elements are to be examined.
+ * @return Zero if all elements in range are zero, 1 otherwise.
+ */
+ /*@
+ @ requires 0 <= from && from <= a.length;
+ @ ensures \result == (AP(a, from) == 0 ? 0 : 1);
+ @*/
+ private /*@ pure @*/ static int checkZeroTail(int[] a, int from) {
+ while (from > 0) {
+ if (a[--from] != 0) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Compares the parameter with this <code>FDBigInteger</code>. Returns an
+ * integer accordingly as:
+ * <pre>
+ * >0: this > other
+ * 0: this == other
+ * <0: this < other
+ * </pre>
+ *
+ * @param other The <code>FDBigInteger</code> to compare.
+ * @return A negative value, zero, or a positive value according to the
+ * result of the comparison.
+ */
+ /*@
+ @ ensures \result == (this.value() < other.value() ? -1 : this.value() > other.value() ? +1 : 0);
+ @*/
+ public /*@ pure @*/ int cmp(FDBigInteger other) {
+ int aSize = nWords + offset;
+ int bSize = other.nWords + other.offset;
+ if (aSize > bSize) {
+ return 1;
+ } else if (aSize < bSize) {
+ return -1;
+ }
+ int aLen = nWords;
+ int bLen = other.nWords;
+ while (aLen > 0 && bLen > 0) {
+ int a = data[--aLen];
+ int b = other.data[--bLen];
+ if (a != b) {
+ return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
+ }
+ }
+ if (aLen > 0) {
+ return checkZeroTail(data, aLen);
+ }
+ if (bLen > 0) {
+ return -checkZeroTail(other.data, bLen);
+ }
+ return 0;
+ }
+
+ /**
+ * Compares this <code>FDBigInteger</code> with
+ * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>.
+ * Returns an integer accordingly as:
+ * <pre>
+ * >0: this > other
+ * 0: this == other
+ * <0: this < other
+ * </pre>
+ * @param p5 The exponent of the power-of-five factor.
+ * @param p2 The exponent of the power-of-two factor.
+ * @return A negative value, zero, or a positive value according to the
+ * result of the comparison.
+ */
+ /*@
+ @ requires p5 >= 0 && p2 >= 0;
+ @ ensures \result == (this.value() < pow52(p5, p2) ? -1 : this.value() > pow52(p5, p2) ? +1 : 0);
+ @*/
+ public /*@ pure @*/ int cmpPow52(int p5, int p2) {
+ if (p5 == 0) {
+ int wordcount = p2 >> 5;
+ int bitcount = p2 & 0x1f;
+ int size = this.nWords + this.offset;
+ if (size > wordcount + 1) {
+ return 1;
+ } else if (size < wordcount + 1) {
+ return -1;
+ }
+ int a = this.data[this.nWords -1];
+ int b = 1 << bitcount;
+ if (a != b) {
+ return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1;
+ }
+ return checkZeroTail(this.data, this.nWords - 1);
+ }
+ return this.cmp(big5pow(p5).leftShift(p2));
+ }
+
+ /**
+ * Compares this <code>FDBigInteger</code> with <code>x + y</code>. Returns a
+ * value according to the comparison as:
+ * <pre>
+ * -1: this < x + y
+ * 0: this == x + y
+ * 1: this > x + y
+ * </pre>
+ * @param x The first addend of the sum to compare.
+ * @param y The second addend of the sum to compare.
+ * @return -1, 0, or 1 according to the result of the comparison.
+ */
+ /*@
+ @ ensures \result == (this.value() < x.value() + y.value() ? -1 : this.value() > x.value() + y.value() ? +1 : 0);
+ @*/
+ public /*@ pure @*/ int addAndCmp(FDBigInteger x, FDBigInteger y) {
+ FDBigInteger big;
+ FDBigInteger small;
+ int xSize = x.size();
+ int ySize = y.size();
+ int bSize;
+ int sSize;
+ if (xSize >= ySize) {
+ big = x;
+ small = y;
+ bSize = xSize;
+ sSize = ySize;
+ } else {
+ big = y;
+ small = x;
+ bSize = ySize;
+ sSize = xSize;
+ }
+ int thSize = this.size();
+ if (bSize == 0) {
+ return thSize == 0 ? 0 : 1;
+ }
+ if (sSize == 0) {
+ return this.cmp(big);
+ }
+ if (bSize > thSize) {
+ return -1;
+ }
+ if (bSize + 1 < thSize) {
+ return 1;
+ }
+ long top = (big.data[big.nWords - 1] & LONG_MASK);
+ if (sSize == bSize) {
+ top += (small.data[small.nWords - 1] & LONG_MASK);
+ }
+ if ((top >>> 32) == 0) {
+ if (((top + 1) >>> 32) == 0) {
+ // good case - no carry extension
+ if (bSize < thSize) {
+ return 1;
+ }
+ // here sum.nWords == this.nWords
+ long v = (this.data[this.nWords - 1] & LONG_MASK);
+ if (v < top) {
+ return -1;
+ }
+ if (v > top + 1) {
+ return 1;
+ }
+ }
+ } else { // (top>>>32)!=0 guaranteed carry extension
+ if (bSize + 1 > thSize) {
+ return -1;
+ }
+ // here sum.nWords == this.nWords
+ top >>>= 32;
+ long v = (this.data[this.nWords - 1] & LONG_MASK);
+ if (v < top) {
+ return -1;
+ }
+ if (v > top + 1) {
+ return 1;
+ }
+ }
+ return this.cmp(big.add(small));
+ }
+
+ /**
+ * Makes this <code>FDBigInteger</code> immutable.
+ */
+ /*@
+ @ assignable this.isImmutable;
+ @ ensures this.isImmutable;
+ @*/
+ public void makeImmutable() {
+ this.isImmutable = true;
+ }
+
+ /**
+ * Multiplies this <code>FDBigInteger</code> by an integer.
+ *
+ * @param i The factor by which to multiply this <code>FDBigInteger</code>.
+ * @return This <code>FDBigInteger</code> multiplied by an integer.
+ */
+ /*@
+ @ requires this.value() == 0;
+ @ assignable \nothing;
+ @ ensures \result == this;
+ @
+ @ also
+ @
+ @ requires this.value() != 0;
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() * UNSIGNED(i));
+ @*/
+ private FDBigInteger mult(int i) {
+ if (this.nWords == 0) {
+ return this;
+ }
+ int[] r = new int[nWords + 1];
+ mult(data, nWords, i, r);
+ return new FDBigInteger(r, offset);
+ }
+
+ /**
+ * Multiplies this <code>FDBigInteger</code> by another <code>FDBigInteger</code>.
+ *
+ * @param other The <code>FDBigInteger</code> factor by which to multiply.
+ * @return The product of this and the parameter <code>FDBigInteger</code>s.
+ */
+ /*@
+ @ requires this.value() == 0;
+ @ assignable \nothing;
+ @ ensures \result == this;
+ @
+ @ also
+ @
+ @ requires this.value() != 0 && other.value() == 0;
+ @ assignable \nothing;
+ @ ensures \result == other;
+ @
+ @ also
+ @
+ @ requires this.value() != 0 && other.value() != 0;
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() * other.value());
+ @*/
+ private FDBigInteger mult(FDBigInteger other) {
+ if (this.nWords == 0) {
+ return this;
+ }
+ if (this.size() == 1) {
+ return other.mult(data[0]);
+ }
+ if (other.nWords == 0) {
+ return other;
+ }
+ if (other.size() == 1) {
+ return this.mult(other.data[0]);
+ }
+ int[] r = new int[nWords + other.nWords];
+ mult(this.data, this.nWords, other.data, other.nWords, r);
+ return new FDBigInteger(r, this.offset + other.offset);
+ }
+
+ /**
+ * Adds another <code>FDBigInteger</code> to this <code>FDBigInteger</code>.
+ *
+ * @param other The <code>FDBigInteger</code> to add.
+ * @return The sum of the <code>FDBigInteger</code>s.
+ */
+ /*@
+ @ assignable \nothing;
+ @ ensures \result.value() == \old(this.value() + other.value());
+ @*/
+ private FDBigInteger add(FDBigInteger other) {
+ FDBigInteger big, small;
+ int bigLen, smallLen;
+ int tSize = this.size();
+ int oSize = other.size();
+ if (tSize >= oSize) {
+ big = this;
+ bigLen = tSize;
+ small = other;
+ smallLen = oSize;
+ } else {
+ big = other;
+ bigLen = oSize;
+ small = this;
+ smallLen = tSize;
+ }
+ int[] r = new int[bigLen + 1];
+ int i = 0;
+ long carry = 0L;
+ for (; i < smallLen; i++) {
+ carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) )
+ + ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK)));
+ r[i] = (int) carry;
+ carry >>= 32; // signed shift.
+ }
+ for (; i < bigLen; i++) {
+ carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) );
+ r[i] = (int) carry;
+ carry >>= 32; // signed shift.
+ }
+ r[bigLen] = (int) carry;
+ return new FDBigInteger(r, 0);
+ }
+
+
+ /**
+ * Multiplies a <code>FDBigInteger</code> by an int and adds another int. The
+ * result is computed in place. This method is intended only to be invoked
+ * from
+ * <code>
+ * FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits)
+ * </code>.
+ *
+ * @param iv The factor by which to multiply this <code>FDBigInteger</code>.
+ * @param addend The value to add to the product of this
+ * <code>FDBigInteger</code> and <code>iv</code>.
+ */
+ /*@
+ @ requires this.value()*UNSIGNED(iv) + UNSIGNED(addend) < ((\bigint)1) << ((this.data.length + this.offset)*32);
+ @ assignable this.data[*];
+ @ ensures this.value() == \old(this.value()*UNSIGNED(iv) + UNSIGNED(addend));
+ @*/
+ private /*@ helper @*/ void multAddMe(int iv, int addend) {
+ long v = iv & LONG_MASK;
+ // unroll 0th iteration, doing addition.
+ long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK);
+ data[0] = (int) p;
+ p >>>= 32;
+ for (int i = 1; i < nWords; i++) {
+ p += v * (data[i] & LONG_MASK);
+ data[i] = (int) p;
+ p >>>= 32;
+ }
+ if (p != 0L) {
+ data[nWords++] = (int) p; // will fail noisily if illegal!
+ }
+ }
+
+ //
+ // original doc:
+ //
+ // do this -=q*S
+ // returns borrow
+ //
+ /**
+ * Multiplies the parameters and subtracts them from this
+ * <code>FDBigInteger</code>.
+ *
+ * @param q The integer parameter.
+ * @param S The <code>FDBigInteger</code> parameter.
+ * @return <code>this - q*S</code>.
+ */
+ /*@
+ @ ensures nWords == 0 ==> offset == 0;
+ @ ensures nWords > 0 ==> data[nWords - 1] != 0;
+ @*/
+ /*@
+ @ requires 0 < q && q <= (1L << 31);
+ @ requires data != null;
+ @ requires 0 <= nWords && nWords <= data.length && offset >= 0;
+ @ requires !this.isImmutable;
+ @ requires this.size() == S.size();
+ @ requires this != S;
+ @ assignable this.nWords, this.offset, this.data, this.data[*];
+ @ ensures -q <= \result && \result <= 0;
+ @ ensures this.size() == \old(this.size());
+ @ ensures this.value() + (\result << (this.size()*32)) == \old(this.value() - q*S.value());
+ @ ensures this.offset == \old(Math.min(this.offset, S.offset));
+ @ ensures \old(this.offset <= S.offset) ==> this.nWords == \old(this.nWords);
+ @ ensures \old(this.offset <= S.offset) ==> this.offset == \old(this.offset);
+ @ ensures \old(this.offset <= S.offset) ==> this.data == \old(this.data);
+ @
+ @ also
+ @
+ @ requires q == 0;
+ @ assignable \nothing;
+ @ ensures \result == 0;
+ @*/
+ private /*@ helper @*/ long multDiffMe(long q, FDBigInteger S) {
+ long diff = 0L;
+ if (q != 0) {
+ int deltaSize = S.offset - this.offset;
+ if (deltaSize >= 0) {
+ int[] sd = S.data;
+ int[] td = this.data;
+ for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) {
+ diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK);
+ td[tIndex] = (int) diff;
+ diff >>= 32; // N.B. SIGNED shift.
+ }
+ } else {
+ deltaSize = -deltaSize;
+ int[] rd = new int[nWords + deltaSize];
+ int sIndex = 0;
+ int rIndex = 0;
+ int[] sd = S.data;
+ for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) {
+ diff -= q * (sd[sIndex] & LONG_MASK);
+ rd[rIndex] = (int) diff;
+ diff >>= 32; // N.B. SIGNED shift.
+ }
+ int tIndex = 0;
+ int[] td = this.data;
+ for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) {
+ diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK);
+ rd[rIndex] = (int) diff;
+ diff >>= 32; // N.B. SIGNED shift.
+ }
+ this.nWords += deltaSize;
+ this.offset -= deltaSize;
+ this.data = rd;
+ }
+ }
+ return diff;
+ }
+
+
+ /**
+ * Multiplies by 10 a big integer represented as an array. The final carry
+ * is returned.
+ *
+ * @param src The array representation of the big integer.
+ * @param srcLen The number of elements of <code>src</code> to use.
+ * @param dst The product array.
+ * @return The final carry of the multiplication.
+ */
+ /*@
+ @ requires src.length >= srcLen && dst.length >= srcLen;
+ @ assignable dst[0 .. srcLen - 1];
+ @ ensures 0 <= \result && \result < 10;
+ @ ensures AP(dst, srcLen) + (\result << (srcLen*32)) == \old(AP(src, srcLen) * 10);
+ @*/
+ private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) {
+ long carry = 0;
+ for (int i = 0; i < srcLen; i++) {
+ long product = (src[i] & LONG_MASK) * 10L + carry;
+ dst[i] = (int) product;
+ carry = product >>> 32;
+ }
+ return (int) carry;
+ }
+
+ /**
+ * Multiplies by a constant value a big integer represented as an array.
+ * The constant factor is an <code>int</code>.
+ *
+ * @param src The array representation of the big integer.
+ * @param srcLen The number of elements of <code>src</code> to use.
+ * @param value The constant factor by which to multiply.
+ * @param dst The product array.
+ */
+ /*@
+ @ requires src.length >= srcLen && dst.length >= srcLen + 1;
+ @ assignable dst[0 .. srcLen];
+ @ ensures AP(dst, srcLen + 1) == \old(AP(src, srcLen) * UNSIGNED(value));
+ @*/
+ private static void mult(int[] src, int srcLen, int value, int[] dst) {
+ long val = value & LONG_MASK;
+ long carry = 0;
+ for (int i = 0; i < srcLen; i++) {
+ long product = (src[i] & LONG_MASK) * val + carry;
+ dst[i] = (int) product;
+ carry = product >>> 32;
+ }
+ dst[srcLen] = (int) carry;
+ }
+
+ /**
+ * Multiplies by a constant value a big integer represented as an array.
+ * The constant factor is a long represent as two <code>int</code>s.
+ *
+ * @param src The array representation of the big integer.
+ * @param srcLen The number of elements of <code>src</code> to use.
+ * @param v0 The lower 32 bits of the long factor.
+ * @param v1 The upper 32 bits of the long factor.
+ * @param dst The product array.
+ */
+ /*@
+ @ requires src != dst;
+ @ requires src.length >= srcLen && dst.length >= srcLen + 2;
+ @ assignable dst[0 .. srcLen + 1];
+ @ ensures AP(dst, srcLen + 2) == \old(AP(src, srcLen) * (UNSIGNED(v0) + (UNSIGNED(v1) << 32)));
+ @*/
+ private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) {
+ long v = v0 & LONG_MASK;
+ long carry = 0;
+ for (int j = 0; j < srcLen; j++) {
+ long product = v * (src[j] & LONG_MASK) + carry;
+ dst[j] = (int) product;
+ carry = product >>> 32;
+ }
+ dst[srcLen] = (int) carry;
+ v = v1 & LONG_MASK;
+ carry = 0;
+ for (int j = 0; j < srcLen; j++) {
+ long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry;
+ dst[j + 1] = (int) product;
+ carry = product >>> 32;
+ }
+ dst[srcLen + 1] = (int) carry;
+ }
+
+ // Fails assertion for negative exponent.
+ /**
+ * Computes <code>5</code> raised to a given power.
+ *
+ * @param p The exponent of 5.
+ * @return <code>5<sup>p</sup></code>.
+ */
+ private static FDBigInteger big5pow(int p) {
+ assert p >= 0 : p; // negative power of 5
+ if (p < MAX_FIVE_POW) {
+ return POW_5_CACHE[p];
+ }
+ return big5powRec(p);
+ }
+
+ // slow path
+ /**
+ * Computes <code>5</code> raised to a given power.
+ *
+ * @param p The exponent of 5.
+ * @return <code>5<sup>p</sup></code>.
+ */
+ private static FDBigInteger big5powRec(int p) {
+ if (p < MAX_FIVE_POW) {
+ return POW_5_CACHE[p];
+ }
+ // construct the value.
+ // recursively.
+ int q, r;
+ // in order to compute 5^p,
+ // compute its square root, 5^(p/2) and square.
+ // or, let q = p / 2, r = p -q, then
+ // 5^p = 5^(q+r) = 5^q * 5^r
+ q = p >> 1;
+ r = p - q;
+ FDBigInteger bigq = big5powRec(q);
+ if (r < SMALL_5_POW.length) {
+ return bigq.mult(SMALL_5_POW[r]);
+ } else {
+ return bigq.mult(big5powRec(r));
+ }
+ }
+
+ // for debugging ...
+ /**
+ * Converts this <code>FDBigInteger</code> to a hexadecimal string.
+ *
+ * @return The hexadecimal string representation.
+ */
+ public String toHexString(){
+ if(nWords ==0) {
+ return "0";
+ }
+ StringBuilder sb = new StringBuilder((nWords +offset)*8);
+ for(int i= nWords -1; i>=0; i--) {
+ String subStr = Integer.toHexString(data[i]);
+ for(int j = subStr.length(); j<8; j++) {
+ sb.append('0');
+ }
+ sb.append(subStr);
+ }
+ for(int i=offset; i>0; i--) {
+ sb.append("00000000");
+ }
+ return sb.toString();
+ }
+
+ // for debugging ...
+ /**
+ * Converts this <code>FDBigInteger</code> to a <code>BigInteger</code>.
+ *
+ * @return The <code>BigInteger</code> representation.
+ */
+ public BigInteger toBigInteger() {
+ byte[] magnitude = new byte[nWords * 4 + 1];
+ for (int i = 0; i < nWords; i++) {
+ int w = data[i];
+ magnitude[magnitude.length - 4 * i - 1] = (byte) w;
+ magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8);
+ magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16);
+ magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24);
+ }
+ return new BigInteger(magnitude).shiftLeft(offset * 32);
+ }
+
+ // for debugging ...
+ /**
+ * Converts this <code>FDBigInteger</code> to a string.
+ *
+ * @return The string representation.
+ */
+ @Override
+ public String toString(){
+ return toBigInteger().toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/misc/FloatingDecimal.java b/ojluni/src/main/java/sun/misc/FloatingDecimal.java
new file mode 100644
index 0000000..ddd8790
--- /dev/null
+++ b/ojluni/src/main/java/sun/misc/FloatingDecimal.java
@@ -0,0 +1,2541 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.misc;
+
+import java.util.Arrays;
+import java.util.regex.*;
+
+/**
+ * A class for converting between ASCII and decimal representations of a single
+ * or double precision floating point number. Most conversions are provided via
+ * static convenience methods, although a <code>BinaryToASCIIConverter</code>
+ * instance may be obtained and reused.
+ */
+public class FloatingDecimal{
+ //
+ // Constants of the implementation;
+ // most are IEEE-754 related.
+ // (There are more really boring constants at the end.)
+ //
+ static final int EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1;
+ static final long FRACT_HOB = ( 1L<<EXP_SHIFT ); // assumed High-Order bit
+ static final long EXP_ONE = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; // exponent of 1.0
+ static final int MAX_SMALL_BIN_EXP = 62;
+ static final int MIN_SMALL_BIN_EXP = -( 63 / 3 );
+ static final int MAX_DECIMAL_DIGITS = 15;
+ static final int MAX_DECIMAL_EXPONENT = 308;
+ static final int MIN_DECIMAL_EXPONENT = -324;
+ static final int BIG_DECIMAL_EXPONENT = 324; // i.e. abs(MIN_DECIMAL_EXPONENT)
+ static final int MAX_NDIGITS = 1100;
+
+ static final int SINGLE_EXP_SHIFT = FloatConsts.SIGNIFICAND_WIDTH - 1;
+ static final int SINGLE_FRACT_HOB = 1<<SINGLE_EXP_SHIFT;
+ static final int SINGLE_MAX_DECIMAL_DIGITS = 7;
+ static final int SINGLE_MAX_DECIMAL_EXPONENT = 38;
+ static final int SINGLE_MIN_DECIMAL_EXPONENT = -45;
+ static final int SINGLE_MAX_NDIGITS = 200;
+
+ static final int INT_DECIMAL_DIGITS = 9;
+
+ /**
+ * Converts a double precision floating point value to a <code>String</code>.
+ *
+ * @param d The double precision value.
+ * @return The value converted to a <code>String</code>.
+ */
+ public static String toJavaFormatString(double d) {
+ return getBinaryToASCIIConverter(d).toJavaFormatString();
+ }
+
+ /**
+ * Converts a single precision floating point value to a <code>String</code>.
+ *
+ * @param f The single precision value.
+ * @return The value converted to a <code>String</code>.
+ */
+ public static String toJavaFormatString(float f) {
+ return getBinaryToASCIIConverter(f).toJavaFormatString();
+ }
+
+ /**
+ * Appends a double precision floating point value to an <code>Appendable</code>.
+ * @param d The double precision value.
+ * @param buf The <code>Appendable</code> with the value appended.
+ */
+ public static void appendTo(double d, Appendable buf) {
+ getBinaryToASCIIConverter(d).appendTo(buf);
+ }
+
+ /**
+ * Appends a single precision floating point value to an <code>Appendable</code>.
+ * @param f The single precision value.
+ * @param buf The <code>Appendable</code> with the value appended.
+ */
+ public static void appendTo(float f, Appendable buf) {
+ getBinaryToASCIIConverter(f).appendTo(buf);
+ }
+
+ /**
+ * Converts a <code>String</code> to a double precision floating point value.
+ *
+ * @param s The <code>String</code> to convert.
+ * @return The double precision value.
+ * @throws NumberFormatException If the <code>String</code> does not
+ * represent a properly formatted double precision value.
+ */
+ public static double parseDouble(String s) throws NumberFormatException {
+ return readJavaFormatString(s).doubleValue();
+ }
+
+ /**
+ * Converts a <code>String</code> to a single precision floating point value.
+ *
+ * @param s The <code>String</code> to convert.
+ * @return The single precision value.
+ * @throws NumberFormatException If the <code>String</code> does not
+ * represent a properly formatted single precision value.
+ */
+ public static float parseFloat(String s) throws NumberFormatException {
+ return readJavaFormatString(s).floatValue();
+ }
+
+ /**
+ * A converter which can process single or double precision floating point
+ * values into an ASCII <code>String</code> representation.
+ */
+ public interface BinaryToASCIIConverter {
+ /**
+ * Converts a floating point value into an ASCII <code>String</code>.
+ * @return The value converted to a <code>String</code>.
+ */
+ public String toJavaFormatString();
+
+ /**
+ * Appends a floating point value to an <code>Appendable</code>.
+ * @param buf The <code>Appendable</code> to receive the value.
+ */
+ public void appendTo(Appendable buf);
+
+ /**
+ * Retrieves the decimal exponent most closely corresponding to this value.
+ * @return The decimal exponent.
+ */
+ public int getDecimalExponent();
+
+ /**
+ * Retrieves the value as an array of digits.
+ * @param digits The digit array.
+ * @return The number of valid digits copied into the array.
+ */
+ public int getDigits(char[] digits);
+
+ /**
+ * Indicates the sign of the value.
+ * @return <code>value < 0.0</code>.
+ */
+ public boolean isNegative();
+
+ /**
+ * Indicates whether the value is either infinite or not a number.
+ *
+ * @return <code>true</code> if and only if the value is <code>NaN</code>
+ * or infinite.
+ */
+ public boolean isExceptional();
+
+ /**
+ * Indicates whether the value was rounded up during the binary to ASCII
+ * conversion.
+ *
+ * @return <code>true</code> if and only if the value was rounded up.
+ */
+ public boolean digitsRoundedUp();
+
+ /**
+ * Indicates whether the binary to ASCII conversion was exact.
+ *
+ * @return <code>true</code> if any only if the conversion was exact.
+ */
+ public boolean decimalDigitsExact();
+ }
+
+ /**
+ * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code>
+ * and infinite values.
+ */
+ private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter {
+ final private String image;
+ private boolean isNegative;
+
+ public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) {
+ this.image = image;
+ this.isNegative = isNegative;
+ }
+
+ @Override
+ public String toJavaFormatString() {
+ return image;
+ }
+
+ @Override
+ public void appendTo(Appendable buf) {
+ if (buf instanceof StringBuilder) {
+ ((StringBuilder) buf).append(image);
+ } else if (buf instanceof StringBuffer) {
+ ((StringBuffer) buf).append(image);
+ } else {
+ assert false;
+ }
+ }
+
+ @Override
+ public int getDecimalExponent() {
+ throw new IllegalArgumentException("Exceptional value does not have an exponent");
+ }
+
+ @Override
+ public int getDigits(char[] digits) {
+ throw new IllegalArgumentException("Exceptional value does not have digits");
+ }
+
+ @Override
+ public boolean isNegative() {
+ return isNegative;
+ }
+
+ @Override
+ public boolean isExceptional() {
+ return true;
+ }
+
+ @Override
+ public boolean digitsRoundedUp() {
+ throw new IllegalArgumentException("Exceptional value is not rounded");
+ }
+
+ @Override
+ public boolean decimalDigitsExact() {
+ throw new IllegalArgumentException("Exceptional value is not exact");
+ }
+ }
+
+ private static final String INFINITY_REP = "Infinity";
+ private static final int INFINITY_LENGTH = INFINITY_REP.length();
+ private static final String NAN_REP = "NaN";
+ private static final int NAN_LENGTH = NAN_REP.length();
+
+ private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false);
+ private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true);
+ private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false);
+ private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'});
+ private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'});
+
+ /**
+ * A buffered implementation of <code>BinaryToASCIIConverter</code>.
+ */
+ static class BinaryToASCIIBuffer implements BinaryToASCIIConverter {
+ private boolean isNegative;
+ private int decExponent;
+ private int firstDigitIndex;
+ private int nDigits;
+ private final char[] digits;
+ private final char[] buffer = new char[26];
+
+ //
+ // The fields below provide additional information about the result of
+ // the binary to decimal digits conversion done in dtoa() and roundup()
+ // methods. They are changed if needed by those two methods.
+ //
+
+ // True if the dtoa() binary to decimal conversion was exact.
+ private boolean exactDecimalConversion = false;
+
+ // True if the result of the binary to decimal conversion was rounded-up
+ // at the end of the conversion process, i.e. roundUp() method was called.
+ private boolean decimalDigitsRoundedUp = false;
+
+ /**
+ * Default constructor; used for non-zero values,
+ * <code>BinaryToASCIIBuffer</code> may be thread-local and reused
+ */
+ BinaryToASCIIBuffer(){
+ this.digits = new char[20];
+ }
+
+ /**
+ * Creates a specialized value (positive and negative zeros).
+ */
+ BinaryToASCIIBuffer(boolean isNegative, char[] digits){
+ this.isNegative = isNegative;
+ this.decExponent = 0;
+ this.digits = digits;
+ this.firstDigitIndex = 0;
+ this.nDigits = digits.length;
+ }
+
+ @Override
+ public String toJavaFormatString() {
+ int len = getChars(buffer);
+ return new String(buffer, 0, len);
+ }
+
+ @Override
+ public void appendTo(Appendable buf) {
+ int len = getChars(buffer);
+ if (buf instanceof StringBuilder) {
+ ((StringBuilder) buf).append(buffer, 0, len);
+ } else if (buf instanceof StringBuffer) {
+ ((StringBuffer) buf).append(buffer, 0, len);
+ } else {
+ assert false;
+ }
+ }
+
+ @Override
+ public int getDecimalExponent() {
+ return decExponent;
+ }
+
+ @Override
+ public int getDigits(char[] digits) {
+ System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits);
+ return this.nDigits;
+ }
+
+ @Override
+ public boolean isNegative() {
+ return isNegative;
+ }
+
+ @Override
+ public boolean isExceptional() {
+ return false;
+ }
+
+ @Override
+ public boolean digitsRoundedUp() {
+ return decimalDigitsRoundedUp;
+ }
+
+ @Override
+ public boolean decimalDigitsExact() {
+ return exactDecimalConversion;
+ }
+
+ private void setSign(boolean isNegative) {
+ this.isNegative = isNegative;
+ }
+
+ /**
+ * This is the easy subcase --
+ * all the significant bits, after scaling, are held in lvalue.
+ * negSign and decExponent tell us what processing and scaling
+ * has already been done. Exceptional cases have already been
+ * stripped out.
+ * In particular:
+ * lvalue is a finite number (not Inf, nor NaN)
+ * lvalue > 0L (not zero, nor negative).
+ *
+ * The only reason that we develop the digits here, rather than
+ * calling on Long.toString() is that we can do it a little faster,
+ * and besides want to treat trailing 0s specially. If Long.toString
+ * changes, we should re-evaluate this strategy!
+ */
+ private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){
+ if ( insignificantDigits != 0 ){
+ // Discard non-significant low-order bits, while rounding,
+ // up to insignificant value.
+ long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i;
+ long residue = lvalue % pow10;
+ lvalue /= pow10;
+ decExponent += insignificantDigits;
+ if ( residue >= (pow10>>1) ){
+ // round up based on the low-order bits we're discarding
+ lvalue++;
+ }
+ }
+ int digitno = digits.length -1;
+ int c;
+ if ( lvalue <= Integer.MAX_VALUE ){
+ assert lvalue > 0L : lvalue; // lvalue <= 0
+ // even easier subcase!
+ // can do int arithmetic rather than long!
+ int ivalue = (int)lvalue;
+ c = ivalue%10;
+ ivalue /= 10;
+ while ( c == 0 ){
+ decExponent++;
+ c = ivalue%10;
+ ivalue /= 10;
+ }
+ while ( ivalue != 0){
+ digits[digitno--] = (char)(c+'0');
+ decExponent++;
+ c = ivalue%10;
+ ivalue /= 10;
+ }
+ digits[digitno] = (char)(c+'0');
+ } else {
+ // same algorithm as above (same bugs, too )
+ // but using long arithmetic.
+ c = (int)(lvalue%10L);
+ lvalue /= 10L;
+ while ( c == 0 ){
+ decExponent++;
+ c = (int)(lvalue%10L);
+ lvalue /= 10L;
+ }
+ while ( lvalue != 0L ){
+ digits[digitno--] = (char)(c+'0');
+ decExponent++;
+ c = (int)(lvalue%10L);
+ lvalue /= 10;
+ }
+ digits[digitno] = (char)(c+'0');
+ }
+ this.decExponent = decExponent+1;
+ this.firstDigitIndex = digitno;
+ this.nDigits = this.digits.length - digitno;
+ }
+
+ private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat)
+ {
+ assert fractBits > 0 ; // fractBits here can't be zero or negative
+ assert (fractBits & FRACT_HOB)!=0 ; // Hi-order bit should be set
+ // Examine number. Determine if it is an easy case,
+ // which we can do pretty trivially using float/long conversion,
+ // or whether we must do real work.
+ final int tailZeros = Long.numberOfTrailingZeros(fractBits);
+
+ // number of significant bits of fractBits;
+ final int nFractBits = EXP_SHIFT+1-tailZeros;
+
+ // reset flags to default values as dtoa() does not always set these
+ // flags and a prior call to dtoa() might have set them to incorrect
+ // values with respect to the current state.
+ decimalDigitsRoundedUp = false;
+ exactDecimalConversion = false;
+
+ // number of significant bits to the right of the point.
+ int nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
+ if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){
+ // Look more closely at the number to decide if,
+ // with scaling by 10^nTinyBits, the result will fit in
+ // a long.
+ if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){
+ //
+ // We can do this:
+ // take the fraction bits, which are normalized.
+ // (a) nTinyBits == 0: Shift left or right appropriately
+ // to align the binary point at the extreme right, i.e.
+ // where a long int point is expected to be. The integer
+ // result is easily converted to a string.
+ // (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits,
+ // which effectively converts to long and scales by
+ // 2^nTinyBits. Then multiply by 5^nTinyBits to
+ // complete the scaling. We know this won't overflow
+ // because we just counted the number of bits necessary
+ // in the result. The integer you get from this can
+ // then be converted to a string pretty easily.
+ //
+ if ( nTinyBits == 0 ) {
+ int insignificant;
+ if ( binExp > nSignificantBits ){
+ insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1);
+ } else {
+ insignificant = 0;
+ }
+ if ( binExp >= EXP_SHIFT ){
+ fractBits <<= (binExp-EXP_SHIFT);
+ } else {
+ fractBits >>>= (EXP_SHIFT-binExp) ;
+ }
+ developLongDigits( 0, fractBits, insignificant );
+ return;
+ }
+ //
+ // The following causes excess digits to be printed
+ // out in the single-float case. Our manipulation of
+ // halfULP here is apparently not correct. If we
+ // better understand how this works, perhaps we can
+ // use this special case again. But for the time being,
+ // we do not.
+ // else {
+ // fractBits >>>= EXP_SHIFT+1-nFractBits;
+ // fractBits//= long5pow[ nTinyBits ];
+ // halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
+ // developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) );
+ // return;
+ // }
+ //
+ }
+ }
+ //
+ // This is the hard case. We are going to compute large positive
+ // integers B and S and integer decExp, s.t.
+ // d = ( B / S )// 10^decExp
+ // 1 <= B / S < 10
+ // Obvious choices are:
+ // decExp = floor( log10(d) )
+ // B = d// 2^nTinyBits// 10^max( 0, -decExp )
+ // S = 10^max( 0, decExp)// 2^nTinyBits
+ // (noting that nTinyBits has already been forced to non-negative)
+ // I am also going to compute a large positive integer
+ // M = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp )
+ // i.e. M is (1/2) of the ULP of d, scaled like B.
+ // When we iterate through dividing B/S and picking off the
+ // quotient bits, we will know when to stop when the remainder
+ // is <= M.
+ //
+ // We keep track of powers of 2 and powers of 5.
+ //
+ int decExp = estimateDecExp(fractBits,binExp);
+ int B2, B5; // powers of 2 and powers of 5, respectively, in B
+ int S2, S5; // powers of 2 and powers of 5, respectively, in S
+ int M2, M5; // powers of 2 and powers of 5, respectively, in M
+
+ B5 = Math.max( 0, -decExp );
+ B2 = B5 + nTinyBits + binExp;
+
+ S5 = Math.max( 0, decExp );
+ S2 = S5 + nTinyBits;
+
+ M5 = B5;
+ M2 = B2 - nSignificantBits;
+
+ //
+ // the long integer fractBits contains the (nFractBits) interesting
+ // bits from the mantissa of d ( hidden 1 added if necessary) followed
+ // by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness,
+ // I will shift out those zeros before turning fractBits into a
+ // FDBigInteger. The resulting whole number will be
+ // d * 2^(nFractBits-1-binExp).
+ //
+ fractBits >>>= tailZeros;
+ B2 -= nFractBits-1;
+ int common2factor = Math.min( B2, S2 );
+ B2 -= common2factor;
+ S2 -= common2factor;
+ M2 -= common2factor;
+
+ //
+ // HACK!! For exact powers of two, the next smallest number
+ // is only half as far away as we think (because the meaning of
+ // ULP changes at power-of-two bounds) for this reason, we
+ // hack M2. Hope this works.
+ //
+ if ( nFractBits == 1 ) {
+ M2 -= 1;
+ }
+
+ if ( M2 < 0 ){
+ // oops.
+ // since we cannot scale M down far enough,
+ // we must scale the other values up.
+ B2 -= M2;
+ S2 -= M2;
+ M2 = 0;
+ }
+ //
+ // Construct, Scale, iterate.
+ // Some day, we'll write a stopping test that takes
+ // account of the asymmetry of the spacing of floating-point
+ // numbers below perfect powers of 2
+ // 26 Sept 96 is not that day.
+ // So we use a symmetric test.
+ //
+ int ndigit = 0;
+ boolean low, high;
+ long lowDigitDifference;
+ int q;
+
+ //
+ // Detect the special cases where all the numbers we are about
+ // to compute will fit in int or long integers.
+ // In these cases, we will avoid doing FDBigInteger arithmetic.
+ // We use the same algorithms, except that we "normalize"
+ // our FDBigIntegers before iterating. This is to make division easier,
+ // as it makes our fist guess (quotient of high-order words)
+ // more accurate!
+ //
+ // Some day, we'll write a stopping test that takes
+ // account of the asymmetry of the spacing of floating-point
+ // numbers below perfect powers of 2
+ // 26 Sept 96 is not that day.
+ // So we use a symmetric test.
+ //
+ // binary digits needed to represent B, approx.
+ int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 ));
+
+ // binary digits needed to represent 10*S, approx.
+ int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 ));
+ if ( Bbits < 64 && tenSbits < 64){
+ if ( Bbits < 32 && tenSbits < 32){
+ // wa-hoo! They're all ints!
+ int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2;
+ int s = FDBigInteger.SMALL_5_POW[S5] << S2;
+ int m = FDBigInteger.SMALL_5_POW[M5] << M2;
+ int tens = s * 10;
+ //
+ // Unroll the first iteration. If our decExp estimate
+ // was too high, our first quotient will be zero. In this
+ // case, we discard it and decrement decExp.
+ //
+ ndigit = 0;
+ q = b / s;
+ b = 10 * ( b % s );
+ m *= 10;
+ low = (b < m );
+ high = (b+m > tens );
+ assert q < 10 : q; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ decExp--;
+ } else {
+ digits[ndigit++] = (char)('0' + q);
+ }
+ //
+ // HACK! Java spec sez that we always have at least
+ // one digit after the . in either F- or E-form output.
+ // Thus we will need more than one digit if we're using
+ // E-form
+ //
+ if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){
+ high = low = false;
+ }
+ while( ! low && ! high ){
+ q = b / s;
+ b = 10 * ( b % s );
+ m *= 10;
+ assert q < 10 : q; // excessively large digit
+ if ( m > 0L ){
+ low = (b < m );
+ high = (b+m > tens );
+ } else {
+ // hack -- m might overflow!
+ // in this case, it is certainly > b,
+ // which won't
+ // and b+m > tens, too, since that has overflowed
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char)('0' + q);
+ }
+ lowDigitDifference = (b<<1) - tens;
+ exactDecimalConversion = (b == 0);
+ } else {
+ // still good! they're all longs!
+ long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2;
+ long s = FDBigInteger.LONG_5_POW[S5] << S2;
+ long m = FDBigInteger.LONG_5_POW[M5] << M2;
+ long tens = s * 10L;
+ //
+ // Unroll the first iteration. If our decExp estimate
+ // was too high, our first quotient will be zero. In this
+ // case, we discard it and decrement decExp.
+ //
+ ndigit = 0;
+ q = (int) ( b / s );
+ b = 10L * ( b % s );
+ m *= 10L;
+ low = (b < m );
+ high = (b+m > tens );
+ assert q < 10 : q; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ decExp--;
+ } else {
+ digits[ndigit++] = (char)('0' + q);
+ }
+ //
+ // HACK! Java spec sez that we always have at least
+ // one digit after the . in either F- or E-form output.
+ // Thus we will need more than one digit if we're using
+ // E-form
+ //
+ if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){
+ high = low = false;
+ }
+ while( ! low && ! high ){
+ q = (int) ( b / s );
+ b = 10 * ( b % s );
+ m *= 10;
+ assert q < 10 : q; // excessively large digit
+ if ( m > 0L ){
+ low = (b < m );
+ high = (b+m > tens );
+ } else {
+ // hack -- m might overflow!
+ // in this case, it is certainly > b,
+ // which won't
+ // and b+m > tens, too, since that has overflowed
+ // either!
+ low = true;
+ high = true;
+ }
+ digits[ndigit++] = (char)('0' + q);
+ }
+ lowDigitDifference = (b<<1) - tens;
+ exactDecimalConversion = (b == 0);
+ }
+ } else {
+ //
+ // We really must do FDBigInteger arithmetic.
+ // Fist, construct our FDBigInteger initial values.
+ //
+ FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2);
+ int shiftBias = Sval.getNormalizationBias();
+ Sval = Sval.leftShift(shiftBias); // normalize so that division works better
+
+ FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias);
+ FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1);
+
+ FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); //Sval.mult( 10 );
+ //
+ // Unroll the first iteration. If our decExp estimate
+ // was too high, our first quotient will be zero. In this
+ // case, we discard it and decrement decExp.
+ //
+ ndigit = 0;
+ q = Bval.quoRemIteration( Sval );
+ low = (Bval.cmp( Mval ) < 0);
+ high = tenSval.addAndCmp(Bval,Mval)<=0;
+
+ assert q < 10 : q; // excessively large digit
+ if ( (q == 0) && ! high ){
+ // oops. Usually ignore leading zero.
+ decExp--;
+ } else {
+ digits[ndigit++] = (char)('0' + q);
+ }
+ //
+ // HACK! Java spec sez that we always have at least
+ // one digit after the . in either F- or E-form output.
+ // Thus we will need more than one digit if we're using
+ // E-form
+ //
+ if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){
+ high = low = false;
+ }
+ while( ! low && ! high ){
+ q = Bval.quoRemIteration( Sval );
+ assert q < 10 : q; // excessively large digit
+ Mval = Mval.multBy10(); //Mval = Mval.mult( 10 );
+ low = (Bval.cmp( Mval ) < 0);
+ high = tenSval.addAndCmp(Bval,Mval)<=0;
+ digits[ndigit++] = (char)('0' + q);
+ }
+ if ( high && low ){
+ Bval = Bval.leftShift(1);
+ lowDigitDifference = Bval.cmp(tenSval);
+ } else {
+ lowDigitDifference = 0L; // this here only for flow analysis!
+ }
+ exactDecimalConversion = (Bval.cmp( FDBigInteger.ZERO ) == 0);
+ }
+ this.decExponent = decExp+1;
+ this.firstDigitIndex = 0;
+ this.nDigits = ndigit;
+ //
+ // Last digit gets rounded based on stopping condition.
+ //
+ if ( high ){
+ if ( low ){
+ if ( lowDigitDifference == 0L ){
+ // it's a tie!
+ // choose based on which digits we like.
+ if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) {
+ roundup();
+ }
+ } else if ( lowDigitDifference > 0 ){
+ roundup();
+ }
+ } else {
+ roundup();
+ }
+ }
+ }
+
+ // add one to the least significant digit.
+ // in the unlikely event there is a carry out, deal with it.
+ // assert that this will only happen where there
+ // is only one digit, e.g. (float)1e-44 seems to do it.
+ //
+ private void roundup() {
+ int i = (firstDigitIndex + nDigits - 1);
+ int q = digits[i];
+ if (q == '9') {
+ while (q == '9' && i > firstDigitIndex) {
+ digits[i] = '0';
+ q = digits[--i];
+ }
+ if (q == '9') {
+ // carryout! High-order 1, rest 0s, larger exp.
+ decExponent += 1;
+ digits[firstDigitIndex] = '1';
+ return;
+ }
+ // else fall through.
+ }
+ digits[i] = (char) (q + 1);
+ decimalDigitsRoundedUp = true;
+ }
+
+ /**
+ * Estimate decimal exponent. (If it is small-ish,
+ * we could double-check.)
+ *
+ * First, scale the mantissa bits such that 1 <= d2 < 2.
+ * We are then going to estimate
+ * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5)
+ * and so we can estimate
+ * log10(d) ~=~ log10(d2) + binExp * log10(2)
+ * take the floor and call it decExp.
+ */
+ static int estimateDecExp(long fractBits, int binExp) {
+ double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) );
+ double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981;
+ long dBits = Double.doubleToRawLongBits(d); //can't be NaN here so use raw
+ int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS;
+ boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
+ if(exponent>=0 && exponent<52) { // hot path
+ long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent;
+ int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent));
+ return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r;
+ } else if (exponent < 0) {
+ return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 :
+ ( (isNegative) ? -1 : 0) );
+ } else { //if (exponent >= 52)
+ return (int)d;
+ }
+ }
+
+ private static int insignificantDigits(int insignificant) {
+ int i;
+ for ( i = 0; insignificant >= 10L; i++ ) {
+ insignificant /= 10L;
+ }
+ return i;
+ }
+
+ /**
+ * Calculates
+ * <pre>
+ * insignificantDigitsForPow2(v) == insignificantDigits(1L<<v)
+ * </pre>
+ */
+ private static int insignificantDigitsForPow2(int p2) {
+ if(p2>1 && p2 < insignificantDigitsNumber.length) {
+ return insignificantDigitsNumber[p2];
+ }
+ return 0;
+ }
+
+ /**
+ * If insignificant==(1L << ixd)
+ * i = insignificantDigitsNumber[idx] is the same as:
+ * int i;
+ * for ( i = 0; insignificant >= 10L; i++ )
+ * insignificant /= 10L;
+ */
+ private static int[] insignificantDigitsNumber = {
+ 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11,
+ 12, 12, 12, 12, 13, 13, 13, 14, 14, 14,
+ 15, 15, 15, 15, 16, 16, 16, 17, 17, 17,
+ 18, 18, 18, 19
+ };
+
+ // approximately ceil( log2( long5pow[i] ) )
+ private static final int[] N_5_BITS = {
+ 0,
+ 3,
+ 5,
+ 7,
+ 10,
+ 12,
+ 14,
+ 17,
+ 19,
+ 21,
+ 24,
+ 26,
+ 28,
+ 31,
+ 33,
+ 35,
+ 38,
+ 40,
+ 42,
+ 45,
+ 47,
+ 49,
+ 52,
+ 54,
+ 56,
+ 59,
+ 61,
+ };
+
+ private int getChars(char[] result) {
+ assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
+ int i = 0;
+ if (isNegative) {
+ result[0] = '-';
+ i = 1;
+ }
+ if (decExponent > 0 && decExponent < 8) {
+ // print digits.digits.
+ int charLength = Math.min(nDigits, decExponent);
+ System.arraycopy(digits, firstDigitIndex, result, i, charLength);
+ i += charLength;
+ if (charLength < decExponent) {
+ charLength = decExponent - charLength;
+ Arrays.fill(result,i,i+charLength,'0');
+ i += charLength;
+ result[i++] = '.';
+ result[i++] = '0';
+ } else {
+ result[i++] = '.';
+ if (charLength < nDigits) {
+ int t = nDigits - charLength;
+ System.arraycopy(digits, firstDigitIndex+charLength, result, i, t);
+ i += t;
+ } else {
+ result[i++] = '0';
+ }
+ }
+ } else if (decExponent <= 0 && decExponent > -3) {
+ result[i++] = '0';
+ result[i++] = '.';
+ if (decExponent != 0) {
+ Arrays.fill(result, i, i-decExponent, '0');
+ i -= decExponent;
+ }
+ System.arraycopy(digits, firstDigitIndex, result, i, nDigits);
+ i += nDigits;
+ } else {
+ result[i++] = digits[firstDigitIndex];
+ result[i++] = '.';
+ if (nDigits > 1) {
+ System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1);
+ i += nDigits - 1;
+ } else {
+ result[i++] = '0';
+ }
+ result[i++] = 'E';
+ int e;
+ if (decExponent <= 0) {
+ result[i++] = '-';
+ e = -decExponent + 1;
+ } else {
+ e = decExponent - 1;
+ }
+ // decExponent has 1, 2, or 3, digits
+ if (e <= 9) {
+ result[i++] = (char) (e + '0');
+ } else if (e <= 99) {
+ result[i++] = (char) (e / 10 + '0');
+ result[i++] = (char) (e % 10 + '0');
+ } else {
+ result[i++] = (char) (e / 100 + '0');
+ e %= 100;
+ result[i++] = (char) (e / 10 + '0');
+ result[i++] = (char) (e % 10 + '0');
+ }
+ }
+ return i;
+ }
+
+ }
+
+ private static final ThreadLocal<BinaryToASCIIBuffer> threadLocalBinaryToASCIIBuffer =
+ new ThreadLocal<BinaryToASCIIBuffer>() {
+ @Override
+ protected BinaryToASCIIBuffer initialValue() {
+ return new BinaryToASCIIBuffer();
+ }
+ };
+
+ private static BinaryToASCIIBuffer getBinaryToASCIIBuffer() {
+ return threadLocalBinaryToASCIIBuffer.get();
+ }
+
+ /**
+ * A converter which can process an ASCII <code>String</code> representation
+ * of a single or double precision floating point value into a
+ * <code>float</code> or a <code>double</code>.
+ */
+ interface ASCIIToBinaryConverter {
+
+ double doubleValue();
+
+ float floatValue();
+
+ }
+
+ /**
+ * A <code>ASCIIToBinaryConverter</code> container for a <code>double</code>.
+ */
+ static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+ final private double doubleVal;
+ final private float floatVal;
+
+ public PreparedASCIIToBinaryBuffer(double doubleVal, float floatVal) {
+ this.doubleVal = doubleVal;
+ this.floatVal = floatVal;
+ }
+
+ @Override
+ public double doubleValue() {
+ return doubleVal;
+ }
+
+ @Override
+ public float floatValue() {
+ return floatVal;
+ }
+ }
+
+ static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY);
+ static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);
+ static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER = new PreparedASCIIToBinaryBuffer(Double.NaN, Float.NaN);
+ static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d, 0.0f);
+ static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d, -0.0f);
+
+ /**
+ * A buffered implementation of <code>ASCIIToBinaryConverter</code>.
+ */
+ static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter {
+ boolean isNegative;
+ int decExponent;
+ char digits[];
+ int nDigits;
+
+ ASCIIToBinaryBuffer( boolean negSign, int decExponent, char[] digits, int n)
+ {
+ this.isNegative = negSign;
+ this.decExponent = decExponent;
+ this.digits = digits;
+ this.nDigits = n;
+ }
+
+ /**
+ * Takes a FloatingDecimal, which we presumably just scanned in,
+ * and finds out what its value is, as a double.
+ *
+ * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
+ * ROUNDING DIRECTION in case the result is really destined
+ * for a single-precision float.
+ */
+ @Override
+ public double doubleValue() {
+ int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1);
+ //
+ // convert the lead kDigits to a long integer.
+ //
+ // (special performance hack: start to do it using int)
+ int iValue = (int) digits[0] - (int) '0';
+ int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS);
+ for (int i = 1; i < iDigits; i++) {
+ iValue = iValue * 10 + (int) digits[i] - (int) '0';
+ }
+ long lValue = (long) iValue;
+ for (int i = iDigits; i < kDigits; i++) {
+ lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
+ }
+ double dValue = (double) lValue;
+ int exp = decExponent - kDigits;
+ //
+ // lValue now contains a long integer with the value of
+ // the first kDigits digits of the number.
+ // dValue contains the (double) of the same.
+ //
+
+ if (nDigits <= MAX_DECIMAL_DIGITS) {
+ //
+ // possibly an easy case.
+ // We know that the digits can be represented
+ // exactly. And if the exponent isn't too outrageous,
+ // the whole thing can be done with one operation,
+ // thus one rounding error.
+ // Note that all our constructors trim all leading and
+ // trailing zeros, so simple values (including zero)
+ // will always end up here
+ //
+ if (exp == 0 || dValue == 0.0) {
+ return (isNegative) ? -dValue : dValue; // small floating integer
+ }
+ else if (exp >= 0) {
+ if (exp <= MAX_SMALL_TEN) {
+ //
+ // Can get the answer with one operation,
+ // thus one roundoff.
+ //
+ double rValue = dValue * SMALL_10_POW[exp];
+ return (isNegative) ? -rValue : rValue;
+ }
+ int slop = MAX_DECIMAL_DIGITS - kDigits;
+ if (exp <= MAX_SMALL_TEN + slop) {
+ //
+ // We can multiply dValue by 10^(slop)
+ // and it is still "small" and exact.
+ // Then we can multiply by 10^(exp-slop)
+ // with one rounding.
+ //
+ dValue *= SMALL_10_POW[slop];
+ double rValue = dValue * SMALL_10_POW[exp - slop];
+ return (isNegative) ? -rValue : rValue;
+ }
+ //
+ // Else we have a hard case with a positive exp.
+ //
+ } else {
+ if (exp >= -MAX_SMALL_TEN) {
+ //
+ // Can get the answer in one division.
+ //
+ double rValue = dValue / SMALL_10_POW[-exp];
+ return (isNegative) ? -rValue : rValue;
+ }
+ //
+ // Else we have a hard case with a negative exp.
+ //
+ }
+ }
+
+ //
+ // Harder cases:
+ // The sum of digits plus exponent is greater than
+ // what we think we can do with one error.
+ //
+ // Start by approximating the right answer by,
+ // naively, scaling by powers of 10.
+ //
+ if (exp > 0) {
+ if (decExponent > MAX_DECIMAL_EXPONENT + 1) {
+ //
+ // Lets face it. This is going to be
+ // Infinity. Cut to the chase.
+ //
+ return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+ }
+ if ((exp & 15) != 0) {
+ dValue *= SMALL_10_POW[exp & 15];
+ }
+ if ((exp >>= 4) != 0) {
+ int j;
+ for (j = 0; exp > 1; j++, exp >>= 1) {
+ if ((exp & 1) != 0) {
+ dValue *= BIG_10_POW[j];
+ }
+ }
+ //
+ // The reason for the weird exp > 1 condition
+ // in the above loop was so that the last multiply
+ // would get unrolled. We handle it here.
+ // It could overflow.
+ //
+ double t = dValue * BIG_10_POW[j];
+ if (Double.isInfinite(t)) {
+ //
+ // It did overflow.
+ // Look more closely at the result.
+ // If the exponent is just one too large,
+ // then use the maximum finite as our estimate
+ // value. Else call the result infinity
+ // and punt it.
+ // ( I presume this could happen because
+ // rounding forces the result here to be
+ // an ULP or two larger than
+ // Double.MAX_VALUE ).
+ //
+ t = dValue / 2.0;
+ t *= BIG_10_POW[j];
+ if (Double.isInfinite(t)) {
+ return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+ }
+ t = Double.MAX_VALUE;
+ }
+ dValue = t;
+ }
+ } else if (exp < 0) {
+ exp = -exp;
+ if (decExponent < MIN_DECIMAL_EXPONENT - 1) {
+ //
+ // Lets face it. This is going to be
+ // zero. Cut to the chase.
+ //
+ return (isNegative) ? -0.0 : 0.0;
+ }
+ if ((exp & 15) != 0) {
+ dValue /= SMALL_10_POW[exp & 15];
+ }
+ if ((exp >>= 4) != 0) {
+ int j;
+ for (j = 0; exp > 1; j++, exp >>= 1) {
+ if ((exp & 1) != 0) {
+ dValue *= TINY_10_POW[j];
+ }
+ }
+ //
+ // The reason for the weird exp > 1 condition
+ // in the above loop was so that the last multiply
+ // would get unrolled. We handle it here.
+ // It could underflow.
+ //
+ double t = dValue * TINY_10_POW[j];
+ if (t == 0.0) {
+ //
+ // It did underflow.
+ // Look more closely at the result.
+ // If the exponent is just one too small,
+ // then use the minimum finite as our estimate
+ // value. Else call the result 0.0
+ // and punt it.
+ // ( I presume this could happen because
+ // rounding forces the result here to be
+ // an ULP or two less than
+ // Double.MIN_VALUE ).
+ //
+ t = dValue * 2.0;
+ t *= TINY_10_POW[j];
+ if (t == 0.0) {
+ return (isNegative) ? -0.0 : 0.0;
+ }
+ t = Double.MIN_VALUE;
+ }
+ dValue = t;
+ }
+ }
+
+ //
+ // dValue is now approximately the result.
+ // The hard part is adjusting it, by comparison
+ // with FDBigInteger arithmetic.
+ // Formulate the EXACT big-number result as
+ // bigD0 * 10^exp
+ //
+ if (nDigits > MAX_NDIGITS) {
+ nDigits = MAX_NDIGITS + 1;
+ digits[MAX_NDIGITS] = '1';
+ }
+ FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits);
+ exp = decExponent - nDigits;
+
+ long ieeeBits = Double.doubleToRawLongBits(dValue); // IEEE-754 bits of double candidate
+ final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
+ final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
+ bigD0 = bigD0.multByPow52(D5, 0);
+ bigD0.makeImmutable(); // prevent bigD0 modification inside correctionLoop
+ FDBigInteger bigD = null;
+ int prevD2 = 0;
+
+ correctionLoop:
+ while (true) {
+ // here ieeeBits can't be NaN, Infinity or zero
+ int binexp = (int) (ieeeBits >>> EXP_SHIFT);
+ long bigBbits = ieeeBits & DoubleConsts.SIGNIF_BIT_MASK;
+ if (binexp > 0) {
+ bigBbits |= FRACT_HOB;
+ } else { // Normalize denormalized numbers.
+ assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0)
+ int leadingZeros = Long.numberOfLeadingZeros(bigBbits);
+ int shift = leadingZeros - (63 - EXP_SHIFT);
+ bigBbits <<= shift;
+ binexp = 1 - shift;
+ }
+ binexp -= DoubleConsts.EXP_BIAS;
+ int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits);
+ bigBbits >>>= lowOrderZeros;
+ final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros;
+ final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros;
+
+ //
+ // Scale bigD, bigB appropriately for
+ // big-integer operations.
+ // Naively, we multiply by powers of ten
+ // and powers of two. What we actually do
+ // is keep track of the powers of 5 and
+ // powers of 2 we would use, then factor out
+ // common divisors before doing the work.
+ //
+ int B2 = B5; // powers of 2 in bigB
+ int D2 = D5; // powers of 2 in bigD
+ int Ulp2; // powers of 2 in halfUlp.
+ if (bigIntExp >= 0) {
+ B2 += bigIntExp;
+ } else {
+ D2 -= bigIntExp;
+ }
+ Ulp2 = B2;
+ // shift bigB and bigD left by a number s. t.
+ // halfUlp is still an integer.
+ int hulpbias;
+ if (binexp <= -DoubleConsts.EXP_BIAS) {
+ // This is going to be a denormalized number
+ // (if not actually zero).
+ // half an ULP is at 2^-(DoubleConsts.EXP_BIAS+EXP_SHIFT+1)
+ hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS;
+ } else {
+ hulpbias = 1 + lowOrderZeros;
+ }
+ B2 += hulpbias;
+ D2 += hulpbias;
+ // if there are common factors of 2, we might just as well
+ // factor them out, as they add nothing useful.
+ int common2 = Math.min(B2, Math.min(D2, Ulp2));
+ B2 -= common2;
+ D2 -= common2;
+ Ulp2 -= common2;
+ // do multiplications by powers of 5 and 2
+ FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
+ if (bigD == null || prevD2 != D2) {
+ bigD = bigD0.leftShift(D2);
+ prevD2 = D2;
+ }
+ //
+ // to recap:
+ // bigB is the scaled-big-int version of our floating-point
+ // candidate.
+ // bigD is the scaled-big-int version of the exact value
+ // as we understand it.
+ // halfUlp is 1/2 an ulp of bigB, except for special cases
+ // of exact powers of 2
+ //
+ // the plan is to compare bigB with bigD, and if the difference
+ // is less than halfUlp, then we're satisfied. Otherwise,
+ // use the ratio of difference to halfUlp to calculate a fudge
+ // factor to add to the floating value, then go 'round again.
+ //
+ FDBigInteger diff;
+ int cmpResult;
+ boolean overvalue;
+ if ((cmpResult = bigB.cmp(bigD)) > 0) {
+ overvalue = true; // our candidate is too big.
+ diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
+ if ((bigIntNBits == 1) && (bigIntExp > -DoubleConsts.EXP_BIAS + 1)) {
+ // candidate is a normalized exact power of 2 and
+ // is too big (larger than Double.MIN_NORMAL). We will be subtracting.
+ // For our purposes, ulp is the ulp of the
+ // next smaller range.
+ Ulp2 -= 1;
+ if (Ulp2 < 0) {
+ // rats. Cannot de-scale ulp this far.
+ // must scale diff in other direction.
+ Ulp2 = 0;
+ diff = diff.leftShift(1);
+ }
+ }
+ } else if (cmpResult < 0) {
+ overvalue = false; // our candidate is too small.
+ diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
+ } else {
+ // the candidate is exactly right!
+ // this happens with surprising frequency
+ break correctionLoop;
+ }
+ cmpResult = diff.cmpPow52(B5, Ulp2);
+ if ((cmpResult) < 0) {
+ // difference is small.
+ // this is close enough
+ break correctionLoop;
+ } else if (cmpResult == 0) {
+ // difference is exactly half an ULP
+ // round to some other value maybe, then finish
+ if ((ieeeBits & 1) != 0) { // half ties to even
+ ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+ }
+ break correctionLoop;
+ } else {
+ // difference is non-trivial.
+ // could scale addend by ratio of difference to
+ // halfUlp here, if we bothered to compute that difference.
+ // Most of the time ( I hope ) it is about 1 anyway.
+ ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+ if (ieeeBits == 0 || ieeeBits == DoubleConsts.EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY
+ break correctionLoop; // oops. Fell off end of range.
+ }
+ continue; // try again.
+ }
+
+ }
+ if (isNegative) {
+ ieeeBits |= DoubleConsts.SIGN_BIT_MASK;
+ }
+ return Double.longBitsToDouble(ieeeBits);
+ }
+
+ /**
+ * Takes a FloatingDecimal, which we presumably just scanned in,
+ * and finds out what its value is, as a float.
+ * This is distinct from doubleValue() to avoid the extremely
+ * unlikely case of a double rounding error, wherein the conversion
+ * to double has one rounding error, and the conversion of that double
+ * to a float has another rounding error, IN THE WRONG DIRECTION,
+ * ( because of the preference to a zero low-order bit ).
+ */
+ @Override
+ public float floatValue() {
+ int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1);
+ //
+ // convert the lead kDigits to an integer.
+ //
+ int iValue = (int) digits[0] - (int) '0';
+ for (int i = 1; i < kDigits; i++) {
+ iValue = iValue * 10 + (int) digits[i] - (int) '0';
+ }
+ float fValue = (float) iValue;
+ int exp = decExponent - kDigits;
+ //
+ // iValue now contains an integer with the value of
+ // the first kDigits digits of the number.
+ // fValue contains the (float) of the same.
+ //
+
+ if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) {
+ //
+ // possibly an easy case.
+ // We know that the digits can be represented
+ // exactly. And if the exponent isn't too outrageous,
+ // the whole thing can be done with one operation,
+ // thus one rounding error.
+ // Note that all our constructors trim all leading and
+ // trailing zeros, so simple values (including zero)
+ // will always end up here.
+ //
+ if (exp == 0 || fValue == 0.0f) {
+ return (isNegative) ? -fValue : fValue; // small floating integer
+ } else if (exp >= 0) {
+ if (exp <= SINGLE_MAX_SMALL_TEN) {
+ //
+ // Can get the answer with one operation,
+ // thus one roundoff.
+ //
+ fValue *= SINGLE_SMALL_10_POW[exp];
+ return (isNegative) ? -fValue : fValue;
+ }
+ int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits;
+ if (exp <= SINGLE_MAX_SMALL_TEN + slop) {
+ //
+ // We can multiply fValue by 10^(slop)
+ // and it is still "small" and exact.
+ // Then we can multiply by 10^(exp-slop)
+ // with one rounding.
+ //
+ fValue *= SINGLE_SMALL_10_POW[slop];
+ fValue *= SINGLE_SMALL_10_POW[exp - slop];
+ return (isNegative) ? -fValue : fValue;
+ }
+ //
+ // Else we have a hard case with a positive exp.
+ //
+ } else {
+ if (exp >= -SINGLE_MAX_SMALL_TEN) {
+ //
+ // Can get the answer in one division.
+ //
+ fValue /= SINGLE_SMALL_10_POW[-exp];
+ return (isNegative) ? -fValue : fValue;
+ }
+ //
+ // Else we have a hard case with a negative exp.
+ //
+ }
+ } else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) {
+ //
+ // In double-precision, this is an exact floating integer.
+ // So we can compute to double, then shorten to float
+ // with one round, and get the right answer.
+ //
+ // First, finish accumulating digits.
+ // Then convert that integer to a double, multiply
+ // by the appropriate power of ten, and convert to float.
+ //
+ long lValue = (long) iValue;
+ for (int i = kDigits; i < nDigits; i++) {
+ lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0');
+ }
+ double dValue = (double) lValue;
+ exp = decExponent - nDigits;
+ dValue *= SMALL_10_POW[exp];
+ fValue = (float) dValue;
+ return (isNegative) ? -fValue : fValue;
+
+ }
+ //
+ // Harder cases:
+ // The sum of digits plus exponent is greater than
+ // what we think we can do with one error.
+ //
+ // Start by approximating the right answer by,
+ // naively, scaling by powers of 10.
+ // Scaling uses doubles to avoid overflow/underflow.
+ //
+ double dValue = fValue;
+ if (exp > 0) {
+ if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) {
+ //
+ // Lets face it. This is going to be
+ // Infinity. Cut to the chase.
+ //
+ return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+ }
+ if ((exp & 15) != 0) {
+ dValue *= SMALL_10_POW[exp & 15];
+ }
+ if ((exp >>= 4) != 0) {
+ int j;
+ for (j = 0; exp > 0; j++, exp >>= 1) {
+ if ((exp & 1) != 0) {
+ dValue *= BIG_10_POW[j];
+ }
+ }
+ }
+ } else if (exp < 0) {
+ exp = -exp;
+ if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) {
+ //
+ // Lets face it. This is going to be
+ // zero. Cut to the chase.
+ //
+ return (isNegative) ? -0.0f : 0.0f;
+ }
+ if ((exp & 15) != 0) {
+ dValue /= SMALL_10_POW[exp & 15];
+ }
+ if ((exp >>= 4) != 0) {
+ int j;
+ for (j = 0; exp > 0; j++, exp >>= 1) {
+ if ((exp & 1) != 0) {
+ dValue *= TINY_10_POW[j];
+ }
+ }
+ }
+ }
+ fValue = Math.max(Float.MIN_VALUE, Math.min(Float.MAX_VALUE, (float) dValue));
+
+ //
+ // fValue is now approximately the result.
+ // The hard part is adjusting it, by comparison
+ // with FDBigInteger arithmetic.
+ // Formulate the EXACT big-number result as
+ // bigD0 * 10^exp
+ //
+ if (nDigits > SINGLE_MAX_NDIGITS) {
+ nDigits = SINGLE_MAX_NDIGITS + 1;
+ digits[SINGLE_MAX_NDIGITS] = '1';
+ }
+ FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits);
+ exp = decExponent - nDigits;
+
+ int ieeeBits = Float.floatToRawIntBits(fValue); // IEEE-754 bits of float candidate
+ final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop
+ final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop
+ bigD0 = bigD0.multByPow52(D5, 0);
+ bigD0.makeImmutable(); // prevent bigD0 modification inside correctionLoop
+ FDBigInteger bigD = null;
+ int prevD2 = 0;
+
+ correctionLoop:
+ while (true) {
+ // here ieeeBits can't be NaN, Infinity or zero
+ int binexp = ieeeBits >>> SINGLE_EXP_SHIFT;
+ int bigBbits = ieeeBits & FloatConsts.SIGNIF_BIT_MASK;
+ if (binexp > 0) {
+ bigBbits |= SINGLE_FRACT_HOB;
+ } else { // Normalize denormalized numbers.
+ assert bigBbits != 0 : bigBbits; // floatToBigInt(0.0)
+ int leadingZeros = Integer.numberOfLeadingZeros(bigBbits);
+ int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT);
+ bigBbits <<= shift;
+ binexp = 1 - shift;
+ }
+ binexp -= FloatConsts.EXP_BIAS;
+ int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits);
+ bigBbits >>>= lowOrderZeros;
+ final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros;
+ final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros;
+
+ //
+ // Scale bigD, bigB appropriately for
+ // big-integer operations.
+ // Naively, we multiply by powers of ten
+ // and powers of two. What we actually do
+ // is keep track of the powers of 5 and
+ // powers of 2 we would use, then factor out
+ // common divisors before doing the work.
+ //
+ int B2 = B5; // powers of 2 in bigB
+ int D2 = D5; // powers of 2 in bigD
+ int Ulp2; // powers of 2 in halfUlp.
+ if (bigIntExp >= 0) {
+ B2 += bigIntExp;
+ } else {
+ D2 -= bigIntExp;
+ }
+ Ulp2 = B2;
+ // shift bigB and bigD left by a number s. t.
+ // halfUlp is still an integer.
+ int hulpbias;
+ if (binexp <= -FloatConsts.EXP_BIAS) {
+ // This is going to be a denormalized number
+ // (if not actually zero).
+ // half an ULP is at 2^-(FloatConsts.EXP_BIAS+SINGLE_EXP_SHIFT+1)
+ hulpbias = binexp + lowOrderZeros + FloatConsts.EXP_BIAS;
+ } else {
+ hulpbias = 1 + lowOrderZeros;
+ }
+ B2 += hulpbias;
+ D2 += hulpbias;
+ // if there are common factors of 2, we might just as well
+ // factor them out, as they add nothing useful.
+ int common2 = Math.min(B2, Math.min(D2, Ulp2));
+ B2 -= common2;
+ D2 -= common2;
+ Ulp2 -= common2;
+ // do multiplications by powers of 5 and 2
+ FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2);
+ if (bigD == null || prevD2 != D2) {
+ bigD = bigD0.leftShift(D2);
+ prevD2 = D2;
+ }
+ //
+ // to recap:
+ // bigB is the scaled-big-int version of our floating-point
+ // candidate.
+ // bigD is the scaled-big-int version of the exact value
+ // as we understand it.
+ // halfUlp is 1/2 an ulp of bigB, except for special cases
+ // of exact powers of 2
+ //
+ // the plan is to compare bigB with bigD, and if the difference
+ // is less than halfUlp, then we're satisfied. Otherwise,
+ // use the ratio of difference to halfUlp to calculate a fudge
+ // factor to add to the floating value, then go 'round again.
+ //
+ FDBigInteger diff;
+ int cmpResult;
+ boolean overvalue;
+ if ((cmpResult = bigB.cmp(bigD)) > 0) {
+ overvalue = true; // our candidate is too big.
+ diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse
+ if ((bigIntNBits == 1) && (bigIntExp > -FloatConsts.EXP_BIAS + 1)) {
+ // candidate is a normalized exact power of 2 and
+ // is too big (larger than Float.MIN_NORMAL). We will be subtracting.
+ // For our purposes, ulp is the ulp of the
+ // next smaller range.
+ Ulp2 -= 1;
+ if (Ulp2 < 0) {
+ // rats. Cannot de-scale ulp this far.
+ // must scale diff in other direction.
+ Ulp2 = 0;
+ diff = diff.leftShift(1);
+ }
+ }
+ } else if (cmpResult < 0) {
+ overvalue = false; // our candidate is too small.
+ diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse
+ } else {
+ // the candidate is exactly right!
+ // this happens with surprising frequency
+ break correctionLoop;
+ }
+ cmpResult = diff.cmpPow52(B5, Ulp2);
+ if ((cmpResult) < 0) {
+ // difference is small.
+ // this is close enough
+ break correctionLoop;
+ } else if (cmpResult == 0) {
+ // difference is exactly half an ULP
+ // round to some other value maybe, then finish
+ if ((ieeeBits & 1) != 0) { // half ties to even
+ ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+ }
+ break correctionLoop;
+ } else {
+ // difference is non-trivial.
+ // could scale addend by ratio of difference to
+ // halfUlp here, if we bothered to compute that difference.
+ // Most of the time ( I hope ) it is about 1 anyway.
+ ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp
+ if (ieeeBits == 0 || ieeeBits == FloatConsts.EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY
+ break correctionLoop; // oops. Fell off end of range.
+ }
+ continue; // try again.
+ }
+
+ }
+ if (isNegative) {
+ ieeeBits |= FloatConsts.SIGN_BIT_MASK;
+ }
+ return Float.intBitsToFloat(ieeeBits);
+ }
+
+
+ /**
+ * All the positive powers of 10 that can be
+ * represented exactly in double/float.
+ */
+ private static final double[] SMALL_10_POW = {
+ 1.0e0,
+ 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
+ 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
+ 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
+ 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
+ 1.0e21, 1.0e22
+ };
+
+ private static final float[] SINGLE_SMALL_10_POW = {
+ 1.0e0f,
+ 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
+ 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
+ };
+
+ private static final double[] BIG_10_POW = {
+ 1e16, 1e32, 1e64, 1e128, 1e256 };
+ private static final double[] TINY_10_POW = {
+ 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
+
+ private static final int MAX_SMALL_TEN = SMALL_10_POW.length-1;
+ private static final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length-1;
+
+ }
+
+ /**
+ * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
+ * The returned object is a <code>ThreadLocal</code> variable of this class.
+ *
+ * @param d The double precision value to convert.
+ * @return The converter.
+ */
+ public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) {
+ return getBinaryToASCIIConverter(d, true);
+ }
+
+ /**
+ * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>.
+ * The returned object is a <code>ThreadLocal</code> variable of this class.
+ *
+ * @param d The double precision value to convert.
+ * @param isCompatibleFormat
+ * @return The converter.
+ */
+ static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) {
+ long dBits = Double.doubleToRawLongBits(d);
+ boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign
+ long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK;
+ int binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT );
+ // Discover obvious special cases of NaN and Infinity.
+ if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) {
+ if ( fractBits == 0L ){
+ return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
+ } else {
+ return B2AC_NOT_A_NUMBER;
+ }
+ }
+ // Finish unpacking
+ // Normalize denormalized numbers.
+ // Insert assumed high-order bit for normalized numbers.
+ // Subtract exponent bias.
+ int nSignificantBits;
+ if ( binExp == 0 ){
+ if ( fractBits == 0L ){
+ // not a denorm, just a 0!
+ return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
+ }
+ int leadingZeros = Long.numberOfLeadingZeros(fractBits);
+ int shift = leadingZeros-(63-EXP_SHIFT);
+ fractBits <<= shift;
+ binExp = 1 - shift;
+ nSignificantBits = 64-leadingZeros; // recall binExp is - shift count.
+ } else {
+ fractBits |= FRACT_HOB;
+ nSignificantBits = EXP_SHIFT+1;
+ }
+ binExp -= DoubleConsts.EXP_BIAS;
+ BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+ buf.setSign(isNegative);
+ // call the routine that actually does all the hard work.
+ buf.dtoa(binExp, fractBits, nSignificantBits, isCompatibleFormat);
+ return buf;
+ }
+
+ private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) {
+ int fBits = Float.floatToRawIntBits( f );
+ boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0;
+ int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK;
+ int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT;
+ // Discover obvious special cases of NaN and Infinity.
+ if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) {
+ if ( fractBits == 0L ){
+ return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY;
+ } else {
+ return B2AC_NOT_A_NUMBER;
+ }
+ }
+ // Finish unpacking
+ // Normalize denormalized numbers.
+ // Insert assumed high-order bit for normalized numbers.
+ // Subtract exponent bias.
+ int nSignificantBits;
+ if ( binExp == 0 ){
+ if ( fractBits == 0 ){
+ // not a denorm, just a 0!
+ return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO;
+ }
+ int leadingZeros = Integer.numberOfLeadingZeros(fractBits);
+ int shift = leadingZeros-(31-SINGLE_EXP_SHIFT);
+ fractBits <<= shift;
+ binExp = 1 - shift;
+ nSignificantBits = 32 - leadingZeros; // recall binExp is - shift count.
+ } else {
+ fractBits |= SINGLE_FRACT_HOB;
+ nSignificantBits = SINGLE_EXP_SHIFT+1;
+ }
+ binExp -= FloatConsts.EXP_BIAS;
+ BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer();
+ buf.setSign(isNegative);
+ // call the routine that actually does all the hard work.
+ buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true);
+ return buf;
+ }
+
+ @SuppressWarnings("fallthrough")
+ static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException {
+ boolean isNegative = false;
+ boolean signSeen = false;
+ int decExp;
+ char c;
+
+ parseNumber:
+ try{
+ in = in.trim(); // don't fool around with white space.
+ // throws NullPointerException if null
+ int len = in.length();
+ if ( len == 0 ) {
+ throw new NumberFormatException("empty String");
+ }
+ int i = 0;
+ switch (in.charAt(i)){
+ case '-':
+ isNegative = true;
+ //FALLTHROUGH
+ case '+':
+ i++;
+ signSeen = true;
+ }
+ c = in.charAt(i);
+ if(c == 'N') { // Check for NaN
+ if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) {
+ return A2BC_NOT_A_NUMBER;
+ }
+ // something went wrong, throw exception
+ break parseNumber;
+ } else if(c == 'I') { // Check for Infinity strings
+ if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) {
+ return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+ }
+ // something went wrong, throw exception
+ break parseNumber;
+ } else if (c == '0') { // check for hexadecimal floating-point number
+ if (len > i+1 ) {
+ char ch = in.charAt(i+1);
+ if (ch == 'x' || ch == 'X' ) { // possible hex string
+ return parseHexString(in);
+ }
+ }
+ } // look for and process decimal floating-point string
+
+ char[] digits = new char[ len ];
+ int nDigits= 0;
+ boolean decSeen = false;
+ int decPt = 0;
+ int nLeadZero = 0;
+ int nTrailZero= 0;
+
+ skipLeadingZerosLoop:
+ while (i < len) {
+ c = in.charAt(i);
+ if (c == '0') {
+ nLeadZero++;
+ } else if (c == '.') {
+ if (decSeen) {
+ // already saw one ., this is the 2nd.
+ throw new NumberFormatException("multiple points");
+ }
+ decPt = i;
+ if (signSeen) {
+ decPt -= 1;
+ }
+ decSeen = true;
+ } else {
+ break skipLeadingZerosLoop;
+ }
+ i++;
+ }
+ digitLoop:
+ while (i < len) {
+ c = in.charAt(i);
+ if (c >= '1' && c <= '9') {
+ digits[nDigits++] = c;
+ nTrailZero = 0;
+ } else if (c == '0') {
+ digits[nDigits++] = c;
+ nTrailZero++;
+ } else if (c == '.') {
+ if (decSeen) {
+ // already saw one ., this is the 2nd.
+ throw new NumberFormatException("multiple points");
+ }
+ decPt = i;
+ if (signSeen) {
+ decPt -= 1;
+ }
+ decSeen = true;
+ } else {
+ break digitLoop;
+ }
+ i++;
+ }
+ nDigits -=nTrailZero;
+ //
+ // At this point, we've scanned all the digits and decimal
+ // point we're going to see. Trim off leading and trailing
+ // zeros, which will just confuse us later, and adjust
+ // our initial decimal exponent accordingly.
+ // To review:
+ // we have seen i total characters.
+ // nLeadZero of them were zeros before any other digits.
+ // nTrailZero of them were zeros after any other digits.
+ // if ( decSeen ), then a . was seen after decPt characters
+ // ( including leading zeros which have been discarded )
+ // nDigits characters were neither lead nor trailing
+ // zeros, nor point
+ //
+ //
+ // special hack: if we saw no non-zero digits, then the
+ // answer is zero!
+ // Unfortunately, we feel honor-bound to keep parsing!
+ //
+ boolean isZero = (nDigits == 0);
+ if ( isZero && nLeadZero == 0 ){
+ // we saw NO DIGITS AT ALL,
+ // not even a crummy 0!
+ // this is not allowed.
+ break parseNumber; // go throw exception
+ }
+ //
+ // Our initial exponent is decPt, adjusted by the number of
+ // discarded zeros. Or, if there was no decPt,
+ // then its just nDigits adjusted by discarded trailing zeros.
+ //
+ if ( decSeen ){
+ decExp = decPt - nLeadZero;
+ } else {
+ decExp = nDigits + nTrailZero;
+ }
+
+ //
+ // Look for 'e' or 'E' and an optionally signed integer.
+ //
+ if ( (i < len) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){
+ int expSign = 1;
+ int expVal = 0;
+ int reallyBig = Integer.MAX_VALUE / 10;
+ boolean expOverflow = false;
+ switch( in.charAt(++i) ){
+ case '-':
+ expSign = -1;
+ //FALLTHROUGH
+ case '+':
+ i++;
+ }
+ int expAt = i;
+ expLoop:
+ while ( i < len ){
+ if ( expVal >= reallyBig ){
+ // the next character will cause integer
+ // overflow.
+ expOverflow = true;
+ }
+ c = in.charAt(i++);
+ if(c>='0' && c<='9') {
+ expVal = expVal*10 + ( (int)c - (int)'0' );
+ } else {
+ i--; // back up.
+ break expLoop; // stop parsing exponent.
+ }
+ }
+ int expLimit = BIG_DECIMAL_EXPONENT+nDigits+nTrailZero;
+ if ( expOverflow || ( expVal > expLimit ) ){
+ //
+ // The intent here is to end up with
+ // infinity or zero, as appropriate.
+ // The reason for yielding such a small decExponent,
+ // rather than something intuitive such as
+ // expSign*Integer.MAX_VALUE, is that this value
+ // is subject to further manipulation in
+ // doubleValue() and floatValue(), and I don't want
+ // it to be able to cause overflow there!
+ // (The only way we can get into trouble here is for
+ // really outrageous nDigits+nTrailZero, such as 2 billion. )
+ //
+ decExp = expSign*expLimit;
+ } else {
+ // this should not overflow, since we tested
+ // for expVal > (MAX+N), where N >= abs(decExp)
+ decExp = decExp + expSign*expVal;
+ }
+
+ // if we saw something not a digit ( or end of string )
+ // after the [Ee][+-], without seeing any digits at all
+ // this is certainly an error. If we saw some digits,
+ // but then some trailing garbage, that might be ok.
+ // so we just fall through in that case.
+ // HUMBUG
+ if ( i == expAt ) {
+ break parseNumber; // certainly bad
+ }
+ }
+ //
+ // We parsed everything we could.
+ // If there are leftovers, then this is not good input!
+ //
+ if ( i < len &&
+ ((i != len - 1) ||
+ (in.charAt(i) != 'f' &&
+ in.charAt(i) != 'F' &&
+ in.charAt(i) != 'd' &&
+ in.charAt(i) != 'D'))) {
+ break parseNumber; // go throw exception
+ }
+ if(isZero) {
+ return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+ }
+ return new ASCIIToBinaryBuffer(isNegative, decExp, digits, nDigits);
+ } catch ( StringIndexOutOfBoundsException e ){ }
+ throw new NumberFormatException("For input string: \"" + in + "\"");
+ }
+
+ private static class HexFloatPattern {
+ /**
+ * Grammar is compatible with hexadecimal floating-point constants
+ * described in section 6.4.4.2 of the C99 specification.
+ */
+ private static final Pattern VALUE = Pattern.compile(
+ //1 234 56 7 8 9
+ "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?"
+ );
+ }
+
+ /**
+ * Converts string s to a suitable floating decimal; uses the
+ * double constructor and sets the roundDir variable appropriately
+ * in case the value is later converted to a float.
+ *
+ * @param s The <code>String</code> to parse.
+ */
+ static ASCIIToBinaryConverter parseHexString(String s) {
+ // Verify string is a member of the hexadecimal floating-point
+ // string language.
+ Matcher m = HexFloatPattern.VALUE.matcher(s);
+ boolean validInput = m.matches();
+ if (!validInput) {
+ // Input does not match pattern
+ throw new NumberFormatException("For input string: \"" + s + "\"");
+ } else { // validInput
+ //
+ // We must isolate the sign, significand, and exponent
+ // fields. The sign value is straightforward. Since
+ // floating-point numbers are stored with a normalized
+ // representation, the significand and exponent are
+ // interrelated.
+ //
+ // After extracting the sign, we normalized the
+ // significand as a hexadecimal value, calculating an
+ // exponent adjust for any shifts made during
+ // normalization. If the significand is zero, the
+ // exponent doesn't need to be examined since the output
+ // will be zero.
+ //
+ // Next the exponent in the input string is extracted.
+ // Afterwards, the significand is normalized as a *binary*
+ // value and the input value's normalized exponent can be
+ // computed. The significand bits are copied into a
+ // double significand; if the string has more logical bits
+ // than can fit in a double, the extra bits affect the
+ // round and sticky bits which are used to round the final
+ // value.
+ //
+ // Extract significand sign
+ String group1 = m.group(1);
+ boolean isNegative = ((group1 != null) && group1.equals("-"));
+
+ // Extract Significand magnitude
+ //
+ // Based on the form of the significand, calculate how the
+ // binary exponent needs to be adjusted to create a
+ // normalized//hexadecimal* floating-point number; that
+ // is, a number where there is one nonzero hex digit to
+ // the left of the (hexa)decimal point. Since we are
+ // adjusting a binary, not hexadecimal exponent, the
+ // exponent is adjusted by a multiple of 4.
+ //
+ // There are a number of significand scenarios to consider;
+ // letters are used in indicate nonzero digits:
+ //
+ // 1. 000xxxx => x.xxx normalized
+ // increase exponent by (number of x's - 1)*4
+ //
+ // 2. 000xxx.yyyy => x.xxyyyy normalized
+ // increase exponent by (number of x's - 1)*4
+ //
+ // 3. .000yyy => y.yy normalized
+ // decrease exponent by (number of zeros + 1)*4
+ //
+ // 4. 000.00000yyy => y.yy normalized
+ // decrease exponent by (number of zeros to right of point + 1)*4
+ //
+ // If the significand is exactly zero, return a properly
+ // signed zero.
+ //
+
+ String significandString = null;
+ int signifLength = 0;
+ int exponentAdjust = 0;
+ {
+ int leftDigits = 0; // number of meaningful digits to
+ // left of "decimal" point
+ // (leading zeros stripped)
+ int rightDigits = 0; // number of digits to right of
+ // "decimal" point; leading zeros
+ // must always be accounted for
+ //
+ // The significand is made up of either
+ //
+ // 1. group 4 entirely (integer portion only)
+ //
+ // OR
+ //
+ // 2. the fractional portion from group 7 plus any
+ // (optional) integer portions from group 6.
+ //
+ String group4;
+ if ((group4 = m.group(4)) != null) { // Integer-only significand
+ // Leading zeros never matter on the integer portion
+ significandString = stripLeadingZeros(group4);
+ leftDigits = significandString.length();
+ } else {
+ // Group 6 is the optional integer; leading zeros
+ // never matter on the integer portion
+ String group6 = stripLeadingZeros(m.group(6));
+ leftDigits = group6.length();
+
+ // fraction
+ String group7 = m.group(7);
+ rightDigits = group7.length();
+
+ // Turn "integer.fraction" into "integer"+"fraction"
+ significandString =
+ ((group6 == null) ? "" : group6) + // is the null
+ // check necessary?
+ group7;
+ }
+
+ significandString = stripLeadingZeros(significandString);
+ signifLength = significandString.length();
+
+ //
+ // Adjust exponent as described above
+ //
+ if (leftDigits >= 1) { // Cases 1 and 2
+ exponentAdjust = 4 * (leftDigits - 1);
+ } else { // Cases 3 and 4
+ exponentAdjust = -4 * (rightDigits - signifLength + 1);
+ }
+
+ // If the significand is zero, the exponent doesn't
+ // matter; return a properly signed zero.
+
+ if (signifLength == 0) { // Only zeros in input
+ return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+ }
+ }
+
+ // Extract Exponent
+ //
+ // Use an int to read in the exponent value; this should
+ // provide more than sufficient range for non-contrived
+ // inputs. If reading the exponent in as an int does
+ // overflow, examine the sign of the exponent and
+ // significand to determine what to do.
+ //
+ String group8 = m.group(8);
+ boolean positiveExponent = (group8 == null) || group8.equals("+");
+ long unsignedRawExponent;
+ try {
+ unsignedRawExponent = Integer.parseInt(m.group(9));
+ }
+ catch (NumberFormatException e) {
+ // At this point, we know the exponent is
+ // syntactically well-formed as a sequence of
+ // digits. Therefore, if an NumberFormatException
+ // is thrown, it must be due to overflowing int's
+ // range. Also, at this point, we have already
+ // checked for a zero significand. Thus the signs
+ // of the exponent and significand determine the
+ // final result:
+ //
+ // significand
+ // + -
+ // exponent + +infinity -infinity
+ // - +0.0 -0.0
+ return isNegative ?
+ (positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO)
+ : (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO);
+
+ }
+
+ long rawExponent =
+ (positiveExponent ? 1L : -1L) * // exponent sign
+ unsignedRawExponent; // exponent magnitude
+
+ // Calculate partially adjusted exponent
+ long exponent = rawExponent + exponentAdjust;
+
+ // Starting copying non-zero bits into proper position in
+ // a long; copy explicit bit too; this will be masked
+ // later for normal values.
+
+ boolean round = false;
+ boolean sticky = false;
+ int nextShift = 0;
+ long significand = 0L;
+ // First iteration is different, since we only copy
+ // from the leading significand bit; one more exponent
+ // adjust will be needed...
+
+ // IMPORTANT: make leadingDigit a long to avoid
+ // surprising shift semantics!
+ long leadingDigit = getHexDigit(significandString, 0);
+
+ //
+ // Left shift the leading digit (53 - (bit position of
+ // leading 1 in digit)); this sets the top bit of the
+ // significand to 1. The nextShift value is adjusted
+ // to take into account the number of bit positions of
+ // the leadingDigit actually used. Finally, the
+ // exponent is adjusted to normalize the significand
+ // as a binary value, not just a hex value.
+ //
+ if (leadingDigit == 1) {
+ significand |= leadingDigit << 52;
+ nextShift = 52 - 4;
+ // exponent += 0
+ } else if (leadingDigit <= 3) { // [2, 3]
+ significand |= leadingDigit << 51;
+ nextShift = 52 - 5;
+ exponent += 1;
+ } else if (leadingDigit <= 7) { // [4, 7]
+ significand |= leadingDigit << 50;
+ nextShift = 52 - 6;
+ exponent += 2;
+ } else if (leadingDigit <= 15) { // [8, f]
+ significand |= leadingDigit << 49;
+ nextShift = 52 - 7;
+ exponent += 3;
+ } else {
+ throw new AssertionError("Result from digit conversion too large!");
+ }
+ // The preceding if-else could be replaced by a single
+ // code block based on the high-order bit set in
+ // leadingDigit. Given leadingOnePosition,
+
+ // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition);
+ // nextShift = 52 - (3 + leadingOnePosition);
+ // exponent += (leadingOnePosition-1);
+
+ //
+ // Now the exponent variable is equal to the normalized
+ // binary exponent. Code below will make representation
+ // adjustments if the exponent is incremented after
+ // rounding (includes overflows to infinity) or if the
+ // result is subnormal.
+ //
+
+ // Copy digit into significand until the significand can't
+ // hold another full hex digit or there are no more input
+ // hex digits.
+ int i = 0;
+ for (i = 1;
+ i < signifLength && nextShift >= 0;
+ i++) {
+ long currentDigit = getHexDigit(significandString, i);
+ significand |= (currentDigit << nextShift);
+ nextShift -= 4;
+ }
+
+ // After the above loop, the bulk of the string is copied.
+ // Now, we must copy any partial hex digits into the
+ // significand AND compute the round bit and start computing
+ // sticky bit.
+
+ if (i < signifLength) { // at least one hex input digit exists
+ long currentDigit = getHexDigit(significandString, i);
+
+ // from nextShift, figure out how many bits need
+ // to be copied, if any
+ switch (nextShift) { // must be negative
+ case -1:
+ // three bits need to be copied in; can
+ // set round bit
+ significand |= ((currentDigit & 0xEL) >> 1);
+ round = (currentDigit & 0x1L) != 0L;
+ break;
+
+ case -2:
+ // two bits need to be copied in; can
+ // set round and start sticky
+ significand |= ((currentDigit & 0xCL) >> 2);
+ round = (currentDigit & 0x2L) != 0L;
+ sticky = (currentDigit & 0x1L) != 0;
+ break;
+
+ case -3:
+ // one bit needs to be copied in
+ significand |= ((currentDigit & 0x8L) >> 3);
+ // Now set round and start sticky, if possible
+ round = (currentDigit & 0x4L) != 0L;
+ sticky = (currentDigit & 0x3L) != 0;
+ break;
+
+ case -4:
+ // all bits copied into significand; set
+ // round and start sticky
+ round = ((currentDigit & 0x8L) != 0); // is top bit set?
+ // nonzeros in three low order bits?
+ sticky = (currentDigit & 0x7L) != 0;
+ break;
+
+ default:
+ throw new AssertionError("Unexpected shift distance remainder.");
+ // break;
+ }
+
+ // Round is set; sticky might be set.
+
+ // For the sticky bit, it suffices to check the
+ // current digit and test for any nonzero digits in
+ // the remaining unprocessed input.
+ i++;
+ while (i < signifLength && !sticky) {
+ currentDigit = getHexDigit(significandString, i);
+ sticky = sticky || (currentDigit != 0);
+ i++;
+ }
+
+ }
+ // else all of string was seen, round and sticky are
+ // correct as false.
+
+ // Float calculations
+ int floatBits = isNegative ? FloatConsts.SIGN_BIT_MASK : 0;
+ if (exponent >= FloatConsts.MIN_EXPONENT) {
+ if (exponent > FloatConsts.MAX_EXPONENT) {
+ // Float.POSITIVE_INFINITY
+ floatBits |= FloatConsts.EXP_BIT_MASK;
+ } else {
+ int threshShift = DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH - 1;
+ boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
+ int iValue = (int) (significand >>> threshShift);
+ if ((iValue & 3) != 1 || floatSticky) {
+ iValue++;
+ }
+ floatBits |= (((((int) exponent) + (FloatConsts.EXP_BIAS - 1))) << SINGLE_EXP_SHIFT) + (iValue >> 1);
+ }
+ } else {
+ if (exponent < FloatConsts.MIN_SUB_EXPONENT - 1) {
+ // 0
+ } else {
+ // exponent == -127 ==> threshShift = 53 - 2 + (-149) - (-127) = 53 - 24
+ int threshShift = (int) ((DoubleConsts.SIGNIFICAND_WIDTH - 2 + FloatConsts.MIN_SUB_EXPONENT) - exponent);
+ assert threshShift >= DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH;
+ assert threshShift < DoubleConsts.SIGNIFICAND_WIDTH;
+ boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky;
+ int iValue = (int) (significand >>> threshShift);
+ if ((iValue & 3) != 1 || floatSticky) {
+ iValue++;
+ }
+ floatBits |= iValue >> 1;
+ }
+ }
+ float fValue = Float.intBitsToFloat(floatBits);
+
+ // Check for overflow and update exponent accordingly.
+ if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result
+ // overflow to properly signed infinity
+ return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY;
+ } else { // Finite return value
+ if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result
+ exponent >= DoubleConsts.MIN_EXPONENT) {
+
+ // The result returned in this block cannot be a
+ // zero or subnormal; however after the
+ // significand is adjusted from rounding, we could
+ // still overflow in infinity.
+
+ // AND exponent bits into significand; if the
+ // significand is incremented and overflows from
+ // rounding, this combination will update the
+ // exponent correctly, even in the case of
+ // Double.MAX_VALUE overflowing to infinity.
+
+ significand = ((( exponent +
+ (long) DoubleConsts.EXP_BIAS) <<
+ (DoubleConsts.SIGNIFICAND_WIDTH - 1))
+ & DoubleConsts.EXP_BIT_MASK) |
+ (DoubleConsts.SIGNIF_BIT_MASK & significand);
+
+ } else { // Subnormal or zero
+ // (exponent < DoubleConsts.MIN_EXPONENT)
+
+ if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) {
+ // No way to round back to nonzero value
+ // regardless of significand if the exponent is
+ // less than -1075.
+ return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO;
+ } else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023
+ //
+ // Find bit position to round to; recompute
+ // round and sticky bits, and shift
+ // significand right appropriately.
+ //
+
+ sticky = sticky || round;
+ round = false;
+
+ // Number of bits of significand to preserve is
+ // exponent - abs_min_exp +1
+ // check:
+ // -1075 +1074 + 1 = 0
+ // -1023 +1074 + 1 = 52
+
+ int bitsDiscarded = 53 -
+ ((int) exponent - DoubleConsts.MIN_SUB_EXPONENT + 1);
+ assert bitsDiscarded >= 1 && bitsDiscarded <= 53;
+
+ // What to do here:
+ // First, isolate the new round bit
+ round = (significand & (1L << (bitsDiscarded - 1))) != 0L;
+ if (bitsDiscarded > 1) {
+ // create mask to update sticky bits; low
+ // order bitsDiscarded bits should be 1
+ long mask = ~((~0L) << (bitsDiscarded - 1));
+ sticky = sticky || ((significand & mask) != 0L);
+ }
+
+ // Now, discard the bits
+ significand = significand >> bitsDiscarded;
+
+ significand = ((((long) (DoubleConsts.MIN_EXPONENT - 1) + // subnorm exp.
+ (long) DoubleConsts.EXP_BIAS) <<
+ (DoubleConsts.SIGNIFICAND_WIDTH - 1))
+ & DoubleConsts.EXP_BIT_MASK) |
+ (DoubleConsts.SIGNIF_BIT_MASK & significand);
+ }
+ }
+
+ // The significand variable now contains the currently
+ // appropriate exponent bits too.
+
+ //
+ // Determine if significand should be incremented;
+ // making this determination depends on the least
+ // significant bit and the round and sticky bits.
+ //
+ // Round to nearest even rounding table, adapted from
+ // table 4.7 in "Computer Arithmetic" by IsraelKoren.
+ // The digit to the left of the "decimal" point is the
+ // least significant bit, the digits to the right of
+ // the point are the round and sticky bits
+ //
+ // Number Round(x)
+ // x0.00 x0.
+ // x0.01 x0.
+ // x0.10 x0.
+ // x0.11 x1. = x0. +1
+ // x1.00 x1.
+ // x1.01 x1.
+ // x1.10 x1. + 1
+ // x1.11 x1. + 1
+ //
+ boolean leastZero = ((significand & 1L) == 0L);
+ if ((leastZero && round && sticky) ||
+ ((!leastZero) && round)) {
+ significand++;
+ }
+
+ double value = isNegative ?
+ Double.longBitsToDouble(significand | DoubleConsts.SIGN_BIT_MASK) :
+ Double.longBitsToDouble(significand );
+
+ return new PreparedASCIIToBinaryBuffer(value, fValue);
+ }
+ }
+ }
+
+ /**
+ * Returns <code>s</code> with any leading zeros removed.
+ */
+ static String stripLeadingZeros(String s) {
+// return s.replaceFirst("^0+", "");
+ if(!s.isEmpty() && s.charAt(0)=='0') {
+ for(int i=1; i<s.length(); i++) {
+ if(s.charAt(i)!='0') {
+ return s.substring(i);
+ }
+ }
+ return "";
+ }
+ return s;
+ }
+
+ /**
+ * Extracts a hexadecimal digit from position <code>position</code>
+ * of string <code>s</code>.
+ */
+ static int getHexDigit(String s, int position) {
+ int value = Character.digit(s.charAt(position), 16);
+ if (value <= -1 || value >= 16) {
+ throw new AssertionError("Unexpected failure of digit conversion of " +
+ s.charAt(position));
+ }
+ return value;
+ }
+}
diff --git a/ojluni/src/main/java/sun/misc/FormattedFloatingDecimal.java b/ojluni/src/main/java/sun/misc/FormattedFloatingDecimal.java
old mode 100755
new mode 100644
index 0b6dd85..fc53920
--- a/ojluni/src/main/java/sun/misc/FormattedFloatingDecimal.java
+++ b/ojluni/src/main/java/sun/misc/FormattedFloatingDecimal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,961 +25,80 @@
package sun.misc;
-import sun.misc.FpUtils;
-import sun.misc.DoubleConsts;
-import sun.misc.FloatConsts;
-import java.util.regex.*;
+import java.util.Arrays;
public class FormattedFloatingDecimal{
- boolean isExceptional;
- boolean isNegative;
- int decExponent; // value set at construction, then immutable
- int decExponentRounded;
- char digits[];
- int nDigits;
- int bigIntExp;
- int bigIntNBits;
- boolean mustSetRoundDir = false;
- boolean fromHex = false;
- int roundDir = 0; // set by doubleValue
- int precision; // number of digits to the right of decimal
public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL };
- private Form form;
- private FormattedFloatingDecimal( boolean negSign, int decExponent, char []digits, int n, boolean e, int precision, Form form )
- {
- isNegative = negSign;
- isExceptional = e;
- this.decExponent = decExponent;
- this.digits = digits;
- this.nDigits = n;
- this.precision = precision;
- this.form = form;
+ public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){
+ FloatingDecimal.BinaryToASCIIConverter fdConverter =
+ FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE);
+ return new FormattedFloatingDecimal(precision,form, fdConverter);
}
- /*
- * Constants of the implementation
- * Most are IEEE-754 related.
- * (There are more really boring constants at the end.)
- */
- static final long signMask = 0x8000000000000000L;
- static final long expMask = 0x7ff0000000000000L;
- static final long fractMask= ~(signMask|expMask);
- static final int expShift = 52;
- static final int expBias = 1023;
- static final long fractHOB = ( 1L<<expShift ); // assumed High-Order bit
- static final long expOne = ((long)expBias)<<expShift; // exponent of 1.0
- static final int maxSmallBinExp = 62;
- static final int minSmallBinExp = -( 63 / 3 );
- static final int maxDecimalDigits = 15;
- static final int maxDecimalExponent = 308;
- static final int minDecimalExponent = -324;
- static final int bigDecimalExponent = 324; // i.e. abs(minDecimalExponent)
+ private int decExponentRounded;
+ private char[] mantissa;
+ private char[] exponent;
- static final long highbyte = 0xff00000000000000L;
- static final long highbit = 0x8000000000000000L;
- static final long lowbytes = ~highbyte;
-
- static final int singleSignMask = 0x80000000;
- static final int singleExpMask = 0x7f800000;
- static final int singleFractMask = ~(singleSignMask|singleExpMask);
- static final int singleExpShift = 23;
- static final int singleFractHOB = 1<<singleExpShift;
- static final int singleExpBias = 127;
- static final int singleMaxDecimalDigits = 7;
- static final int singleMaxDecimalExponent = 38;
- static final int singleMinDecimalExponent = -45;
-
- static final int intDecimalDigits = 9;
-
-
- /*
- * count number of bits from high-order 1 bit to low-order 1 bit,
- * inclusive.
- */
- private static int
- countBits( long v ){
- //
- // the strategy is to shift until we get a non-zero sign bit
- // then shift until we have no bits left, counting the difference.
- // we do byte shifting as a hack. Hope it helps.
- //
- if ( v == 0L ) return 0;
-
- while ( ( v & highbyte ) == 0L ){
- v <<= 8;
- }
- while ( v > 0L ) { // i.e. while ((v&highbit) == 0L )
- v <<= 1;
- }
-
- int n = 0;
- while (( v & lowbytes ) != 0L ){
- v <<= 8;
- n += 8;
- }
- while ( v != 0L ){
- v <<= 1;
- n += 1;
- }
- return n;
- }
-
- /*
- * Keep big powers of 5 handy for future reference.
- */
- private static FDBigInt b5p[];
-
- private static synchronized FDBigInt
- big5pow( int p ){
- assert p >= 0 : p; // negative power of 5
- if ( b5p == null ){
- b5p = new FDBigInt[ p+1 ];
- }else if (b5p.length <= p ){
- FDBigInt t[] = new FDBigInt[ p+1 ];
- System.arraycopy( b5p, 0, t, 0, b5p.length );
- b5p = t;
- }
- if ( b5p[p] != null )
- return b5p[p];
- else if ( p < small5pow.length )
- return b5p[p] = new FDBigInt( small5pow[p] );
- else if ( p < long5pow.length )
- return b5p[p] = new FDBigInt( long5pow[p] );
- else {
- // construct the value.
- // recursively.
- int q, r;
- // in order to compute 5^p,
- // compute its square root, 5^(p/2) and square.
- // or, let q = p / 2, r = p -q, then
- // 5^p = 5^(q+r) = 5^q * 5^r
- q = p >> 1;
- r = p - q;
- FDBigInt bigq = b5p[q];
- if ( bigq == null )
- bigq = big5pow ( q );
- if ( r < small5pow.length ){
- return (b5p[p] = bigq.mult( small5pow[r] ) );
- }else{
- FDBigInt bigr = b5p[ r ];
- if ( bigr == null )
- bigr = big5pow( r );
- return (b5p[p] = bigq.mult( bigr ) );
- }
- }
- }
-
- //
- // a common operation
- //
- private static FDBigInt
- multPow52( FDBigInt v, int p5, int p2 ){
- if ( p5 != 0 ){
- if ( p5 < small5pow.length ){
- v = v.mult( small5pow[p5] );
- } else {
- v = v.mult( big5pow( p5 ) );
- }
- }
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
- }
- return v;
- }
-
- //
- // another common operation
- //
- private static FDBigInt
- constructPow52( int p5, int p2 ){
- FDBigInt v = new FDBigInt( big5pow( p5 ) );
- if ( p2 != 0 ){
- v.lshiftMe( p2 );
- }
- return v;
- }
-
- /*
- * Make a floating double into a FDBigInt.
- * This could also be structured as a FDBigInt
- * constructor, but we'd have to build a lot of knowledge
- * about floating-point representation into it, and we don't want to.
- *
- * AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
- * bigIntExp and bigIntNBits
- *
- */
- private FDBigInt
- doubleToBigInt( double dval ){
- long lbits = Double.doubleToLongBits( dval ) & ~signMask;
- int binexp = (int)(lbits >>> expShift);
- lbits &= fractMask;
- if ( binexp > 0 ){
- lbits |= fractHOB;
- } else {
- assert lbits != 0L : lbits; // doubleToBigInt(0.0)
- binexp +=1;
- while ( (lbits & fractHOB ) == 0L){
- lbits <<= 1;
- binexp -= 1;
- }
- }
- binexp -= expBias;
- int nbits = countBits( lbits );
- /*
- * We now know where the high-order 1 bit is,
- * and we know how many there are.
- */
- int lowOrderZeros = expShift+1-nbits;
- lbits >>>= lowOrderZeros;
-
- bigIntExp = binexp+1-nbits;
- bigIntNBits = nbits;
- return new FDBigInt( lbits );
- }
-
- /*
- * Compute a number that is the ULP of the given value,
- * for purposes of addition/subtraction. Generally easy.
- * More difficult if subtracting and the argument
- * is a normalized a power of 2, as the ULP changes at these points.
- */
- private static double ulp( double dval, boolean subtracting ){
- long lbits = Double.doubleToLongBits( dval ) & ~signMask;
- int binexp = (int)(lbits >>> expShift);
- double ulpval;
- if ( subtracting && ( binexp >= expShift ) && ((lbits&fractMask) == 0L) ){
- // for subtraction from normalized, powers of 2,
- // use next-smaller exponent
- binexp -= 1;
- }
- if ( binexp > expShift ){
- ulpval = Double.longBitsToDouble( ((long)(binexp-expShift))<<expShift );
- } else if ( binexp == 0 ){
- ulpval = Double.MIN_VALUE;
- } else {
- ulpval = Double.longBitsToDouble( 1L<<(binexp-1) );
- }
- if ( subtracting ) ulpval = - ulpval;
-
- return ulpval;
- }
-
- /*
- * Round a double to a float.
- * In addition to the fraction bits of the double,
- * look at the class instance variable roundDir,
- * which should help us avoid double-rounding error.
- * roundDir was set in hardValueOf if the estimate was
- * close enough, but not exact. It tells us which direction
- * of rounding is preferred.
- */
- float
- stickyRound( double dval ){
- long lbits = Double.doubleToLongBits( dval );
- long binexp = lbits & expMask;
- if ( binexp == 0L || binexp == expMask ){
- // what we have here is special.
- // don't worry, the right thing will happen.
- return (float) dval;
- }
- lbits += (long)roundDir; // hack-o-matic.
- return (float)Double.longBitsToDouble( lbits );
- }
-
-
- /*
- * This is the easy subcase --
- * all the significant bits, after scaling, are held in lvalue.
- * negSign and decExponent tell us what processing and scaling
- * has already been done. Exceptional cases have already been
- * stripped out.
- * In particular:
- * lvalue is a finite number (not Inf, nor NaN)
- * lvalue > 0L (not zero, nor negative).
- *
- * The only reason that we develop the digits here, rather than
- * calling on Long.toString() is that we can do it a little faster,
- * and besides want to treat trailing 0s specially. If Long.toString
- * changes, we should re-evaluate this strategy!
- */
- private void
- developLongDigits( int decExponent, long lvalue, long insignificant ){
- char digits[];
- int ndigits;
- int digitno;
- int c;
- //
- // Discard non-significant low-order bits, while rounding,
- // up to insignificant value.
- int i;
- for ( i = 0; insignificant >= 10L; i++ )
- insignificant /= 10L;
- if ( i != 0 ){
- long pow10 = long5pow[i] << i; // 10^i == 5^i * 2^i;
- long residue = lvalue % pow10;
- lvalue /= pow10;
- decExponent += i;
- if ( residue >= (pow10>>1) ){
- // round up based on the low-order bits we're discarding
- lvalue++;
- }
- }
- if ( lvalue <= Integer.MAX_VALUE ){
- assert lvalue > 0L : lvalue; // lvalue <= 0
- // even easier subcase!
- // can do int arithmetic rather than long!
- int ivalue = (int)lvalue;
- ndigits = 10;
- digits = (char[])(perThreadBuffer.get());
- digitno = ndigits-1;
- c = ivalue%10;
- ivalue /= 10;
- while ( c == 0 ){
- decExponent++;
- c = ivalue%10;
- ivalue /= 10;
- }
- while ( ivalue != 0){
- digits[digitno--] = (char)(c+'0');
- decExponent++;
- c = ivalue%10;
- ivalue /= 10;
- }
- digits[digitno] = (char)(c+'0');
- } else {
- // same algorithm as above (same bugs, too )
- // but using long arithmetic.
- ndigits = 20;
- digits = (char[])(perThreadBuffer.get());
- digitno = ndigits-1;
- c = (int)(lvalue%10L);
- lvalue /= 10L;
- while ( c == 0 ){
- decExponent++;
- c = (int)(lvalue%10L);
- lvalue /= 10L;
- }
- while ( lvalue != 0L ){
- digits[digitno--] = (char)(c+'0');
- decExponent++;
- c = (int)(lvalue%10L);
- lvalue /= 10;
- }
- digits[digitno] = (char)(c+'0');
- }
- char result [];
- ndigits -= digitno;
- result = new char[ ndigits ];
- System.arraycopy( digits, digitno, result, 0, ndigits );
- this.digits = result;
- this.decExponent = decExponent+1;
- this.nDigits = ndigits;
- }
-
- //
- // add one to the least significant digit.
- // in the unlikely event there is a carry out,
- // deal with it.
- // assert that this will only happen where there
- // is only one digit, e.g. (float)1e-44 seems to do it.
- //
- private void
- roundup(){
- int i;
- int q = digits[ i = (nDigits-1)];
- if ( q == '9' ){
- while ( q == '9' && i > 0 ){
- digits[i] = '0';
- q = digits[--i];
- }
- if ( q == '9' ){
- // carryout! High-order 1, rest 0s, larger exp.
- decExponent += 1;
- digits[0] = '1';
- return;
- }
- // else fall through.
- }
- digits[i] = (char)(q+1);
- }
-
- // Given the desired number of digits predict the result's exponent.
- private int checkExponent(int length) {
- if (length >= nDigits || length < 0)
- return decExponent;
-
- for (int i = 0; i < length; i++)
- if (digits[i] != '9')
- // a '9' anywhere in digits will absorb the round
- return decExponent;
- return decExponent + (digits[length] >= '5' ? 1 : 0);
- }
-
- // Unlike roundup(), this method does not modify digits. It also
- // rounds at a particular precision.
- private char [] applyPrecision(int length) {
- char [] result = new char[nDigits];
- for (int i = 0; i < result.length; i++) result[i] = '0';
-
- if (length >= nDigits || length < 0) {
- // no rounding necessary
- System.arraycopy(digits, 0, result, 0, nDigits);
- return result;
- }
- if (length == 0) {
- // only one digit (0 or 1) is returned because the precision
- // excludes all significant digits
- if (digits[0] >= '5') {
- result[0] = '1';
- }
- return result;
- }
-
- int i = length;
- int q = digits[i];
- if (q >= '5' && i > 0) {
- q = digits[--i];
- if ( q == '9' ) {
- while ( q == '9' && i > 0 ){
- q = digits[--i];
+ private static final ThreadLocal<Object> threadLocalCharBuffer =
+ new ThreadLocal<Object>() {
+ @Override
+ protected Object initialValue() {
+ return new char[20];
}
- if ( q == '9' ){
- // carryout! High-order 1, rest 0s, larger exp.
- result[0] = '1';
- return result;
- }
- }
- result[i] = (char)(q + 1);
- }
- while (--i >= 0) {
- result[i] = digits[i];
- }
- return result;
+ };
+
+ private static char[] getBuffer(){
+ return (char[]) threadLocalCharBuffer.get();
}
- /*
- * FIRST IMPORTANT CONSTRUCTOR: DOUBLE
- */
- public FormattedFloatingDecimal( double d )
- {
- this(d, Integer.MAX_VALUE, Form.COMPATIBLE);
- }
-
- public FormattedFloatingDecimal( double d, int precision, Form form )
- {
- long dBits = Double.doubleToLongBits( d );
- long fractBits;
- int binExp;
- int nSignificantBits;
-
- this.precision = precision;
- this.form = form;
-
- // discover and delete sign
- if ( (dBits&signMask) != 0 ){
- isNegative = true;
- dBits ^= signMask;
- } else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (int)( (dBits&expMask) >> expShift );
- fractBits = dBits&fractMask;
- if ( binExp == (int)(expMask>>expShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
- }
- nDigits = digits.length;
+ private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) {
+ if (fdConverter.isExceptional()) {
+ this.mantissa = fdConverter.toJavaFormatString().toCharArray();
+ this.exponent = null;
return;
}
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0L ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- return;
- }
- while ( (fractBits&fractHOB) == 0L ){
- fractBits <<= 1;
- binExp -= 1;
- }
- nSignificantBits = expShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= fractHOB;
- nSignificantBits = expShift+1;
- }
- binExp -= expBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, fractBits, nSignificantBits );
- }
-
- /*
- * SECOND IMPORTANT CONSTRUCTOR: SINGLE
- */
- public FormattedFloatingDecimal( float f )
- {
- this(f, Integer.MAX_VALUE, Form.COMPATIBLE);
- }
- public FormattedFloatingDecimal( float f, int precision, Form form )
- {
- int fBits = Float.floatToIntBits( f );
- int fractBits;
- int binExp;
- int nSignificantBits;
-
- this.precision = precision;
- this.form = form;
-
- // discover and delete sign
- if ( (fBits&singleSignMask) != 0 ){
- isNegative = true;
- fBits ^= singleSignMask;
- } else {
- isNegative = false;
- }
- // Begin to unpack
- // Discover obvious special cases of NaN and Infinity.
- binExp = (int)( (fBits&singleExpMask) >> singleExpShift );
- fractBits = fBits&singleFractMask;
- if ( binExp == (int)(singleExpMask>>singleExpShift) ) {
- isExceptional = true;
- if ( fractBits == 0L ){
- digits = infinity;
- } else {
- digits = notANumber;
- isNegative = false; // NaN has no sign!
- }
- nDigits = digits.length;
- return;
- }
- isExceptional = false;
- // Finish unpacking
- // Normalize denormalized numbers.
- // Insert assumed high-order bit for normalized numbers.
- // Subtract exponent bias.
- if ( binExp == 0 ){
- if ( fractBits == 0 ){
- // not a denorm, just a 0!
- decExponent = 0;
- digits = zero;
- nDigits = 1;
- return;
- }
- while ( (fractBits&singleFractHOB) == 0 ){
- fractBits <<= 1;
- binExp -= 1;
- }
- nSignificantBits = singleExpShift + binExp +1; // recall binExp is - shift count.
- binExp += 1;
- } else {
- fractBits |= singleFractHOB;
- nSignificantBits = singleExpShift+1;
- }
- binExp -= singleExpBias;
- // call the routine that actually does all the hard work.
- dtoa( binExp, ((long)fractBits)<<(expShift-singleExpShift), nSignificantBits );
- }
-
- private void
- dtoa( int binExp, long fractBits, int nSignificantBits )
- {
- int nFractBits; // number of significant bits of fractBits;
- int nTinyBits; // number of these to the right of the point.
- int decExp;
-
- // Examine number. Determine if it is an easy case,
- // which we can do pretty trivially using float/long conversion,
- // or whether we must do real work.
- nFractBits = countBits( fractBits );
- nTinyBits = Math.max( 0, nFractBits - binExp - 1 );
- if ( binExp <= maxSmallBinExp && binExp >= minSmallBinExp ){
- // Look more closely at the number to decide if,
- // with scaling by 10^nTinyBits, the result will fit in
- // a long.
- if ( (nTinyBits < long5pow.length) && ((nFractBits + n5bits[nTinyBits]) < 64 ) ){
- /*
- * We can do this:
- * take the fraction bits, which are normalized.
- * (a) nTinyBits == 0: Shift left or right appropriately
- * to align the binary point at the extreme right, i.e.
- * where a long int point is expected to be. The integer
- * result is easily converted to a string.
- * (b) nTinyBits > 0: Shift right by expShift-nFractBits,
- * which effectively converts to long and scales by
- * 2^nTinyBits. Then multiply by 5^nTinyBits to
- * complete the scaling. We know this won't overflow
- * because we just counted the number of bits necessary
- * in the result. The integer you get from this can
- * then be converted to a string pretty easily.
- */
- long halfULP;
- if ( nTinyBits == 0 ) {
- if ( binExp > nSignificantBits ){
- halfULP = 1L << ( binExp-nSignificantBits-1);
- } else {
- halfULP = 0L;
- }
- if ( binExp >= expShift ){
- fractBits <<= (binExp-expShift);
- } else {
- fractBits >>>= (expShift-binExp) ;
- }
- developLongDigits( 0, fractBits, halfULP );
- return;
- }
- /*
- * The following causes excess digits to be printed
- * out in the single-float case. Our manipulation of
- * halfULP here is apparently not correct. If we
- * better understand how this works, perhaps we can
- * use this special case again. But for the time being,
- * we do not.
- * else {
- * fractBits >>>= expShift+1-nFractBits;
- * fractBits *= long5pow[ nTinyBits ];
- * halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits);
- * developLongDigits( -nTinyBits, fractBits, halfULP );
- * return;
- * }
- */
- }
- }
- /*
- * This is the hard case. We are going to compute large positive
- * integers B and S and integer decExp, s.t.
- * d = ( B / S ) * 10^decExp
- * 1 <= B / S < 10
- * Obvious choices are:
- * decExp = floor( log10(d) )
- * B = d * 2^nTinyBits * 10^max( 0, -decExp )
- * S = 10^max( 0, decExp) * 2^nTinyBits
- * (noting that nTinyBits has already been forced to non-negative)
- * I am also going to compute a large positive integer
- * M = (1/2^nSignificantBits) * 2^nTinyBits * 10^max( 0, -decExp )
- * i.e. M is (1/2) of the ULP of d, scaled like B.
- * When we iterate through dividing B/S and picking off the
- * quotient bits, we will know when to stop when the remainder
- * is <= M.
- *
- * We keep track of powers of 2 and powers of 5.
- */
-
- /*
- * Estimate decimal exponent. (If it is small-ish,
- * we could double-check.)
- *
- * First, scale the mantissa bits such that 1 <= d2 < 2.
- * We are then going to estimate
- * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5)
- * and so we can estimate
- * log10(d) ~=~ log10(d2) + binExp * log10(2)
- * take the floor and call it decExp.
- * FIXME -- use more precise constants here. It costs no more.
- */
- double d2 = Double.longBitsToDouble(
- expOne | ( fractBits &~ fractHOB ) );
- decExp = (int)Math.floor(
- (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981 );
- int B2, B5; // powers of 2 and powers of 5, respectively, in B
- int S2, S5; // powers of 2 and powers of 5, respectively, in S
- int M2, M5; // powers of 2 and powers of 5, respectively, in M
- int Bbits; // binary digits needed to represent B, approx.
- int tenSbits; // binary digits needed to represent 10*S, approx.
- FDBigInt Sval, Bval, Mval;
-
- B5 = Math.max( 0, -decExp );
- B2 = B5 + nTinyBits + binExp;
-
- S5 = Math.max( 0, decExp );
- S2 = S5 + nTinyBits;
-
- M5 = B5;
- M2 = B2 - nSignificantBits;
-
- /*
- * the long integer fractBits contains the (nFractBits) interesting
- * bits from the mantissa of d ( hidden 1 added if necessary) followed
- * by (expShift+1-nFractBits) zeros. In the interest of compactness,
- * I will shift out those zeros before turning fractBits into a
- * FDBigInt. The resulting whole number will be
- * d * 2^(nFractBits-1-binExp).
- */
- fractBits >>>= (expShift+1-nFractBits);
- B2 -= nFractBits-1;
- int common2factor = Math.min( B2, S2 );
- B2 -= common2factor;
- S2 -= common2factor;
- M2 -= common2factor;
-
- /*
- * HACK!! For exact powers of two, the next smallest number
- * is only half as far away as we think (because the meaning of
- * ULP changes at power-of-two bounds) for this reason, we
- * hack M2. Hope this works.
- */
- if ( nFractBits == 1 )
- M2 -= 1;
-
- if ( M2 < 0 ){
- // oops.
- // since we cannot scale M down far enough,
- // we must scale the other values up.
- B2 -= M2;
- S2 -= M2;
- M2 = 0;
- }
- /*
- * Construct, Scale, iterate.
- * Some day, we'll write a stopping test that takes
- * account of the assymetry of the spacing of floating-point
- * numbers below perfect powers of 2
- * 26 Sept 96 is not that day.
- * So we use a symmetric test.
- */
- char digits[] = this.digits = new char[18];
- int ndigit = 0;
- boolean low, high;
- long lowDigitDifference;
- int q;
-
- /*
- * Detect the special cases where all the numbers we are about
- * to compute will fit in int or long integers.
- * In these cases, we will avoid doing FDBigInt arithmetic.
- * We use the same algorithms, except that we "normalize"
- * our FDBigInts before iterating. This is to make division easier,
- * as it makes our fist guess (quotient of high-order words)
- * more accurate!
- *
- * Some day, we'll write a stopping test that takes
- * account of the assymetry of the spacing of floating-point
- * numbers below perfect powers of 2
- * 26 Sept 96 is not that day.
- * So we use a symmetric test.
- */
- Bbits = nFractBits + B2 + (( B5 < n5bits.length )? n5bits[B5] : ( B5*3 ));
- tenSbits = S2+1 + (( (S5+1) < n5bits.length )? n5bits[(S5+1)] : ( (S5+1)*3 ));
- if ( Bbits < 64 && tenSbits < 64){
- if ( Bbits < 32 && tenSbits < 32){
- // wa-hoo! They're all ints!
- int b = ((int)fractBits * small5pow[B5] ) << B2;
- int s = small5pow[S5] << S2;
- int m = small5pow[M5] << M2;
- int tens = s * 10;
- /*
- * Unroll the first iteration. If our decExp estimate
- * was too high, our first quotient will be zero. In this
- * case, we discard it and decrement decExp.
- */
- ndigit = 0;
- q = b / s;
- b = 10 * ( b % s );
- m *= 10;
- low = (b < m );
- high = (b+m > tens );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
+ char[] digits = getBuffer();
+ int nDigits = fdConverter.getDigits(digits);
+ int decExp = fdConverter.getDecimalExponent();
+ int exp;
+ boolean isNegative = fdConverter.isNegative();
+ switch (form) {
+ case COMPATIBLE:
+ exp = decExp;
+ this.decExponentRounded = exp;
+ fillCompatible(precision, digits, nDigits, exp, isNegative);
+ break;
+ case DECIMAL_FLOAT:
+ exp = applyPrecision(decExp, digits, nDigits, decExp + precision);
+ fillDecimal(precision, digits, nDigits, exp, isNegative);
+ this.decExponentRounded = exp;
+ break;
+ case SCIENTIFIC:
+ exp = applyPrecision(decExp, digits, nDigits, precision + 1);
+ fillScientific(precision, digits, nDigits, exp, isNegative);
+ this.decExponentRounded = exp;
+ break;
+ case GENERAL:
+ exp = applyPrecision(decExp, digits, nDigits, precision);
+ // adjust precision to be the number of digits to right of decimal
+ // the real exponent to be output is actually exp - 1, not exp
+ if (exp - 1 < -4 || exp - 1 >= precision) {
+ // form = Form.SCIENTIFIC;
+ precision--;
+ fillScientific(precision, digits, nDigits, exp, isNegative);
} else {
- digits[ndigit++] = (char)('0' + q);
+ // form = Form.DECIMAL_FLOAT;
+ precision = precision - exp;
+ fillDecimal(precision, digits, nDigits, exp, isNegative);
}
- /*
- * HACK! Java spec sez that we always have at least
- * one digit after the . in either F- or E-form output.
- * Thus we will need more than one digit if we're using
- * E-form
- */
- if (! (form == Form.COMPATIBLE && -3 < decExp && decExp < 8)) {
- high = low = false;
- }
- while( ! low && ! high ){
- q = b / s;
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- if ( m > 0L ){
- low = (b < m );
- high = (b+m > tens );
- } else {
- // hack -- m might overflow!
- // in this case, it is certainly > b,
- // which won't
- // and b+m > tens, too, since that has overflowed
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
- } else {
- // still good! they're all longs!
- long b = (fractBits * long5pow[B5] ) << B2;
- long s = long5pow[S5] << S2;
- long m = long5pow[M5] << M2;
- long tens = s * 10L;
- /*
- * Unroll the first iteration. If our decExp estimate
- * was too high, our first quotient will be zero. In this
- * case, we discard it and decrement decExp.
- */
- ndigit = 0;
- q = (int) ( b / s );
- b = 10L * ( b % s );
- m *= 10L;
- low = (b < m );
- high = (b+m > tens );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
- } else {
- digits[ndigit++] = (char)('0' + q);
- }
- /*
- * HACK! Java spec sez that we always have at least
- * one digit after the . in either F- or E-form output.
- * Thus we will need more than one digit if we're using
- * E-form
- */
- if (! (form == Form.COMPATIBLE && -3 < decExp && decExp < 8)) {
- high = low = false;
- }
- while( ! low && ! high ){
- q = (int) ( b / s );
- b = 10 * ( b % s );
- m *= 10;
- assert q < 10 : q; // excessively large digit
- if ( m > 0L ){
- low = (b < m );
- high = (b+m > tens );
- } else {
- // hack -- m might overflow!
- // in this case, it is certainly > b,
- // which won't
- // and b+m > tens, too, since that has overflowed
- // either!
- low = true;
- high = true;
- }
- digits[ndigit++] = (char)('0' + q);
- }
- lowDigitDifference = (b<<1) - tens;
- }
- } else {
- FDBigInt tenSval;
- int shiftBias;
-
- /*
- * We really must do FDBigInt arithmetic.
- * Fist, construct our FDBigInt initial values.
- */
- Bval = multPow52( new FDBigInt( fractBits ), B5, B2 );
- Sval = constructPow52( S5, S2 );
- Mval = constructPow52( M5, M2 );
-
-
- // normalize so that division works better
- Bval.lshiftMe( shiftBias = Sval.normalizeMe() );
- Mval.lshiftMe( shiftBias );
- tenSval = Sval.mult( 10 );
- /*
- * Unroll the first iteration. If our decExp estimate
- * was too high, our first quotient will be zero. In this
- * case, we discard it and decrement decExp.
- */
- ndigit = 0;
- q = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- assert q < 10 : q; // excessively large digit
- if ( (q == 0) && ! high ){
- // oops. Usually ignore leading zero.
- decExp--;
- } else {
- digits[ndigit++] = (char)('0' + q);
- }
- /*
- * HACK! Java spec sez that we always have at least
- * one digit after the . in either F- or E-form output.
- * Thus we will need more than one digit if we're using
- * E-form
- */
- if (! (form == Form.COMPATIBLE && -3 < decExp && decExp < 8)) {
- high = low = false;
- }
- while( ! low && ! high ){
- q = Bval.quoRemIteration( Sval );
- Mval = Mval.mult( 10 );
- assert q < 10 : q; // excessively large digit
- low = (Bval.cmp( Mval ) < 0);
- high = (Bval.add( Mval ).cmp( tenSval ) > 0 );
- digits[ndigit++] = (char)('0' + q);
- }
- if ( high && low ){
- Bval.lshiftMe(1);
- lowDigitDifference = Bval.cmp(tenSval);
- } else
- lowDigitDifference = 0L; // this here only for flow analysis!
+ this.decExponentRounded = exp;
+ break;
+ default:
+ assert false;
}
- this.decExponent = decExp+1;
- this.digits = digits;
- this.nDigits = ndigit;
- /*
- * Last digit gets rounded based on stopping condition.
- */
- if ( high ){
- if ( low ){
- if ( lowDigitDifference == 0L ){
- // it's a tie!
- // choose based on which digits we like.
- if ( (digits[nDigits-1]&1) != 0 ) roundup();
- } else if ( lowDigitDifference > 0 ){
- roundup();
- }
- } else {
- roundup();
- }
- }
- }
-
- public String
- toString(){
- // most brain-dead version
- StringBuffer result = new StringBuffer( nDigits+8 );
- if ( isNegative ){ result.append( '-' ); }
- if ( isExceptional ){
- result.append( digits, 0, nDigits );
- } else {
- result.append( "0.");
- result.append( digits, 0, nDigits );
- result.append('e');
- result.append( decExponent );
- }
- return new String(result);
- }
-
- // returns the exponent before rounding
- public int getExponent() {
- return decExponent - 1;
}
// returns the exponent after rounding has been done by applyPrecision
@@ -987,781 +106,244 @@
return decExponentRounded - 1;
}
- public int getChars(char[] result) {
- assert nDigits <= 19 : nDigits; // generous bound on size of nDigits
- int i = 0;
- if (isNegative) { result[0] = '-'; i = 1; }
- if (isExceptional) {
- System.arraycopy(digits, 0, result, i, nDigits);
- i += nDigits;
- } else {
- char digits [] = this.digits;
- int exp = decExponent;
- switch (form) {
- case COMPATIBLE:
- break;
- case DECIMAL_FLOAT:
- exp = checkExponent(decExponent + precision);
- digits = applyPrecision(decExponent + precision);
- break;
- case SCIENTIFIC:
- exp = checkExponent(precision + 1);
- digits = applyPrecision(precision + 1);
- break;
- case GENERAL:
- exp = checkExponent(precision);
- digits = applyPrecision(precision);
- // adjust precision to be the number of digits to right of decimal
- // the real exponent to be output is actually exp - 1, not exp
- if (exp - 1 < -4 || exp - 1 >= precision) {
- form = Form.SCIENTIFIC;
- precision--;
- } else {
- form = Form.DECIMAL_FLOAT;
- precision = precision - exp;
- }
- break;
- default:
- assert false;
- }
- decExponentRounded = exp;
+ public char[] getMantissa(){
+ return mantissa;
+ }
- if (exp > 0
- && ((form == Form.COMPATIBLE && (exp < 8))
- || (form == Form.DECIMAL_FLOAT)))
- {
- // print digits.digits.
- int charLength = Math.min(nDigits, exp);
- System.arraycopy(digits, 0, result, i, charLength);
- i += charLength;
- if (charLength < exp) {
- charLength = exp-charLength;
- for (int nz = 0; nz < charLength; nz++)
- result[i++] = '0';
- // Do not append ".0" for formatted floats since the user
- // may request that it be omitted. It is added as necessary
- // by the Formatter.
- if (form == Form.COMPATIBLE) {
- result[i++] = '.';
- result[i++] = '0';
- }
- } else {
- // Do not append ".0" for formatted floats since the user
- // may request that it be omitted. It is added as necessary
- // by the Formatter.
- if (form == Form.COMPATIBLE) {
- result[i++] = '.';
- if (charLength < nDigits) {
- int t = Math.min(nDigits - charLength, precision);
- System.arraycopy(digits, charLength, result, i, t);
- i += t;
- } else {
- result[i++] = '0';
- }
- } else {
- int t = Math.min(nDigits - charLength, precision);
- if (t > 0) {
- result[i++] = '.';
- System.arraycopy(digits, charLength, result, i, t);
- i += t;
- }
- }
- }
- } else if (exp <= 0
- && ((form == Form.COMPATIBLE && exp > -3)
- || (form == Form.DECIMAL_FLOAT)))
- {
- // print 0.0* digits
- result[i++] = '0';
- if (exp != 0) {
- // write '0' s before the significant digits
- int t = Math.min(-exp, precision);
- if (t > 0) {
- result[i++] = '.';
- for (int nz = 0; nz < t; nz++)
- result[i++] = '0';
- }
- }
- int t = Math.min(digits.length, precision + exp);
- if (t > 0) {
- if (i == 1)
- result[i++] = '.';
- // copy only when significant digits are within the precision
- System.arraycopy(digits, 0, result, i, t);
- i += t;
- }
+ public char[] getExponent(){
+ return exponent;
+ }
+
+ /**
+ * Returns new decExp in case of overflow.
+ */
+ private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) {
+ if (prec >= nDigits || prec < 0) {
+ // no rounding necessary
+ return decExp;
+ }
+ if (prec == 0) {
+ // only one digit (0 or 1) is returned because the precision
+ // excludes all significant digits
+ if (digits[0] >= '5') {
+ digits[0] = '1';
+ Arrays.fill(digits, 1, nDigits, '0');
+ return decExp + 1;
} else {
- result[i++] = digits[0];
- if (form == Form.COMPATIBLE) {
- result[i++] = '.';
- if (nDigits > 1) {
- System.arraycopy(digits, 1, result, i, nDigits-1);
- i += nDigits-1;
- } else {
- result[i++] = '0';
- }
- result[i++] = 'E';
- } else {
- if (nDigits > 1) {
- int t = Math.min(nDigits -1, precision);
- if (t > 0) {
- result[i++] = '.';
- System.arraycopy(digits, 1, result, i, t);
- i += t;
- }
- }
- result[i++] = 'e';
- }
- int e;
- if (exp <= 0) {
- result[i++] = '-';
- e = -exp+1;
- } else {
- if (form != Form.COMPATIBLE)
- result[i++] = '+';
- e = exp-1;
- }
- // decExponent has 1, 2, or 3, digits
- if (e <= 9) {
- if (form != Form.COMPATIBLE)
- result[i++] = '0';
- result[i++] = (char)(e+'0');
- } else if (e <= 99) {
- result[i++] = (char)(e/10 +'0');
- result[i++] = (char)(e%10 + '0');
- } else {
- result[i++] = (char)(e/100+'0');
- e %= 100;
- result[i++] = (char)(e/10+'0');
- result[i++] = (char)(e%10 + '0');
- }
+ Arrays.fill(digits, 0, nDigits, '0');
+ return decExp;
}
}
- return i;
+ int q = digits[prec];
+ if (q >= '5') {
+ int i = prec;
+ q = digits[--i];
+ if ( q == '9' ) {
+ while ( q == '9' && i > 0 ){
+ q = digits[--i];
+ }
+ if ( q == '9' ){
+ // carryout! High-order 1, rest 0s, larger exp.
+ digits[0] = '1';
+ Arrays.fill(digits, 1, nDigits, '0');
+ return decExp+1;
+ }
+ }
+ digits[i] = (char)(q + 1);
+ Arrays.fill(digits, i+1, nDigits, '0');
+ } else {
+ Arrays.fill(digits, prec, nDigits, '0');
+ }
+ return decExp;
}
- // Per-thread buffer for string/stringbuffer conversion
- private static ThreadLocal perThreadBuffer = new ThreadLocal() {
- protected synchronized Object initialValue() {
- return new char[26];
- }
- };
-
- /*
- * Take a FormattedFloatingDecimal, which we presumably just scanned in,
- * and find out what its value is, as a double.
- *
- * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED
- * ROUNDING DIRECTION in case the result is really destined
- * for a single-precision float.
+ /**
+ * Fills mantissa and exponent char arrays for compatible format.
*/
-
- public strictfp double doubleValue(){
- int kDigits = Math.min( nDigits, maxDecimalDigits+1 );
- long lValue;
- double dValue;
- double rValue, tValue;
-
- // First, check for NaN and Infinity values
- if(digits == infinity || digits == notANumber) {
- if(digits == notANumber)
- return Double.NaN;
- else
- return (isNegative?Double.NEGATIVE_INFINITY:Double.POSITIVE_INFINITY);
+ private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+ int startIndex = isNegative ? 1 : 0;
+ if (exp > 0 && exp < 8) {
+ // print digits.digits.
+ if (nDigits < exp) {
+ int extraZeros = exp - nDigits;
+ mantissa = create(isNegative, nDigits + extraZeros + 2);
+ System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+ Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0');
+ mantissa[startIndex + nDigits + extraZeros] = '.';
+ mantissa[startIndex + nDigits + extraZeros+1] = '0';
+ } else if (exp < nDigits) {
+ int t = Math.min(nDigits - exp, precision);
+ mantissa = create(isNegative, exp + 1 + t);
+ System.arraycopy(digits, 0, mantissa, startIndex, exp);
+ mantissa[startIndex + exp ] = '.';
+ System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t);
+ } else { // exp == digits.length
+ mantissa = create(isNegative, nDigits + 2);
+ System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+ mantissa[startIndex + nDigits ] = '.';
+ mantissa[startIndex + nDigits +1] = '0';
+ }
+ } else if (exp <= 0 && exp > -3) {
+ int zeros = Math.max(0, Math.min(-exp, precision));
+ int t = Math.max(0, Math.min(nDigits, precision + exp));
+ // write '0' s before the significant digits
+ if (zeros > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex+1] = '.';
+ Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
+ if (t > 0) {
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
+ }
+ } else if (t > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex + 1] = '.';
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
+ } else {
+ this.mantissa = create(isNegative, 1);
+ this.mantissa[startIndex] = '0';
+ }
+ } else {
+ if (nDigits > 1) {
+ mantissa = create(isNegative, nDigits + 1);
+ mantissa[startIndex] = digits[0];
+ mantissa[startIndex + 1] = '.';
+ System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1);
+ } else {
+ mantissa = create(isNegative, 3);
+ mantissa[startIndex] = digits[0];
+ mantissa[startIndex + 1] = '.';
+ mantissa[startIndex + 2] = '0';
+ }
+ int e, expStartIntex;
+ boolean isNegExp = (exp <= 0);
+ if (isNegExp) {
+ e = -exp + 1;
+ expStartIntex = 1;
+ } else {
+ e = exp - 1;
+ expStartIntex = 0;
+ }
+ // decExponent has 1, 2, or 3, digits
+ if (e <= 9) {
+ exponent = create(isNegExp,1);
+ exponent[expStartIntex] = (char) (e + '0');
+ } else if (e <= 99) {
+ exponent = create(isNegExp,2);
+ exponent[expStartIntex] = (char) (e / 10 + '0');
+ exponent[expStartIntex+1] = (char) (e % 10 + '0');
+ } else {
+ exponent = create(isNegExp,3);
+ exponent[expStartIntex] = (char) (e / 100 + '0');
+ e %= 100;
+ exponent[expStartIntex+1] = (char) (e / 10 + '0');
+ exponent[expStartIntex+2] = (char) (e % 10 + '0');
+ }
}
- else {
- if (mustSetRoundDir) {
- roundDir = 0;
- }
- /*
- * convert the lead kDigits to a long integer.
- */
- // (special performance hack: start to do it using int)
- int iValue = (int)digits[0]-(int)'0';
- int iDigits = Math.min( kDigits, intDecimalDigits );
- for ( int i=1; i < iDigits; i++ ){
- iValue = iValue*10 + (int)digits[i]-(int)'0';
- }
- lValue = (long)iValue;
- for ( int i=iDigits; i < kDigits; i++ ){
- lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
- }
- dValue = (double)lValue;
- int exp = decExponent-kDigits;
- /*
- * lValue now contains a long integer with the value of
- * the first kDigits digits of the number.
- * dValue contains the (double) of the same.
- */
+ }
- if ( nDigits <= maxDecimalDigits ){
- /*
- * possibly an easy case.
- * We know that the digits can be represented
- * exactly. And if the exponent isn't too outrageous,
- * the whole thing can be done with one operation,
- * thus one rounding error.
- * Note that all our constructors trim all leading and
- * trailing zeros, so simple values (including zero)
- * will always end up here
- */
- if (exp == 0 || dValue == 0.0)
- return (isNegative)? -dValue : dValue; // small floating integer
- else if ( exp >= 0 ){
- if ( exp <= maxSmallTen ){
- /*
- * Can get the answer with one operation,
- * thus one roundoff.
- */
- rValue = dValue * small10pow[exp];
- if ( mustSetRoundDir ){
- tValue = rValue / small10pow[exp];
- roundDir = ( tValue == dValue ) ? 0
- :( tValue < dValue ) ? 1
- : -1;
- }
- return (isNegative)? -rValue : rValue;
- }
- int slop = maxDecimalDigits - kDigits;
- if ( exp <= maxSmallTen+slop ){
- /*
- * We can multiply dValue by 10^(slop)
- * and it is still "small" and exact.
- * Then we can multiply by 10^(exp-slop)
- * with one rounding.
- */
- dValue *= small10pow[slop];
- rValue = dValue * small10pow[exp-slop];
-
- if ( mustSetRoundDir ){
- tValue = rValue / small10pow[exp-slop];
- roundDir = ( tValue == dValue ) ? 0
- :( tValue < dValue ) ? 1
- : -1;
- }
- return (isNegative)? -rValue : rValue;
- }
- /*
- * Else we have a hard case with a positive exp.
- */
- } else {
- if ( exp >= -maxSmallTen ){
- /*
- * Can get the answer in one division.
- */
- rValue = dValue / small10pow[-exp];
- tValue = rValue * small10pow[-exp];
- if ( mustSetRoundDir ){
- roundDir = ( tValue == dValue ) ? 0
- :( tValue < dValue ) ? 1
- : -1;
- }
- return (isNegative)? -rValue : rValue;
- }
- /*
- * Else we have a hard case with a negative exp.
- */
- }
- }
-
- /*
- * Harder cases:
- * The sum of digits plus exponent is greater than
- * what we think we can do with one error.
- *
- * Start by approximating the right answer by,
- * naively, scaling by powers of 10.
- */
- if ( exp > 0 ){
- if ( decExponent > maxDecimalExponent+1 ){
- /*
- * Lets face it. This is going to be
- * Infinity. Cut to the chase.
- */
- return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
- }
- if ( (exp&15) != 0 ){
- dValue *= small10pow[exp&15];
- }
- if ( (exp>>=4) != 0 ){
- int j;
- for( j = 0; exp > 1; j++, exp>>=1 ){
- if ( (exp&1)!=0)
- dValue *= big10pow[j];
- }
- /*
- * The reason for the weird exp > 1 condition
- * in the above loop was so that the last multiply
- * would get unrolled. We handle it here.
- * It could overflow.
- */
- double t = dValue * big10pow[j];
- if ( Double.isInfinite( t ) ){
- /*
- * It did overflow.
- * Look more closely at the result.
- * If the exponent is just one too large,
- * then use the maximum finite as our estimate
- * value. Else call the result infinity
- * and punt it.
- * ( I presume this could happen because
- * rounding forces the result here to be
- * an ULP or two larger than
- * Double.MAX_VALUE ).
- */
- t = dValue / 2.0;
- t *= big10pow[j];
- if ( Double.isInfinite( t ) ){
- return (isNegative)? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
- }
- t = Double.MAX_VALUE;
- }
- dValue = t;
- }
- } else if ( exp < 0 ){
- exp = -exp;
- if ( decExponent < minDecimalExponent-1 ){
- /*
- * Lets face it. This is going to be
- * zero. Cut to the chase.
- */
- return (isNegative)? -0.0 : 0.0;
- }
- if ( (exp&15) != 0 ){
- dValue /= small10pow[exp&15];
- }
- if ( (exp>>=4) != 0 ){
- int j;
- for( j = 0; exp > 1; j++, exp>>=1 ){
- if ( (exp&1)!=0)
- dValue *= tiny10pow[j];
- }
- /*
- * The reason for the weird exp > 1 condition
- * in the above loop was so that the last multiply
- * would get unrolled. We handle it here.
- * It could underflow.
- */
- double t = dValue * tiny10pow[j];
- if ( t == 0.0 ){
- /*
- * It did underflow.
- * Look more closely at the result.
- * If the exponent is just one too small,
- * then use the minimum finite as our estimate
- * value. Else call the result 0.0
- * and punt it.
- * ( I presume this could happen because
- * rounding forces the result here to be
- * an ULP or two less than
- * Double.MIN_VALUE ).
- */
- t = dValue * 2.0;
- t *= tiny10pow[j];
- if ( t == 0.0 ){
- return (isNegative)? -0.0 : 0.0;
- }
- t = Double.MIN_VALUE;
- }
- dValue = t;
- }
- }
-
- /*
- * dValue is now approximately the result.
- * The hard part is adjusting it, by comparison
- * with FDBigInt arithmetic.
- * Formulate the EXACT big-number result as
- * bigD0 * 10^exp
- */
- FDBigInt bigD0 = new FDBigInt( lValue, digits, kDigits, nDigits );
- exp = decExponent - nDigits;
-
- correctionLoop:
- while(true){
- /* AS A SIDE EFFECT, THIS METHOD WILL SET THE INSTANCE VARIABLES
- * bigIntExp and bigIntNBits
- */
- FDBigInt bigB = doubleToBigInt( dValue );
-
- /*
- * Scale bigD, bigB appropriately for
- * big-integer operations.
- * Naively, we multipy by powers of ten
- * and powers of two. What we actually do
- * is keep track of the powers of 5 and
- * powers of 2 we would use, then factor out
- * common divisors before doing the work.
- */
- int B2, B5; // powers of 2, 5 in bigB
- int D2, D5; // powers of 2, 5 in bigD
- int Ulp2; // powers of 2 in halfUlp.
- if ( exp >= 0 ){
- B2 = B5 = 0;
- D2 = D5 = exp;
- } else {
- B2 = B5 = -exp;
- D2 = D5 = 0;
- }
- if ( bigIntExp >= 0 ){
- B2 += bigIntExp;
- } else {
- D2 -= bigIntExp;
- }
- Ulp2 = B2;
- // shift bigB and bigD left by a number s. t.
- // halfUlp is still an integer.
- int hulpbias;
- if ( bigIntExp+bigIntNBits <= -expBias+1 ){
- // This is going to be a denormalized number
- // (if not actually zero).
- // half an ULP is at 2^-(expBias+expShift+1)
- hulpbias = bigIntExp+ expBias + expShift;
- } else {
- hulpbias = expShift + 2 - bigIntNBits;
- }
- B2 += hulpbias;
- D2 += hulpbias;
- // if there are common factors of 2, we might just as well
- // factor them out, as they add nothing useful.
- int common2 = Math.min( B2, Math.min( D2, Ulp2 ) );
- B2 -= common2;
- D2 -= common2;
- Ulp2 -= common2;
- // do multiplications by powers of 5 and 2
- bigB = multPow52( bigB, B5, B2 );
- FDBigInt bigD = multPow52( new FDBigInt( bigD0 ), D5, D2 );
- //
- // to recap:
- // bigB is the scaled-big-int version of our floating-point
- // candidate.
- // bigD is the scaled-big-int version of the exact value
- // as we understand it.
- // halfUlp is 1/2 an ulp of bigB, except for special cases
- // of exact powers of 2
- //
- // the plan is to compare bigB with bigD, and if the difference
- // is less than halfUlp, then we're satisfied. Otherwise,
- // use the ratio of difference to halfUlp to calculate a fudge
- // factor to add to the floating value, then go 'round again.
- //
- FDBigInt diff;
- int cmpResult;
- boolean overvalue;
- if ( (cmpResult = bigB.cmp( bigD ) ) > 0 ){
- overvalue = true; // our candidate is too big.
- diff = bigB.sub( bigD );
- if ( (bigIntNBits == 1) && (bigIntExp > -expBias) ){
- // candidate is a normalized exact power of 2 and
- // is too big. We will be subtracting.
- // For our purposes, ulp is the ulp of the
- // next smaller range.
- Ulp2 -= 1;
- if ( Ulp2 < 0 ){
- // rats. Cannot de-scale ulp this far.
- // must scale diff in other direction.
- Ulp2 = 0;
- diff.lshiftMe( 1 );
- }
- }
- } else if ( cmpResult < 0 ){
- overvalue = false; // our candidate is too small.
- diff = bigD.sub( bigB );
- } else {
- // the candidate is exactly right!
- // this happens with surprising fequency
- break correctionLoop;
- }
- FDBigInt halfUlp = constructPow52( B5, Ulp2 );
- if ( (cmpResult = diff.cmp( halfUlp ) ) < 0 ){
- // difference is small.
- // this is close enough
- if (mustSetRoundDir) {
- roundDir = overvalue ? -1 : 1;
- }
- break correctionLoop;
- } else if ( cmpResult == 0 ){
- // difference is exactly half an ULP
- // round to some other value maybe, then finish
- dValue += 0.5*ulp( dValue, overvalue );
- // should check for bigIntNBits == 1 here??
- if (mustSetRoundDir) {
- roundDir = overvalue ? -1 : 1;
- }
- break correctionLoop;
- } else {
- // difference is non-trivial.
- // could scale addend by ratio of difference to
- // halfUlp here, if we bothered to compute that difference.
- // Most of the time ( I hope ) it is about 1 anyway.
- dValue += ulp( dValue, overvalue );
- if ( dValue == 0.0 || dValue == Double.POSITIVE_INFINITY )
- break correctionLoop; // oops. Fell off end of range.
- continue; // try again.
- }
-
- }
- return (isNegative)? -dValue : dValue;
+ private static char[] create(boolean isNegative, int size) {
+ if(isNegative) {
+ char[] r = new char[size +1];
+ r[0] = '-';
+ return r;
+ } else {
+ return new char[size];
}
}
/*
- * Take a FormattedFloatingDecimal, which we presumably just scanned in,
- * and find out what its value is, as a float.
- * This is distinct from doubleValue() to avoid the extremely
- * unlikely case of a double rounding error, wherein the converstion
- * to double has one rounding error, and the conversion of that double
- * to a float has another rounding error, IN THE WRONG DIRECTION,
- * ( because of the preference to a zero low-order bit ).
+ * Fills mantissa char arrays for DECIMAL_FLOAT format.
+ * Exponent should be equal to null.
*/
-
- public strictfp float floatValue(){
- int kDigits = Math.min( nDigits, singleMaxDecimalDigits+1 );
- int iValue;
- float fValue;
-
- // First, check for NaN and Infinity values
- if(digits == infinity || digits == notANumber) {
- if(digits == notANumber)
- return Float.NaN;
- else
- return (isNegative?Float.NEGATIVE_INFINITY:Float.POSITIVE_INFINITY);
- }
- else {
- /*
- * convert the lead kDigits to an integer.
- */
- iValue = (int)digits[0]-(int)'0';
- for ( int i=1; i < kDigits; i++ ){
- iValue = iValue*10 + (int)digits[i]-(int)'0';
- }
- fValue = (float)iValue;
- int exp = decExponent-kDigits;
- /*
- * iValue now contains an integer with the value of
- * the first kDigits digits of the number.
- * fValue contains the (float) of the same.
- */
-
- if ( nDigits <= singleMaxDecimalDigits ){
- /*
- * possibly an easy case.
- * We know that the digits can be represented
- * exactly. And if the exponent isn't too outrageous,
- * the whole thing can be done with one operation,
- * thus one rounding error.
- * Note that all our constructors trim all leading and
- * trailing zeros, so simple values (including zero)
- * will always end up here.
- */
- if (exp == 0 || fValue == 0.0f)
- return (isNegative)? -fValue : fValue; // small floating integer
- else if ( exp >= 0 ){
- if ( exp <= singleMaxSmallTen ){
- /*
- * Can get the answer with one operation,
- * thus one roundoff.
- */
- fValue *= singleSmall10pow[exp];
- return (isNegative)? -fValue : fValue;
- }
- int slop = singleMaxDecimalDigits - kDigits;
- if ( exp <= singleMaxSmallTen+slop ){
- /*
- * We can multiply dValue by 10^(slop)
- * and it is still "small" and exact.
- * Then we can multiply by 10^(exp-slop)
- * with one rounding.
- */
- fValue *= singleSmall10pow[slop];
- fValue *= singleSmall10pow[exp-slop];
- return (isNegative)? -fValue : fValue;
- }
- /*
- * Else we have a hard case with a positive exp.
- */
- } else {
- if ( exp >= -singleMaxSmallTen ){
- /*
- * Can get the answer in one division.
- */
- fValue /= singleSmall10pow[-exp];
- return (isNegative)? -fValue : fValue;
- }
- /*
- * Else we have a hard case with a negative exp.
- */
+ private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+ int startIndex = isNegative ? 1 : 0;
+ if (exp > 0) {
+ // print digits.digits.
+ if (nDigits < exp) {
+ mantissa = create(isNegative,exp);
+ System.arraycopy(digits, 0, mantissa, startIndex, nDigits);
+ Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0');
+ // Do not append ".0" for formatted floats since the user
+ // may request that it be omitted. It is added as necessary
+ // by the Formatter.
+ } else {
+ int t = Math.min(nDigits - exp, precision);
+ mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0));
+ System.arraycopy(digits, 0, mantissa, startIndex, exp);
+ // Do not append ".0" for formatted floats since the user
+ // may request that it be omitted. It is added as necessary
+ // by the Formatter.
+ if (t > 0) {
+ mantissa[startIndex + exp] = '.';
+ System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t);
}
- } else if ( (decExponent >= nDigits) && (nDigits+decExponent <= maxDecimalDigits) ){
- /*
- * In double-precision, this is an exact floating integer.
- * So we can compute to double, then shorten to float
- * with one round, and get the right answer.
- *
- * First, finish accumulating digits.
- * Then convert that integer to a double, multiply
- * by the appropriate power of ten, and convert to float.
- */
- long lValue = (long)iValue;
- for ( int i=kDigits; i < nDigits; i++ ){
- lValue = lValue*10L + (long)((int)digits[i]-(int)'0');
+ }
+ } else if (exp <= 0) {
+ int zeros = Math.max(0, Math.min(-exp, precision));
+ int t = Math.max(0, Math.min(nDigits, precision + exp));
+ // write '0' s before the significant digits
+ if (zeros > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex+1] = '.';
+ Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0');
+ if (t > 0) {
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t);
}
- double dValue = (double)lValue;
- exp = decExponent-nDigits;
- dValue *= small10pow[exp];
- fValue = (float)dValue;
- return (isNegative)? -fValue : fValue;
-
+ } else if (t > 0) {
+ mantissa = create(isNegative, zeros + 2 + t);
+ mantissa[startIndex] = '0';
+ mantissa[startIndex + 1] = '.';
+ // copy only when significant digits are within the precision
+ System.arraycopy(digits, 0, mantissa, startIndex + 2, t);
+ } else {
+ this.mantissa = create(isNegative, 1);
+ this.mantissa[startIndex] = '0';
}
- /*
- * Harder cases:
- * The sum of digits plus exponent is greater than
- * what we think we can do with one error.
- *
- * Start by weeding out obviously out-of-range
- * results, then convert to double and go to
- * common hard-case code.
- */
- if ( decExponent > singleMaxDecimalExponent+1 ){
- /*
- * Lets face it. This is going to be
- * Infinity. Cut to the chase.
- */
- return (isNegative)? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
- } else if ( decExponent < singleMinDecimalExponent-1 ){
- /*
- * Lets face it. This is going to be
- * zero. Cut to the chase.
- */
- return (isNegative)? -0.0f : 0.0f;
- }
-
- /*
- * Here, we do 'way too much work, but throwing away
- * our partial results, and going and doing the whole
- * thing as double, then throwing away half the bits that computes
- * when we convert back to float.
- *
- * The alternative is to reproduce the whole multiple-precision
- * algorythm for float precision, or to try to parameterize it
- * for common usage. The former will take about 400 lines of code,
- * and the latter I tried without success. Thus the semi-hack
- * answer here.
- */
- mustSetRoundDir = !fromHex;
- double dValue = doubleValue();
- return stickyRound( dValue );
}
}
-
- /*
- * All the positive powers of 10 that can be
- * represented exactly in double/float.
+ /**
+ * Fills mantissa and exponent char arrays for SCIENTIFIC format.
*/
- private static final double small10pow[] = {
- 1.0e0,
- 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5,
- 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10,
- 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15,
- 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20,
- 1.0e21, 1.0e22
- };
-
- private static final float singleSmall10pow[] = {
- 1.0e0f,
- 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f,
- 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f
- };
-
- private static final double big10pow[] = {
- 1e16, 1e32, 1e64, 1e128, 1e256 };
- private static final double tiny10pow[] = {
- 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
-
- private static final int maxSmallTen = small10pow.length-1;
- private static final int singleMaxSmallTen = singleSmall10pow.length-1;
-
- private static final int small5pow[] = {
- 1,
- 5,
- 5*5,
- 5*5*5,
- 5*5*5*5,
- 5*5*5*5*5,
- 5*5*5*5*5*5,
- 5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5,
- 5*5*5*5*5*5*5*5*5*5*5*5*5
- };
-
-
- private static final long long5pow[] = {
- 1L,
- 5L,
- 5L*5,
- 5L*5*5,
- 5L*5*5*5,
- 5L*5*5*5*5,
- 5L*5*5*5*5*5,
- 5L*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- 5L*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5*5,
- };
-
- // approximately ceil( log2( long5pow[i] ) )
- private static final int n5bits[] = {
- 0,
- 3,
- 5,
- 7,
- 10,
- 12,
- 14,
- 17,
- 19,
- 21,
- 24,
- 26,
- 28,
- 31,
- 33,
- 35,
- 38,
- 40,
- 42,
- 45,
- 47,
- 49,
- 52,
- 54,
- 56,
- 59,
- 61,
- };
-
- private static final char infinity[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
- private static final char notANumber[] = { 'N', 'a', 'N' };
- private static final char zero[] = { '0', '0', '0', '0', '0', '0', '0', '0' };
+ private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) {
+ int startIndex = isNegative ? 1 : 0;
+ int t = Math.max(0, Math.min(nDigits - 1, precision));
+ if (t > 0) {
+ mantissa = create(isNegative, t + 2);
+ mantissa[startIndex] = digits[0];
+ mantissa[startIndex + 1] = '.';
+ System.arraycopy(digits, 1, mantissa, startIndex + 2, t);
+ } else {
+ mantissa = create(isNegative, 1);
+ mantissa[startIndex] = digits[0];
+ }
+ char expSign;
+ int e;
+ if (exp <= 0) {
+ expSign = '-';
+ e = -exp + 1;
+ } else {
+ expSign = '+' ;
+ e = exp - 1;
+ }
+ // decExponent has 1, 2, or 3, digits
+ if (e <= 9) {
+ exponent = new char[] { expSign,
+ '0', (char) (e + '0') };
+ } else if (e <= 99) {
+ exponent = new char[] { expSign,
+ (char) (e / 10 + '0'), (char) (e % 10 + '0') };
+ } else {
+ char hiExpChar = (char) (e / 100 + '0');
+ e %= 100;
+ exponent = new char[] { expSign,
+ hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') };
+ }
+ }
}
diff --git a/ojluni/src/main/java/sun/net/www/MimeEntry.java b/ojluni/src/main/java/sun/net/www/MimeEntry.java
deleted file mode 100755
index 005d960..0000000
--- a/ojluni/src/main/java/sun/net/www/MimeEntry.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (c) 1994, 2002, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www;
-import java.net.URL;
-import java.io.*;
-import java.util.StringTokenizer;
-
-public class MimeEntry implements Cloneable {
- private String typeName; // of the form: "type/subtype"
- private String tempFileNameTemplate;
-
- private int action;
- private String command;
- private String description;
- private String imageFileName;
- private String fileExtensions[];
-
- boolean starred;
-
- // Actions
- public static final int UNKNOWN = 0;
- public static final int LOAD_INTO_BROWSER = 1;
- public static final int SAVE_TO_FILE = 2;
- public static final int LAUNCH_APPLICATION = 3;
-
- static final String[] actionKeywords = {
- "unknown",
- "browser",
- "save",
- "application",
- };
-
- /**
- * Construct an empty entry of the given type and subtype.
- */
- public MimeEntry(String type) {
- // Default action is UNKNOWN so clients can decide what the default
- // should be, typically save to file or ask user.
- this(type, UNKNOWN, null, null, null);
- }
-
- //
- // The next two constructors are used only by the deprecated
- // PlatformMimeTable classes or, in last case, is called by the public
- // constructor. They are kept here anticipating putting support for
- // mailcap formatted config files back in (so BOTH the properties format
- // and the mailcap formats are supported).
- //
- MimeEntry(String type, String imageFileName, String extensionString) {
- typeName = type.toLowerCase();
- action = UNKNOWN;
- command = null;
- this.imageFileName = imageFileName;
- setExtensions(extensionString);
- starred = isStarred(typeName);
- }
-
- // For use with MimeTable::parseMailCap
- MimeEntry(String typeName, int action, String command,
- String tempFileNameTemplate) {
- this.typeName = typeName.toLowerCase();
- this.action = action;
- this.command = command;
- this.imageFileName = null;
- this.fileExtensions = null;
-
- this.tempFileNameTemplate = tempFileNameTemplate;
- }
-
- // This is the one called by the public constructor.
- MimeEntry(String typeName, int action, String command,
- String imageFileName, String fileExtensions[]) {
-
- this.typeName = typeName.toLowerCase();
- this.action = action;
- this.command = command;
- this.imageFileName = imageFileName;
- this.fileExtensions = fileExtensions;
-
- starred = isStarred(typeName);
-
- }
-
- public synchronized String getType() {
- return typeName;
- }
-
- public synchronized void setType(String type) {
- typeName = type.toLowerCase();
- }
-
- public synchronized int getAction() {
- return action;
- }
-
- public synchronized void setAction(int action, String command) {
- this.action = action;
- this.command = command;
- }
-
- public synchronized void setAction(int action) {
- this.action = action;
- }
-
- public synchronized String getLaunchString() {
- return command;
- }
-
- public synchronized void setCommand(String command) {
- this.command = command;
- }
-
- public synchronized String getDescription() {
- return (description != null ? description : typeName);
- }
-
- public synchronized void setDescription(String description) {
- this.description = description;
- }
-
- // ??? what to return for the image -- the file name or should this return
- // something more advanced like an image source or something?
- // returning the name has the least policy associated with it.
- // pro tempore, we'll use the name
- public String getImageFileName() {
- return imageFileName;
- }
-
- public synchronized void setImageFileName(String filename) {
- File file = new File(filename);
- if (file.getParent() == null) {
- imageFileName = System.getProperty(
- "java.net.ftp.imagepath."+filename);
- }
- else {
- imageFileName = filename;
- }
-
- if (filename.lastIndexOf('.') < 0) {
- imageFileName = imageFileName + ".gif";
- }
- }
-
- public String getTempFileTemplate() {
- return tempFileNameTemplate;
- }
-
- public synchronized String[] getExtensions() {
- return fileExtensions;
- }
-
- public synchronized String getExtensionsAsList() {
- String extensionsAsString = "";
- if (fileExtensions != null) {
- for (int i = 0; i < fileExtensions.length; i++) {
- extensionsAsString += fileExtensions[i];
- if (i < (fileExtensions.length - 1)) {
- extensionsAsString += ",";
- }
- }
- }
-
- return extensionsAsString;
- }
-
- public synchronized void setExtensions(String extensionString) {
- StringTokenizer extTokens = new StringTokenizer(extensionString, ",");
- int numExts = extTokens.countTokens();
- String extensionStrings[] = new String[numExts];
-
- for (int i = 0; i < numExts; i++) {
- String ext = (String)extTokens.nextElement();
- extensionStrings[i] = ext.trim();
- }
-
- fileExtensions = extensionStrings;
- }
-
- private boolean isStarred(String typeName) {
- return (typeName != null)
- && (typeName.length() > 0)
- && (typeName.endsWith("/*"));
- }
-
- /**
- * Invoke the MIME type specific behavior for this MIME type.
- * Returned value can be one of several types:
- * <ol>
- * <li>A thread -- the caller can choose when to launch this thread.
- * <li>A string -- the string is loaded into the browser directly.
- * <li>An input stream -- the caller can read from this byte stream and
- * will typically store the results in a file.
- * <li>A document (?) --
- * </ol>
- */
- public Object launch(java.net.URLConnection urlc, InputStream is, MimeTable mt) throws ApplicationLaunchException {
- switch (action) {
- case SAVE_TO_FILE:
- // REMIND: is this really the right thing to do?
- try {
- return is;
- } catch(Exception e) {
- // I18N
- return "Load to file failed:\n" + e;
- }
-
- case LOAD_INTO_BROWSER:
- // REMIND: invoke the content handler?
- // may be the right thing to do, may not be -- short term
- // where docs are not loaded asynch, loading and returning
- // the content is the right thing to do.
- try {
- return urlc.getContent();
- } catch (Exception e) {
- return null;
- }
-
- case LAUNCH_APPLICATION:
- {
- String threadName = command;
- int fst = threadName.indexOf(' ');
- if (fst > 0) {
- threadName = threadName.substring(0, fst);
- }
-
- return new MimeLauncher(this, urlc, is,
- mt.getTempFileTemplate(), threadName);
- }
-
- case UNKNOWN:
- // REMIND: What do do here?
- return null;
- }
-
- return null;
- }
-
- public boolean matches(String type) {
- if (starred) {
- // REMIND: is this the right thing or not?
- return type.startsWith(typeName);
- } else {
- return type.equals(typeName);
- }
- }
-
- public Object clone() {
- // return a shallow copy of this.
- MimeEntry theClone = new MimeEntry(typeName);
- theClone.action = action;
- theClone.command = command;
- theClone.description = description;
- theClone.imageFileName = imageFileName;
- theClone.tempFileNameTemplate = tempFileNameTemplate;
- theClone.fileExtensions = fileExtensions;
-
- return theClone;
- }
-
- public synchronized String toProperty() {
- StringBuffer buf = new StringBuffer();
-
- String separator = "; ";
- boolean needSeparator = false;
-
- int action = getAction();
- if (action != MimeEntry.UNKNOWN) {
- buf.append("action=" + actionKeywords[action]);
- needSeparator = true;
- }
-
- String command = getLaunchString();
- if (command != null && command.length() > 0) {
- if (needSeparator) {
- buf.append(separator);
- }
- buf.append("application=" + command);
- needSeparator = true;
- }
-
- if (getImageFileName() != null) {
- if (needSeparator) {
- buf.append(separator);
- }
- buf.append("icon=" + getImageFileName());
- needSeparator = true;
- }
-
- String extensions = getExtensionsAsList();
- if (extensions.length() > 0) {
- if (needSeparator) {
- buf.append(separator);
- }
- buf.append("file_extensions=" + extensions);
- needSeparator = true;
- }
-
- String description = getDescription();
- if (description != null && !description.equals(getType())) {
- if (needSeparator) {
- buf.append(separator);
- }
- buf.append("description=" + description);
- }
-
- return buf.toString();
- }
-
- public String toString() {
- return "MimeEntry[contentType=" + typeName
- + ", image=" + imageFileName
- + ", action=" + action
- + ", command=" + command
- + ", extensions=" + getExtensionsAsList()
- + "]";
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/MimeLauncher.java b/ojluni/src/main/java/sun/net/www/MimeLauncher.java
deleted file mode 100755
index ee4fb40..0000000
--- a/ojluni/src/main/java/sun/net/www/MimeLauncher.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www;
-import java.net.URL;
-import java.io.*;
-import java.util.StringTokenizer;
-
-class MimeLauncher extends Thread {
- java.net.URLConnection uc;
- MimeEntry m;
- String genericTempFileTemplate;
- InputStream is;
- String execPath;
-
- MimeLauncher (MimeEntry M, java.net.URLConnection uc,
- InputStream is, String tempFileTemplate, String threadName) throws ApplicationLaunchException {
- super(threadName);
- m = M;
- this.uc = uc;
- this.is = is;
- genericTempFileTemplate = tempFileTemplate;
-
- /* get the application to launch */
- String launchString = m.getLaunchString();
-
- /* get a valid path to launch application - sets
- the execPath instance variable with the correct path.
- */
- if (!findExecutablePath(launchString)) {
- /* strip off parameters i.e %s */
- String appName;
- int index = launchString.indexOf(' ');
- if (index != -1) {
- appName = launchString.substring(0, index);
- }
- else {
- appName = launchString;
- }
- throw new ApplicationLaunchException(appName);
- }
- }
-
- protected String getTempFileName(URL url, String template) {
- String tempFilename = template;
-
- // Replace all but last occurrance of "%s" with timestamp to insure
- // uniqueness. There's a subtle behavior here: if there is anything
- // _after_ the last "%s" we need to append it so that unusual launch
- // strings that have the datafile in the middle can still be used.
- int wildcard = tempFilename.lastIndexOf("%s");
- String prefix = tempFilename.substring(0, wildcard);
-
- String suffix = "";
- if (wildcard < tempFilename.length() - 2) {
- suffix = tempFilename.substring(wildcard + 2);
- }
-
- long timestamp = System.currentTimeMillis()/1000;
- int argIndex = 0;
- while ((argIndex = prefix.indexOf("%s")) >= 0) {
- prefix = prefix.substring(0, argIndex)
- + timestamp
- + prefix.substring(argIndex + 2);
- }
-
- // Add a file name and file-extension if known
- String filename = url.getFile();
-
- String extension = "";
- int dot = filename.lastIndexOf('.');
-
- // BugId 4084826: Temp MIME file names not always valid.
- // Fix: don't allow slashes in the file name or extension.
- if (dot >= 0 && dot > filename.lastIndexOf('/')) {
- extension = filename.substring(dot);
- }
-
- filename = "HJ" + url.hashCode();
-
- tempFilename = prefix + filename + timestamp + extension + suffix;
-
- return tempFilename;
- }
-
- public void run() {
- try {
- String ofn = m.getTempFileTemplate();
- if (ofn == null) {
- ofn = genericTempFileTemplate;
- }
-
- ofn = getTempFileName(uc.getURL(), ofn);
- try {
- OutputStream os = new FileOutputStream(ofn);
- byte buf[] = new byte[2048];
- int i = 0;
- try {
- while ((i = is.read(buf)) >= 0) {
- os.write(buf, 0, i);
- }
- } catch(IOException e) {
- //System.err.println("Exception in write loop " + i);
- //e.printStackTrace();
- } finally {
- os.close();
- is.close();
- }
- } catch(IOException e) {
- //System.err.println("Exception in input or output stream");
- //e.printStackTrace();
- }
-
- int inx = 0;
- String c = execPath;
- while ((inx = c.indexOf("%t")) >= 0) {
- c = c.substring(0, inx) + uc.getContentType()
- + c.substring(inx + 2);
- }
-
- boolean substituted = false;
- while ((inx = c.indexOf("%s")) >= 0) {
- c = c.substring(0, inx) + ofn + c.substring(inx + 2);
- substituted = true;
- }
- if (!substituted)
- c = c + " <" + ofn;
-
- // System.out.println("Execing " +c);
-
- Runtime.getRuntime().exec(c);
- } catch(IOException e) {
- }
- }
-
- /* This method determines the path for the launcher application
- and sets the execPath instance variable. It uses the exec.path
- property to obtain a list of paths that is in turn used to
- location the application. If a valid path is not found, it
- returns false else true. */
- private boolean findExecutablePath(String str) {
- if (str == null || str.length() == 0) {
- return false;
- }
-
- String command;
- int index = str.indexOf(' ');
- if (index != -1) {
- command = str.substring(0, index);
- }
- else {
- command = str;
- }
-
- File f = new File(command);
- if (f.isFile()) {
- // Already executable as it is
- execPath = str;
- return true;
- }
-
- String execPathList;
- execPathList = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("exec.path"));
- if (execPathList == null) {
- // exec.path property not set
- return false;
- }
-
- StringTokenizer iter = new StringTokenizer(execPathList, "|");
- while (iter.hasMoreElements()) {
- String prefix = (String)iter.nextElement();
- String fullCmd = prefix + File.separator + command;
- f = new File(fullCmd);
- if (f.isFile()) {
- execPath = prefix + File.separator + str;
- return true;
- }
- }
-
- return false; // application not found in exec.path
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/MimeTable.java b/ojluni/src/main/java/sun/net/www/MimeTable.java
deleted file mode 100755
index b8b70fd..0000000
--- a/ojluni/src/main/java/sun/net/www/MimeTable.java
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www;
-import java.io.*;
-import java.util.Calendar;
-import java.util.Date;
-import java.text.SimpleDateFormat;
-import java.net.URL;
-import java.net.FileNameMap;
-import java.util.Hashtable;
-import java.util.Enumeration;
-import java.util.Properties;
-import java.util.StringTokenizer;
-
-public class MimeTable implements FileNameMap {
- /** Keyed by content type, returns MimeEntries */
- private Hashtable<String, MimeEntry> entries
- = new Hashtable<String, MimeEntry>();
-
- /** Keyed by file extension (with the .), returns MimeEntries */
- private Hashtable<String, MimeEntry> extensionMap
- = new Hashtable<String, MimeEntry>();
-
- // Will be reset if in the platform-specific data file
- private static String tempFileTemplate;
-
- static {
- java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<Void>() {
- public Void run() {
- tempFileTemplate =
- System.getProperty("content.types.temp.file.template",
- "/tmp/%s");
-
- mailcapLocations = new String[] {
- System.getProperty("user.mailcap"),
- System.getProperty("user.home") + "/.mailcap",
- "/etc/mailcap",
- "/usr/etc/mailcap",
- "/usr/local/etc/mailcap",
- System.getProperty("hotjava.home",
- "/usr/local/hotjava")
- + "/lib/mailcap",
- };
- return null;
- }
- });
- }
-
-
- private static final String filePreamble = "sun.net.www MIME content-types table";
- private static final String fileMagic = "#" + filePreamble;
-
- MimeTable() {
- load();
- }
-
- private static class DefaultInstanceHolder {
- static final MimeTable defaultInstance = getDefaultInstance();
-
- static MimeTable getDefaultInstance() {
- return java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<MimeTable>() {
- public MimeTable run() {
- MimeTable instance = new MimeTable();
- URLConnection.setFileNameMap(instance);
- return instance;
- }
- });
- }
- }
-
- /**
- * Get the single instance of this class. First use will load the
- * table from a data file.
- */
- public static MimeTable getDefaultTable() {
- return DefaultInstanceHolder.defaultInstance;
- }
-
- /**
- *
- */
- public static FileNameMap loadTable() {
- MimeTable mt = getDefaultTable();
- return (FileNameMap)mt;
- }
-
- public synchronized int getSize() {
- return entries.size();
- }
-
- public synchronized String getContentTypeFor(String fileName) {
- MimeEntry entry = findByFileName(fileName);
- if (entry != null) {
- return entry.getType();
- } else {
- return null;
- }
- }
-
- public synchronized void add(MimeEntry m) {
- entries.put(m.getType(), m);
-
- String exts[] = m.getExtensions();
- if (exts == null) {
- return;
- }
-
- for (int i = 0; i < exts.length; i++) {
- extensionMap.put(exts[i], m);
- }
- }
-
- public synchronized MimeEntry remove(String type) {
- MimeEntry entry = entries.get(type);
- return remove(entry);
- }
-
- public synchronized MimeEntry remove(MimeEntry entry) {
- String[] extensionKeys = entry.getExtensions();
- if (extensionKeys != null) {
- for (int i = 0; i < extensionKeys.length; i++) {
- extensionMap.remove(extensionKeys[i]);
- }
- }
-
- return entries.remove(entry.getType());
- }
-
- public synchronized MimeEntry find(String type) {
- MimeEntry entry = entries.get(type);
- if (entry == null) {
- // try a wildcard lookup
- Enumeration<MimeEntry> e = entries.elements();
- while (e.hasMoreElements()) {
- MimeEntry wild = e.nextElement();
- if (wild.matches(type)) {
- return wild;
- }
- }
- }
-
- return entry;
- }
-
- /**
- * Locate a MimeEntry by the file extension that has been associated
- * with it. Parses general file names, and URLs.
- */
- public MimeEntry findByFileName(String fname) {
- String ext = "";
-
- int i = fname.lastIndexOf('#');
-
- if (i > 0) {
- fname = fname.substring(0, i - 1);
- }
-
- i = fname.lastIndexOf('.');
- // REMIND: OS specific delimters appear here
- i = Math.max(i, fname.lastIndexOf('/'));
- i = Math.max(i, fname.lastIndexOf('?'));
-
- if (i != -1 && fname.charAt(i) == '.') {
- ext = fname.substring(i).toLowerCase();
- }
-
- return findByExt(ext);
- }
-
- /**
- * Locate a MimeEntry by the file extension that has been associated
- * with it.
- */
- public synchronized MimeEntry findByExt(String fileExtension) {
- return extensionMap.get(fileExtension);
- }
-
- public synchronized MimeEntry findByDescription(String description) {
- Enumeration<MimeEntry> e = elements();
- while (e.hasMoreElements()) {
- MimeEntry entry = e.nextElement();
- if (description.equals(entry.getDescription())) {
- return entry;
- }
- }
-
- // We failed, now try treating description as type
- return find(description);
- }
-
- String getTempFileTemplate() {
- return tempFileTemplate;
- }
-
- public synchronized Enumeration<MimeEntry> elements() {
- return entries.elements();
- }
-
- // For backward compatibility -- mailcap format files
- // This is not currently used, but may in the future when we add ability
- // to read BOTH the properties format and the mailcap format.
- protected static String[] mailcapLocations;
-
- public synchronized void load() {
- Properties entries = new Properties();
- File file = null;
- try {
- InputStream is;
- // First try to load the user-specific table, if it exists
- String userTablePath =
- System.getProperty("content.types.user.table");
- if (userTablePath != null) {
- file = new File(userTablePath);
- if (!file.exists()) {
- // No user-table, try to load the default built-in table.
- file = new File(System.getProperty("java.home") +
- File.separator +
- "lib" +
- File.separator +
- "content-types.properties");
- }
- }
- else {
- // No user table, try to load the default built-in table.
- file = new File(System.getProperty("java.home") +
- File.separator +
- "lib" +
- File.separator +
- "content-types.properties");
- }
-
- is = new BufferedInputStream(new FileInputStream(file));
- entries.load(is);
- is.close();
- }
- catch (IOException e) {
- System.err.println("Warning: default mime table not found: " +
- file.getPath());
- return;
- }
- parse(entries);
- }
-
- void parse(Properties entries) {
- // first, strip out the platform-specific temp file template
- String tempFileTemplate = (String)entries.get("temp.file.template");
- if (tempFileTemplate != null) {
- entries.remove("temp.file.template");
- this.tempFileTemplate = tempFileTemplate;
- }
-
- // now, parse the mime-type spec's
- Enumeration<?> types = entries.propertyNames();
- while (types.hasMoreElements()) {
- String type = (String)types.nextElement();
- String attrs = entries.getProperty(type);
- parse(type, attrs);
- }
- }
-
- //
- // Table format:
- //
- // <entry> ::= <table_tag> | <type_entry>
- //
- // <table_tag> ::= <table_format_version> | <temp_file_template>
- //
- // <type_entry> ::= <type_subtype_pair> '=' <type_attrs_list>
- //
- // <type_subtype_pair> ::= <type> '/' <subtype>
- //
- // <type_attrs_list> ::= <attr_value_pair> [ ';' <attr_value_pair> ]*
- // | [ <attr_value_pair> ]+
- //
- // <attr_value_pair> ::= <attr_name> '=' <attr_value>
- //
- // <attr_name> ::= 'description' | 'action' | 'application'
- // | 'file_extensions' | 'icon'
- //
- // <attr_value> ::= <legal_char>*
- //
- // Embedded ';' in an <attr_value> are quoted with leading '\' .
- //
- // Interpretation of <attr_value> depends on the <attr_name> it is
- // associated with.
- //
-
- void parse(String type, String attrs) {
- MimeEntry newEntry = new MimeEntry(type);
-
- // REMIND handle embedded ';' and '|' and literal '"'
- StringTokenizer tokenizer = new StringTokenizer(attrs, ";");
- while (tokenizer.hasMoreTokens()) {
- String pair = tokenizer.nextToken();
- parse(pair, newEntry);
- }
-
- add(newEntry);
- }
-
- void parse(String pair, MimeEntry entry) {
- // REMIND add exception handling...
- String name = null;
- String value = null;
-
- boolean gotName = false;
- StringTokenizer tokenizer = new StringTokenizer(pair, "=");
- while (tokenizer.hasMoreTokens()) {
- if (gotName) {
- value = tokenizer.nextToken().trim();
- }
- else {
- name = tokenizer.nextToken().trim();
- gotName = true;
- }
- }
-
- fill(entry, name, value);
- }
-
- void fill(MimeEntry entry, String name, String value) {
- if ("description".equalsIgnoreCase(name)) {
- entry.setDescription(value);
- }
- else if ("action".equalsIgnoreCase(name)) {
- entry.setAction(getActionCode(value));
- }
- else if ("application".equalsIgnoreCase(name)) {
- entry.setCommand(value);
- }
- else if ("icon".equalsIgnoreCase(name)) {
- entry.setImageFileName(value);
- }
- else if ("file_extensions".equalsIgnoreCase(name)) {
- entry.setExtensions(value);
- }
-
- // else illegal name exception
- }
-
- String[] getExtensions(String list) {
- StringTokenizer tokenizer = new StringTokenizer(list, ",");
- int n = tokenizer.countTokens();
- String[] extensions = new String[n];
- for (int i = 0; i < n; i++) {
- extensions[i] = tokenizer.nextToken();
- }
-
- return extensions;
- }
-
- int getActionCode(String action) {
- for (int i = 0; i < MimeEntry.actionKeywords.length; i++) {
- if (action.equalsIgnoreCase(MimeEntry.actionKeywords[i])) {
- return i;
- }
- }
-
- return MimeEntry.UNKNOWN;
- }
-
- public synchronized boolean save(String filename) {
- if (filename == null) {
- filename = System.getProperty("user.home" +
- File.separator +
- "lib" +
- File.separator +
- "content-types.properties");
- }
-
- return saveAsProperties(new File(filename));
- }
-
- public Properties getAsProperties() {
- Properties properties = new Properties();
- Enumeration<MimeEntry> e = elements();
- while (e.hasMoreElements()) {
- MimeEntry entry = e.nextElement();
- properties.put(entry.getType(), entry.toProperty());
- }
-
- return properties;
- }
-
- protected boolean saveAsProperties(File file) {
- FileOutputStream os = null;
- try {
- os = new FileOutputStream(file);
- Properties properties = getAsProperties();
- properties.put("temp.file.template", tempFileTemplate);
- String tag;
- String user = System.getProperty("user.name");
- if (user != null) {
- tag = "; customized for " + user;
- properties.save(os, filePreamble + tag);
- }
- else {
- properties.save(os, filePreamble);
- }
- }
- catch (IOException e) {
- e.printStackTrace();
- return false;
- }
- finally {
- if (os != null) {
- try { os.close(); } catch (IOException e) {}
- }
- }
-
- return true;
- }
- /*
- * Debugging utilities
- *
- public void list(PrintStream out) {
- Enumeration keys = entries.keys();
- while (keys.hasMoreElements()) {
- String key = (String)keys.nextElement();
- MimeEntry entry = (MimeEntry)entries.get(key);
- out.println(key + ": " + entry);
- }
- }
-
- public static void main(String[] args) {
- MimeTable testTable = MimeTable.getDefaultTable();
-
- Enumeration e = testTable.elements();
- while (e.hasMoreElements()) {
- MimeEntry entry = (MimeEntry)e.nextElement();
- System.out.println(entry);
- }
-
- testTable.save(File.separator + "tmp" +
- File.separator + "mime_table.save");
- }
- */
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/gopher/GopherClient.java b/ojluni/src/main/java/sun/net/www/protocol/gopher/GopherClient.java
deleted file mode 100755
index dd19d40..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/gopher/GopherClient.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package sun.net.www.protocol.gopher;
-
-import java.io.*;
-import java.util.*;
-import java.net.*;
-import sun.net.www.*;
-import sun.net.NetworkClient;
-import java.net.URL;
-import java.net.URLStreamHandler;
-
-import sun.security.action.GetBooleanAction;
-
-/** Class to maintain the state of a gopher fetch and handle the protocol */
-public class GopherClient extends NetworkClient implements Runnable {
-
- /* The following three data members are left in for binary
- * backwards-compatibility. Unfortunately, HotJava sets them directly
- * when it wants to change the settings. The new design has us not
- * cache these, so this is unnecessary, but eliminating the data members
- * would break HJB 1.1 under JDK 1.2.
- *
- * These data members are not used, and their values are meaningless.
- * REMIND: Take them out for JDK 2.0!
- */
-
- /**
- * @deprecated
- */
- @Deprecated
- public static boolean useGopherProxy;
-
- /**
- * @deprecated
- */
- @Deprecated
- public static String gopherProxyHost;
-
- /**
- * @deprecated
- */
- @Deprecated
- public static int gopherProxyPort;
-
-
- static {
- useGopherProxy = java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction("gopherProxySet"))
- .booleanValue();
-
- gopherProxyHost = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("gopherProxyHost"));
-
- gopherProxyPort = java.security.AccessController.doPrivileged(
- new sun.security.action.GetIntegerAction("gopherProxyPort", 80))
- .intValue();
- }
-
- PipedOutputStream os;
- URL u;
- int gtype;
- String gkey;
- sun.net.www.URLConnection connection;
-
- GopherClient(sun.net.www.URLConnection connection) {
- this.connection = connection;
- }
-
- /**
- * @return true if gopher connections should go through a proxy, according
- * to system properties.
- */
- public static boolean getUseGopherProxy() {
- return java.security.AccessController.doPrivileged(
- new GetBooleanAction("gopherProxySet")).booleanValue();
- }
-
- /**
- * @return the proxy host to use, or null if nothing is set.
- */
- public static String getGopherProxyHost() {
- String host = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("gopherProxyHost"));
- if ("".equals(host)) {
- host = null;
- }
- return host;
- }
-
- /**
- * @return the proxy port to use. Will default reasonably.
- */
- public static int getGopherProxyPort() {
- return java.security.AccessController.doPrivileged(
- new sun.security.action.GetIntegerAction("gopherProxyPort", 80))
- .intValue();
- }
-
- /** Given a url, setup to fetch the gopher document it refers to */
- InputStream openStream(URL u) throws IOException {
- this.u = u;
- this.os = os;
- int i = 0;
- String s = u.getFile();
- int limit = s.length();
- int c = '1';
- while (i < limit && (c = s.charAt(i)) == '/')
- i++;
- gtype = c == '/' ? '1' : c;
- if (i < limit)
- i++;
- gkey = s.substring(i);
-
- openServer(u.getHost(), u.getPort() <= 0 ? 70 : u.getPort());
-
- MessageHeader msgh = new MessageHeader();
-
- switch (gtype) {
- case '0':
- case '7':
- msgh.add("content-type", "text/plain");
- break;
- case '1':
- msgh.add("content-type", "text/html");
- break;
- case 'g':
- case 'I':
- msgh.add("content-type", "image/gif");
- break;
- default:
- msgh.add("content-type", "content/unknown");
- break;
- }
- if (gtype != '7') {
- serverOutput.print(decodePercent(gkey) + "\r\n");
- serverOutput.flush();
- } else if ((i = gkey.indexOf('?')) >= 0) {
- serverOutput.print(decodePercent(gkey.substring(0, i) + "\t" +
- gkey.substring(i + 1) + "\r\n"));
- serverOutput.flush();
- msgh.add("content-type", "text/html");
- } else {
- msgh.add("content-type", "text/html");
- }
- connection.setProperties(msgh);
- if (msgh.findValue("content-type") == "text/html") {
- os = new PipedOutputStream();
- PipedInputStream ret = new PipedInputStream();
- ret.connect(os);
- new Thread(this).start();
- return ret;
- }
- return new GopherInputStream(this, serverInput);
- }
-
- /** Translate all the instances of %NN into the character they represent */
- private String decodePercent(String s) {
- if (s == null || s.indexOf('%') < 0)
- return s;
- int limit = s.length();
- char d[] = new char[limit];
- int dp = 0;
- for (int sp = 0; sp < limit; sp++) {
- int c = s.charAt(sp);
- if (c == '%' && sp + 2 < limit) {
- int s1 = s.charAt(sp + 1);
- int s2 = s.charAt(sp + 2);
- if ('0' <= s1 && s1 <= '9')
- s1 = s1 - '0';
- else if ('a' <= s1 && s1 <= 'f')
- s1 = s1 - 'a' + 10;
- else if ('A' <= s1 && s1 <= 'F')
- s1 = s1 - 'A' + 10;
- else
- s1 = -1;
- if ('0' <= s2 && s2 <= '9')
- s2 = s2 - '0';
- else if ('a' <= s2 && s2 <= 'f')
- s2 = s2 - 'a' + 10;
- else if ('A' <= s2 && s2 <= 'F')
- s2 = s2 - 'A' + 10;
- else
- s2 = -1;
- if (s1 >= 0 && s2 >= 0) {
- c = (s1 << 4) | s2;
- sp += 2;
- }
- }
- d[dp++] = (char) c;
- }
- return new String(d, 0, dp);
- }
-
- /** Turn special characters into the %NN form */
- private String encodePercent(String s) {
- if (s == null)
- return s;
- int limit = s.length();
- char d[] = null;
- int dp = 0;
- for (int sp = 0; sp < limit; sp++) {
- int c = s.charAt(sp);
- if (c <= ' ' || c == '"' || c == '%') {
- if (d == null)
- d = s.toCharArray();
- if (dp + 3 >= d.length) {
- char nd[] = new char[dp + 10];
- System.arraycopy(d, 0, nd, 0, dp);
- d = nd;
- }
- d[dp] = '%';
- int dig = (c >> 4) & 0xF;
- d[dp + 1] = (char) (dig < 10 ? '0' + dig : 'A' - 10 + dig);
- dig = c & 0xF;
- d[dp + 2] = (char) (dig < 10 ? '0' + dig : 'A' - 10 + dig);
- dp += 3;
- } else {
- if (d != null) {
- if (dp >= d.length) {
- char nd[] = new char[dp + 10];
- System.arraycopy(d, 0, nd, 0, dp);
- d = nd;
- }
- d[dp] = (char) c;
- }
- dp++;
- }
- }
- return d == null ? s : new String(d, 0, dp);
- }
-
- /** This method is run as a seperate thread when an incoming gopher
- document requires translation to html */
- public void run() {
- int qpos = -1;
- try {
- if (gtype == '7' && (qpos = gkey.indexOf('?')) < 0) {
- PrintStream ps = new PrintStream(os, false, encoding);
- ps.print("<html><head><title>Searchable Gopher Index</title></head>\n<body><h1>Searchable Gopher Index</h1><isindex>\n</body></html>\n");
- } else if (gtype != '1' && gtype != '7') {
- byte buf[] = new byte[2048];
- try {
- int n;
- while ((n = serverInput.read(buf)) >= 0)
- os.write(buf, 0, n);
- } catch(Exception e) {
- }
- } else {
- PrintStream ps = new PrintStream(os, false, encoding);
- String title = null;
- if (gtype == '7')
- title = "Results of searching for \"" + gkey.substring(qpos + 1)
- + "\" on " + u.getHost();
- else
- title = "Gopher directory " + gkey + " from " + u.getHost();
- ps.print("<html><head><title>");
- ps.print(title);
- ps.print("</title></head>\n<body>\n<H1>");
- ps.print(title);
- ps.print("</h1><dl compact>\n");
- DataInputStream ds = new DataInputStream(serverInput);
- String s;
- while ((s = ds.readLine()) != null) {
- int len = s.length();
- while (len > 0 && s.charAt(len - 1) <= ' ')
- len--;
- if (len <= 0)
- continue;
- int key = s.charAt(0);
- int t1 = s.indexOf('\t');
- int t2 = t1 > 0 ? s.indexOf('\t', t1 + 1) : -1;
- int t3 = t2 > 0 ? s.indexOf('\t', t2 + 1) : -1;
- if (t3 < 0) {
- // ps.print("<br><i>"+s+"</i>\n");
- continue;
- }
- String port = t3 + 1 < len ? ":" + s.substring(t3 + 1, len) : "";
- String host = t2 + 1 < t3 ? s.substring(t2 + 1, t3) : u.getHost();
- ps.print("<dt><a href=\"gopher://" + host + port + "/"
- + s.substring(0, 1) + encodePercent(s.substring(t1 + 1, t2)) + "\">\n");
- ps.print("<img align=middle border=0 width=25 height=32 src=");
- switch (key) {
- default:
- ps.print(System.getProperty("java.net.ftp.imagepath.file"));
- break;
- case '0':
- ps.print(System.getProperty("java.net.ftp.imagepath.text"));
- break;
- case '1':
- ps.print(System.getProperty("java.net.ftp.imagepath.directory"));
- break;
- case 'g':
- ps.print(System.getProperty("java.net.ftp.imagepath.gif"));
- break;
- }
- ps.print(".gif align=middle><dd>\n");
- ps.print(s.substring(1, t1) + "</a>\n");
- }
- ps.print("</dl></body>\n");
- ps.close();
- }
-
- } catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding+ " encoding not found");
- } catch (IOException e) {
- } finally {
- try {
- closeServer();
- os.close();
- } catch (IOException e2) {
- }
- }
- }
-}
-
-/** An input stream that does nothing more than hold on to the NetworkClient
- that created it. This is used when only the input stream is needed, and
- the network client needs to be closed when the input stream is closed. */
-class GopherInputStream extends FilterInputStream {
- NetworkClient parent;
-
- GopherInputStream(NetworkClient o, InputStream fd) {
- super(fd);
- parent = o;
- }
-
- public void close() {
- try {
- parent.closeServer();
- super.close();
- } catch (IOException e) {
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/gopher/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/gopher/Handler.java
deleted file mode 100755
index 8009859..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/gopher/Handler.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.protocol.gopher;
-
-import java.io.*;
-import java.util.*;
-import sun.net.NetworkClient;
-import java.net.URL;
-import java.net.URLStreamHandler;
-import java.net.Proxy;
-import java.net.InetSocketAddress;
-import java.net.SocketPermission;
-import java.security.Permission;
-import sun.net.www.protocol.http.HttpURLConnection;
-
-/**
- * A class to handle the gopher protocol.
- */
-
-public class Handler extends java.net.URLStreamHandler {
-
- protected int getDefaultPort() {
- return 70;
- }
-
- public java.net.URLConnection openConnection(URL u)
- throws IOException {
- return openConnection(u, null);
- }
-
- public java.net.URLConnection openConnection(URL u, Proxy p)
- throws IOException {
-
-
- /* if set for proxy usage then go through the http code to get */
- /* the url connection. */
- if (p == null && GopherClient.getUseGopherProxy()) {
- String host = GopherClient.getGopherProxyHost();
- if (host != null) {
- InetSocketAddress saddr = InetSocketAddress.createUnresolved(host, GopherClient.getGopherProxyPort());
-
- p = new Proxy(Proxy.Type.HTTP, saddr);
- }
- }
- if (p != null) {
- return new HttpURLConnection(u, p);
- }
-
- return new GopherURLConnection(u);
- }
-}
-
-class GopherURLConnection extends sun.net.www.URLConnection {
-
- Permission permission;
-
- GopherURLConnection(URL u) {
- super(u);
- }
-
- public void connect() throws IOException {
- }
-
- public InputStream getInputStream() throws IOException {
- return new GopherClient(this).openStream(url);
- }
-
- public Permission getPermission() {
- if (permission == null) {
- int port = url.getPort();
- port = port < 0 ? 70 : port;
- String host = url.getHost() + ":" + url.getPort();
- permission = new SocketPermission(host, "connect");
- }
- return permission;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java
deleted file mode 100755
index 05a6174..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2001, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.protocol.https;
-
-import java.net.URL;
-import java.net.Proxy;
-import java.net.SecureCacheResponse;
-import java.security.Principal;
-import java.io.IOException;
-import java.util.List;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import sun.net.www.http.*;
-import sun.net.www.protocol.http.HttpURLConnection;
-
-/**
- * HTTPS URL connection support.
- * We need this delegate because HttpsURLConnection is a subclass of
- * java.net.HttpURLConnection. We will avoid copying over the code from
- * sun.net.www.protocol.http.HttpURLConnection by having this class
- *
- */
-public abstract class AbstractDelegateHttpsURLConnection extends
- HttpURLConnection {
-
- protected AbstractDelegateHttpsURLConnection(URL url,
- sun.net.www.protocol.http.Handler handler) throws IOException {
- this(url, null, handler);
- }
-
- protected AbstractDelegateHttpsURLConnection(URL url, Proxy p,
- sun.net.www.protocol.http.Handler handler) throws IOException {
- super(url, p, handler);
- }
-
- protected abstract javax.net.ssl.SSLSocketFactory getSSLSocketFactory();
-
- protected abstract javax.net.ssl.HostnameVerifier getHostnameVerifier();
-
- /**
- * No user application is able to call these routines, as no one
- * should ever get access to an instance of
- * DelegateHttpsURLConnection (sun.* or com.*)
- */
-
- /**
- * Create a new HttpClient object, bypassing the cache of
- * HTTP client objects/connections.
- *
- * Note: this method is changed from protected to public because
- * the com.sun.ssl.internal.www.protocol.https handler reuses this
- * class for its actual implemantation
- *
- * @param url the URL being accessed
- */
- public void setNewClient (URL url)
- throws IOException {
- setNewClient (url, false);
- }
-
- /**
- * Obtain a HttpClient object. Use the cached copy if specified.
- *
- * Note: this method is changed from protected to public because
- * the com.sun.ssl.internal.www.protocol.https handler reuses this
- * class for its actual implemantation
- *
- * @param url the URL being accessed
- * @param useCache whether the cached connection should be used
- * if present
- */
- public void setNewClient (URL url, boolean useCache)
- throws IOException {
- http = HttpsClient.New (getSSLSocketFactory(),
- url,
- getHostnameVerifier(),
- useCache, this);
- ((HttpsClient)http).afterConnect();
- }
-
- /**
- * Create a new HttpClient object, set up so that it uses
- * per-instance proxying to the given HTTP proxy. This
- * bypasses the cache of HTTP client objects/connections.
- *
- * Note: this method is changed from protected to public because
- * the com.sun.ssl.internal.www.protocol.https handler reuses this
- * class for its actual implemantation
- *
- * @param url the URL being accessed
- * @param proxyHost the proxy host to use
- * @param proxyPort the proxy port to use
- */
- public void setProxiedClient (URL url, String proxyHost, int proxyPort)
- throws IOException {
- setProxiedClient(url, proxyHost, proxyPort, false);
- }
-
- /**
- * Obtain a HttpClient object, set up so that it uses per-instance
- * proxying to the given HTTP proxy. Use the cached copy of HTTP
- * client objects/connections if specified.
- *
- * Note: this method is changed from protected to public because
- * the com.sun.ssl.internal.www.protocol.https handler reuses this
- * class for its actual implemantation
- *
- * @param url the URL being accessed
- * @param proxyHost the proxy host to use
- * @param proxyPort the proxy port to use
- * @param useCache whether the cached connection should be used
- * if present
- */
- public void setProxiedClient (URL url, String proxyHost, int proxyPort,
- boolean useCache) throws IOException {
- proxiedConnect(url, proxyHost, proxyPort, useCache);
- if (!http.isCachedConnection()) {
- doTunneling();
- }
- ((HttpsClient)http).afterConnect();
- }
-
- protected void proxiedConnect(URL url, String proxyHost, int proxyPort,
- boolean useCache) throws IOException {
- if (connected)
- return;
- http = HttpsClient.New (getSSLSocketFactory(),
- url,
- getHostnameVerifier(),
- proxyHost, proxyPort, useCache, this);
- connected = true;
- }
-
- /**
- * Used by subclass to access "connected" variable.
- */
- public boolean isConnected() {
- return connected;
- }
-
- /**
- * Used by subclass to access "connected" variable.
- */
- public void setConnected(boolean conn) {
- connected = conn;
- }
-
- /**
- * Implements the HTTP protocol handler's "connect" method,
- * establishing an SSL connection to the server as necessary.
- */
- public void connect() throws IOException {
- if (connected)
- return;
- plainConnect();
- if (cachedResponse != null) {
- // using cached response
- return;
- }
- if (!http.isCachedConnection() && http.needsTunneling()) {
- doTunneling();
- }
- ((HttpsClient)http).afterConnect();
- }
-
- // will try to use cached HttpsClient
- protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout)
- throws IOException {
- return HttpsClient.New(getSSLSocketFactory(), url,
- getHostnameVerifier(), p, true, connectTimeout,
- this);
- }
-
- // will open new connection
- protected HttpClient getNewHttpClient(URL url, Proxy p, int connectTimeout,
- boolean useCache)
- throws IOException {
- return HttpsClient.New(getSSLSocketFactory(), url,
- getHostnameVerifier(), p,
- useCache, connectTimeout, this);
- }
-
- /**
- * Returns the cipher suite in use on this connection.
- */
- public String getCipherSuite () {
- if (cachedResponse != null) {
- return ((SecureCacheResponse)cachedResponse).getCipherSuite();
- }
- if (http == null) {
- throw new IllegalStateException("connection not yet open");
- } else {
- return ((HttpsClient)http).getCipherSuite ();
- }
- }
-
- /**
- * Returns the certificate chain the client sent to the
- * server, or null if the client did not authenticate.
- */
- public java.security.cert.Certificate[] getLocalCertificates() {
- if (cachedResponse != null) {
- List l = ((SecureCacheResponse)cachedResponse).getLocalCertificateChain();
- if (l == null) {
- return null;
- } else {
- return (java.security.cert.Certificate[])l.toArray();
- }
- }
- if (http == null) {
- throw new IllegalStateException("connection not yet open");
- } else {
- return (((HttpsClient)http).getLocalCertificates ());
- }
- }
-
- /**
- * Returns the server's certificate chain, or throws
- * SSLPeerUnverified Exception if
- * the server did not authenticate.
- */
- public java.security.cert.Certificate[] getServerCertificates()
- throws SSLPeerUnverifiedException {
- if (cachedResponse != null) {
- List l = ((SecureCacheResponse)cachedResponse).getServerCertificateChain();
- if (l == null) {
- return null;
- } else {
- return (java.security.cert.Certificate[])l.toArray();
- }
- }
-
- if (http == null) {
- throw new IllegalStateException("connection not yet open");
- } else {
- return (((HttpsClient)http).getServerCertificates ());
- }
- }
-
- /**
- * Returns the server's X.509 certificate chain, or null if
- * the server did not authenticate.
- */
- public javax.security.cert.X509Certificate[] getServerCertificateChain()
- throws SSLPeerUnverifiedException {
- if (cachedResponse != null) {
- throw new UnsupportedOperationException("this method is not supported when using cache");
- }
- if (http == null) {
- throw new IllegalStateException("connection not yet open");
- } else {
- return ((HttpsClient)http).getServerCertificateChain ();
- }
- }
-
- /**
- * Returns the server's principal, or throws SSLPeerUnverifiedException
- * if the server did not authenticate.
- */
- Principal getPeerPrincipal()
- throws SSLPeerUnverifiedException
- {
- if (cachedResponse != null) {
- return ((SecureCacheResponse)cachedResponse).getPeerPrincipal();
- }
-
- if (http == null) {
- throw new IllegalStateException("connection not yet open");
- } else {
- return (((HttpsClient)http).getPeerPrincipal());
- }
- }
-
- /**
- * Returns the principal the client sent to the
- * server, or null if the client did not authenticate.
- */
- Principal getLocalPrincipal()
- {
- if (cachedResponse != null) {
- return ((SecureCacheResponse)cachedResponse).getLocalPrincipal();
- }
-
- if (http == null) {
- throw new IllegalStateException("connection not yet open");
- } else {
- return (((HttpsClient)http).getLocalPrincipal());
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/https/DelegateHttpsURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/https/DelegateHttpsURLConnection.java
deleted file mode 100755
index b6ff7b4..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/https/DelegateHttpsURLConnection.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.protocol.https;
-
-import java.net.URL;
-import java.net.Proxy;
-import java.io.IOException;
-
-/**
- * This class was introduced to provide an additional level of
- * abstraction between javax.net.ssl.HttpURLConnection and
- * com.sun.net.ssl.HttpURLConnection objects. <p>
- *
- * javax.net.ssl.HttpURLConnection is used in the new sun.net version
- * of protocol implementation (this one)
- * com.sun.net.ssl.HttpURLConnection is used in the com.sun version.
- *
- */
-public class DelegateHttpsURLConnection extends AbstractDelegateHttpsURLConnection {
-
- // we need a reference to the HttpsURLConnection to get
- // the properties set there
- // we also need it to be public so that it can be referenced
- // from sun.net.www.protocol.http.HttpURLConnection
- // this is for ResponseCache.put(URI, URLConnection)
- // second parameter needs to be cast to javax.net.ssl.HttpsURLConnection
- // instead of AbstractDelegateHttpsURLConnection
- public javax.net.ssl.HttpsURLConnection httpsURLConnection;
-
- DelegateHttpsURLConnection(URL url,
- sun.net.www.protocol.http.Handler handler,
- javax.net.ssl.HttpsURLConnection httpsURLConnection)
- throws IOException {
- this(url, null, handler, httpsURLConnection);
- }
-
- DelegateHttpsURLConnection(URL url, Proxy p,
- sun.net.www.protocol.http.Handler handler,
- javax.net.ssl.HttpsURLConnection httpsURLConnection)
- throws IOException {
- super(url, p, handler);
- this.httpsURLConnection = httpsURLConnection;
- }
-
- protected javax.net.ssl.SSLSocketFactory getSSLSocketFactory() {
- return httpsURLConnection.getSSLSocketFactory();
- }
-
- protected javax.net.ssl.HostnameVerifier getHostnameVerifier() {
- return httpsURLConnection.getHostnameVerifier();
- }
-
- /*
- * Called by layered delegator's finalize() method to handle closing
- * the underlying object.
- */
- protected void dispose() throws Throwable {
- super.finalize();
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/https/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/https/Handler.java
deleted file mode 100755
index d2be7fd..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/https/Handler.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*-
- * HTTP stream opener
- */
-
-package sun.net.www.protocol.https;
-
-import java.io.IOException;
-import java.net.URL;
-import java.net.Proxy;
-
-/** open an http input stream given a URL */
-public class Handler extends sun.net.www.protocol.http.Handler {
- protected String proxy;
- protected int proxyPort;
-
- protected int getDefaultPort() {
- return 443;
- }
-
- public Handler () {
- proxy = null;
- proxyPort = -1;
- }
-
- public Handler (String proxy, int port) {
- this.proxy = proxy;
- this.proxyPort = port;
- }
-
- protected java.net.URLConnection openConnection(URL u)
- throws IOException {
- return openConnection(u, (Proxy)null);
- }
-
- protected java.net.URLConnection openConnection(URL u, Proxy p)
- throws IOException {
- return new HttpsURLConnectionImpl(u, p, this);
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/https/HttpsClient.java b/ojluni/src/main/java/sun/net/www/protocol/https/HttpsClient.java
deleted file mode 100755
index 91a5329..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/https/HttpsClient.java
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.net.www.protocol.https;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.io.PrintStream;
-import java.io.BufferedOutputStream;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketException;
-import java.net.URL;
-import java.net.UnknownHostException;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.security.Principal;
-import java.security.cert.*;
-import java.util.StringTokenizer;
-import java.util.Vector;
-import java.security.AccessController;
-
-import javax.security.auth.x500.X500Principal;
-
-import javax.net.ssl.*;
-import sun.net.www.http.HttpClient;
-import sun.net.www.protocol.http.HttpURLConnection;
-import sun.security.action.*;
-
-import sun.security.util.HostnameChecker;
-import sun.security.ssl.SSLSocketImpl;
-
-import sun.util.logging.PlatformLogger;
-import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*;
-
-
-/**
- * This class provides HTTPS client URL support, building on the standard
- * "sun.net.www" HTTP protocol handler. HTTPS is the same protocol as HTTP,
- * but differs in the transport layer which it uses: <UL>
- *
- * <LI>There's a <em>Secure Sockets Layer</em> between TCP
- * and the HTTP protocol code.
- *
- * <LI>It uses a different default TCP port.
- *
- * <LI>It doesn't use application level proxies, which can see and
- * manipulate HTTP user level data, compromising privacy. It uses
- * low level tunneling instead, which hides HTTP protocol and data
- * from all third parties. (Traffic analysis is still possible).
- *
- * <LI>It does basic server authentication, to protect
- * against "URL spoofing" attacks. This involves deciding
- * whether the X.509 certificate chain identifying the server
- * is trusted, and verifying that the name of the server is
- * found in the certificate. (The application may enable an
- * anonymous SSL cipher suite, and such checks are not done
- * for anonymous ciphers.)
- *
- * <LI>It exposes key SSL session attributes, specifically the
- * cipher suite in use and the server's X509 certificates, to
- * application software which knows about this protocol handler.
- *
- * </UL>
- *
- * <P> System properties used include: <UL>
- *
- * <LI><em>https.proxyHost</em> ... the host supporting SSL
- * tunneling using the conventional CONNECT syntax
- *
- * <LI><em>https.proxyPort</em> ... port to use on proxyHost
- *
- * <LI><em>https.cipherSuites</em> ... comma separated list of
- * SSL cipher suite names to enable.
- *
- * <LI><em>http.nonProxyHosts</em> ...
- *
- * </UL>
- *
- * @author David Brownell
- * @author Bill Foote
- */
-
-// final for export control reasons (access to APIs); remove with care
-final class HttpsClient extends HttpClient
- implements HandshakeCompletedListener
-{
- // STATIC STATE and ACCESSORS THERETO
-
- // HTTPS uses a different default port number than HTTP.
- private static final int httpsPortNumber = 443;
-
- // default HostnameVerifier class canonical name
- private static final String defaultHVCanonicalName =
- "javax.net.ssl.DefaultHostnameVerifier";
-
- /** Returns the default HTTPS port (443) */
- @Override
- protected int getDefaultPort() { return httpsPortNumber; }
-
- private HostnameVerifier hv;
- private SSLSocketFactory sslSocketFactory;
-
- // HttpClient.proxyDisabled will always be false, because we don't
- // use an application-level HTTP proxy. We might tunnel through
- // our http proxy, though.
-
-
- // INSTANCE DATA
-
- // last negotiated SSL session
- private SSLSession session;
-
- private String [] getCipherSuites() {
- //
- // If ciphers are assigned, sort them into an array.
- //
- String ciphers [];
- String cipherString = AccessController.doPrivileged(
- new GetPropertyAction("https.cipherSuites"));
-
- if (cipherString == null || "".equals(cipherString)) {
- ciphers = null;
- } else {
- StringTokenizer tokenizer;
- Vector<String> v = new Vector<String>();
-
- tokenizer = new StringTokenizer(cipherString, ",");
- while (tokenizer.hasMoreTokens())
- v.addElement(tokenizer.nextToken());
- ciphers = new String [v.size()];
- for (int i = 0; i < ciphers.length; i++)
- ciphers [i] = v.elementAt(i);
- }
- return ciphers;
- }
-
- private String [] getProtocols() {
- //
- // If protocols are assigned, sort them into an array.
- //
- String protocols [];
- String protocolString = AccessController.doPrivileged(
- new GetPropertyAction("https.protocols"));
-
- if (protocolString == null || "".equals(protocolString)) {
- protocols = null;
- } else {
- StringTokenizer tokenizer;
- Vector<String> v = new Vector<String>();
-
- tokenizer = new StringTokenizer(protocolString, ",");
- while (tokenizer.hasMoreTokens())
- v.addElement(tokenizer.nextToken());
- protocols = new String [v.size()];
- for (int i = 0; i < protocols.length; i++) {
- protocols [i] = v.elementAt(i);
- }
- }
- return protocols;
- }
-
- private String getUserAgent() {
- String userAgent = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("https.agent"));
- if (userAgent == null || userAgent.length() == 0) {
- userAgent = "JSSE";
- }
- return userAgent;
- }
-
- // should remove once HttpClient.newHttpProxy is putback
- private static Proxy newHttpProxy(String proxyHost, int proxyPort) {
- InetSocketAddress saddr = null;
- final String phost = proxyHost;
- final int pport = proxyPort < 0 ? httpsPortNumber : proxyPort;
- try {
- saddr = java.security.AccessController.doPrivileged(new
- java.security.PrivilegedExceptionAction<InetSocketAddress>() {
- public InetSocketAddress run() {
- return new InetSocketAddress(phost, pport);
- }});
- } catch (java.security.PrivilegedActionException pae) {
- }
- return new Proxy(Proxy.Type.HTTP, saddr);
- }
-
- // CONSTRUCTOR, FACTORY
-
-
- /**
- * Create an HTTPS client URL. Traffic will be tunneled through any
- * intermediate nodes rather than proxied, so that confidentiality
- * of data exchanged can be preserved. However, note that all the
- * anonymous SSL flavors are subject to "person-in-the-middle"
- * attacks against confidentiality. If you enable use of those
- * flavors, you may be giving up the protection you get through
- * SSL tunneling.
- *
- * Use New to get new HttpsClient. This constructor is meant to be
- * used only by New method. New properly checks for URL spoofing.
- *
- * @param URL https URL with which a connection must be established
- */
- private HttpsClient(SSLSocketFactory sf, URL url)
- throws IOException
- {
- // HttpClient-level proxying is always disabled,
- // because we override doConnect to do tunneling instead.
- this(sf, url, (String)null, -1);
- }
-
- /**
- * Create an HTTPS client URL. Traffic will be tunneled through
- * the specified proxy server.
- */
- HttpsClient(SSLSocketFactory sf, URL url, String proxyHost, int proxyPort)
- throws IOException {
- this(sf, url, proxyHost, proxyPort, -1);
- }
-
- /**
- * Create an HTTPS client URL. Traffic will be tunneled through
- * the specified proxy server, with a connect timeout
- */
- HttpsClient(SSLSocketFactory sf, URL url, String proxyHost, int proxyPort,
- int connectTimeout)
- throws IOException {
- this(sf, url,
- (proxyHost == null? null:
- HttpsClient.newHttpProxy(proxyHost, proxyPort)),
- connectTimeout);
- }
-
- /**
- * Same as previous constructor except using a Proxy
- */
- HttpsClient(SSLSocketFactory sf, URL url, Proxy proxy,
- int connectTimeout)
- throws IOException {
- this.proxy = proxy;
- setSSLSocketFactory(sf);
- this.proxyDisabled = true;
-
- this.host = url.getHost();
- this.url = url;
- port = url.getPort();
- if (port == -1) {
- port = getDefaultPort();
- }
- setConnectTimeout(connectTimeout);
- openServer();
- }
-
-
- // This code largely ripped off from HttpClient.New, and
- // it uses the same keepalive cache.
-
- static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
- HttpURLConnection httpuc)
- throws IOException {
- return HttpsClient.New(sf, url, hv, true, httpuc);
- }
-
- /** See HttpClient for the model for this method. */
- static HttpClient New(SSLSocketFactory sf, URL url,
- HostnameVerifier hv, boolean useCache,
- HttpURLConnection httpuc) throws IOException {
- return HttpsClient.New(sf, url, hv, (String)null, -1, useCache, httpuc);
- }
-
- /**
- * Get a HTTPS client to the URL. Traffic will be tunneled through
- * the specified proxy server.
- */
- static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
- String proxyHost, int proxyPort,
- HttpURLConnection httpuc) throws IOException {
- return HttpsClient.New(sf, url, hv, proxyHost, proxyPort, true, httpuc);
- }
-
- static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
- String proxyHost, int proxyPort, boolean useCache,
- HttpURLConnection httpuc)
- throws IOException {
- return HttpsClient.New(sf, url, hv, proxyHost, proxyPort, useCache, -1,
- httpuc);
- }
-
- static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
- String proxyHost, int proxyPort, boolean useCache,
- int connectTimeout, HttpURLConnection httpuc)
- throws IOException {
-
- return HttpsClient.New(sf, url, hv,
- (proxyHost == null? null :
- HttpsClient.newHttpProxy(proxyHost, proxyPort)),
- useCache, connectTimeout, httpuc);
- }
-
- static HttpClient New(SSLSocketFactory sf, URL url, HostnameVerifier hv,
- Proxy p, boolean useCache,
- int connectTimeout, HttpURLConnection httpuc)
- throws IOException
- {
- if (p == null) {
- p = Proxy.NO_PROXY;
- }
- HttpsClient ret = null;
- if (useCache) {
- /* see if one's already around */
- ret = (HttpsClient) kac.get(url, sf);
- if (ret != null && httpuc != null &&
- httpuc.streaming() &&
- httpuc.getRequestMethod() == "POST") {
- if (!ret.available())
- ret = null;
- }
-
- if (ret != null) {
- if ((ret.proxy != null && ret.proxy.equals(p)) ||
- (ret.proxy == null && p == null)) {
- synchronized (ret) {
- ret.cachedHttpClient = true;
- assert ret.inCache;
- ret.inCache = false;
- if (httpuc != null && ret.needsTunneling())
- httpuc.setTunnelState(TUNNELING);
- PlatformLogger logger = HttpURLConnection.getHttpLogger();
- if (logger.isLoggable(PlatformLogger.FINEST)) {
- logger.finest("KeepAlive stream retrieved from the cache, " + ret);
- }
- }
- } else {
- // We cannot return this connection to the cache as it's
- // KeepAliveTimeout will get reset. We simply close the connection.
- // This should be fine as it is very rare that a connection
- // to the same host will not use the same proxy.
- synchronized(ret) {
- ret.inCache = false;
- ret.closeServer();
- }
- ret = null;
- }
- }
- }
- if (ret == null) {
- ret = new HttpsClient(sf, url, p, connectTimeout);
- } else {
- SecurityManager security = System.getSecurityManager();
- if (security != null) {
- if (ret.proxy == Proxy.NO_PROXY || ret.proxy == null) {
- security.checkConnect(InetAddress.getByName(url.getHost()).getHostAddress(), url.getPort());
- } else {
- security.checkConnect(url.getHost(), url.getPort());
- }
- }
- ret.url = url;
- }
- ret.setHostnameVerifier(hv);
-
- return ret;
- }
-
- // METHODS
- void setHostnameVerifier(HostnameVerifier hv) {
- this.hv = hv;
- }
-
- void setSSLSocketFactory(SSLSocketFactory sf) {
- sslSocketFactory = sf;
- }
-
- SSLSocketFactory getSSLSocketFactory() {
- return sslSocketFactory;
- }
-
- /**
- * The following method, createSocket, is defined in NetworkClient
- * and overridden here so that the socket facroty is used to create
- * new sockets.
- */
- @Override
- protected Socket createSocket() throws IOException {
- try {
- return sslSocketFactory.createSocket();
- } catch (SocketException se) {
- //
- // bug 6771432
- // javax.net.SocketFactory throws a SocketException with an
- // UnsupportedOperationException as its cause to indicate that
- // unconnected sockets have not been implemented.
- //
- Throwable t = se.getCause();
- if (t != null && t instanceof UnsupportedOperationException) {
- return super.createSocket();
- } else {
- throw se;
- }
- }
- }
-
-
- @Override
- public boolean needsTunneling() {
- return (proxy != null && proxy.type() != Proxy.Type.DIRECT
- && proxy.type() != Proxy.Type.SOCKS);
- }
-
- @Override
- public void afterConnect() throws IOException, UnknownHostException {
- if (!isCachedConnection()) {
- SSLSocket s = null;
- SSLSocketFactory factory = sslSocketFactory;
- try {
- if (!(serverSocket instanceof SSLSocket)) {
- s = (SSLSocket)factory.createSocket(serverSocket,
- host, port, true);
- } else {
- s = (SSLSocket)serverSocket;
- if (s instanceof SSLSocketImpl) {
- ((SSLSocketImpl)s).setHost(host);
- }
- }
- } catch (IOException ex) {
- // If we fail to connect through the tunnel, try it
- // locally, as a last resort. If this doesn't work,
- // throw the original exception.
- try {
- s = (SSLSocket)factory.createSocket(host, port);
- } catch (IOException ignored) {
- throw ex;
- }
- }
-
- //
- // Force handshaking, so that we get any authentication.
- // Register a handshake callback so our session state tracks any
- // later session renegotiations.
- //
- String [] protocols = getProtocols();
- String [] ciphers = getCipherSuites();
- if (protocols != null) {
- s.setEnabledProtocols(protocols);
- }
- if (ciphers != null) {
- s.setEnabledCipherSuites(ciphers);
- }
- s.addHandshakeCompletedListener(this);
-
- // We have two hostname verification approaches. One is in
- // SSL/TLS socket layer, where the algorithm is configured with
- // SSLParameters.setEndpointIdentificationAlgorithm(), and the
- // hostname verification is done by X509ExtendedTrustManager when
- // the algorithm is "HTTPS". The other one is in HTTPS layer,
- // where the algorithm is customized by
- // HttpsURLConnection.setHostnameVerifier(), and the hostname
- // verification is done by HostnameVerifier when the default
- // rules for hostname verification fail.
- //
- // The relationship between two hostname verification approaches
- // likes the following:
- //
- // | EIA algorithm
- // +----------------------------------------------
- // | null | HTTPS | LDAP/other |
- // -------------------------------------------------------------
- // | |1 |2 |3 |
- // HNV | default | Set HTTPS EIA | use EIA | HTTPS |
- // |--------------------------------------------------------
- // | non - |4 |5 |6 |
- // | default | HTTPS/HNV | use EIA | HTTPS/HNV |
- // -------------------------------------------------------------
- //
- // Abbreviation:
- // EIA: the endpoint identification algorithm in SSL/TLS
- // socket layer
- // HNV: the hostname verification object in HTTPS layer
- // Notes:
- // case 1. default HNV and EIA is null
- // Set EIA as HTTPS, hostname check done in SSL/TLS
- // layer.
- // case 2. default HNV and EIA is HTTPS
- // Use existing EIA, hostname check done in SSL/TLS
- // layer.
- // case 3. default HNV and EIA is other than HTTPS
- // Use existing EIA, EIA check done in SSL/TLS
- // layer, then do HTTPS check in HTTPS layer.
- // case 4. non-default HNV and EIA is null
- // No EIA, no EIA check done in SSL/TLS layer, then do
- // HTTPS check in HTTPS layer using HNV as override.
- // case 5. non-default HNV and EIA is HTTPS
- // Use existing EIA, hostname check done in SSL/TLS
- // layer. No HNV override possible. We will review this
- // decision and may update the architecture for JDK 7.
- // case 6. non-default HNV and EIA is other than HTTPS
- // Use existing EIA, EIA check done in SSL/TLS layer,
- // then do HTTPS check in HTTPS layer as override.
- boolean needToCheckSpoofing = true;
- String identification =
- s.getSSLParameters().getEndpointIdentificationAlgorithm();
- if (identification != null && identification.length() != 0) {
- if (identification.equalsIgnoreCase("HTTPS")) {
- // Do not check server identity again out of SSLSocket,
- // the endpoint will be identified during TLS handshaking
- // in SSLSocket.
- needToCheckSpoofing = false;
- } // else, we don't understand the identification algorithm,
- // need to check URL spoofing here.
- } else {
- boolean isDefaultHostnameVerifier = false;
-
- // We prefer to let the SSLSocket do the spoof checks, but if
- // the application has specified a HostnameVerifier (HNV),
- // we will always use that.
- if (hv != null) {
- String canonicalName = hv.getClass().getCanonicalName();
- if (canonicalName != null &&
- canonicalName.equalsIgnoreCase(defaultHVCanonicalName)) {
- isDefaultHostnameVerifier = true;
- }
- } else {
- // Unlikely to happen! As the behavior is the same as the
- // default hostname verifier, so we prefer to let the
- // SSLSocket do the spoof checks.
- isDefaultHostnameVerifier = true;
- }
-
- if (isDefaultHostnameVerifier) {
- // If the HNV is the default from HttpsURLConnection, we
- // will do the spoof checks in SSLSocket.
- SSLParameters paramaters = s.getSSLParameters();
- paramaters.setEndpointIdentificationAlgorithm("HTTPS");
- s.setSSLParameters(paramaters);
-
- needToCheckSpoofing = false;
- }
- }
-
- s.startHandshake();
- session = s.getSession();
- // change the serverSocket and serverOutput
- serverSocket = s;
- try {
- serverOutput = new PrintStream(
- new BufferedOutputStream(serverSocket.getOutputStream()),
- false, encoding);
- } catch (UnsupportedEncodingException e) {
- throw new InternalError(encoding+" encoding not found");
- }
-
- // check URL spoofing if it has not been checked under handshaking
- if (needToCheckSpoofing) {
- checkURLSpoofing(hv);
- }
- } else {
- // if we are reusing a cached https session,
- // we don't need to do handshaking etc. But we do need to
- // set the ssl session
- session = ((SSLSocket)serverSocket).getSession();
- }
- }
-
- // Server identity checking is done according to RFC 2818: HTTP over TLS
- // Section 3.1 Server Identity
- private void checkURLSpoofing(HostnameVerifier hostnameVerifier)
- throws IOException {
- //
- // Get authenticated server name, if any
- //
- String host = url.getHost();
-
- // if IPv6 strip off the "[]"
- if (host != null && host.startsWith("[") && host.endsWith("]")) {
- host = host.substring(1, host.length()-1);
- }
-
- Certificate[] peerCerts = null;
- String cipher = session.getCipherSuite();
- try {
- HostnameChecker checker = HostnameChecker.getInstance(
- HostnameChecker.TYPE_TLS);
-
- // Use ciphersuite to determine whether Kerberos is present.
- if (cipher.startsWith("TLS_KRB5")) {
- if (!HostnameChecker.match(host, getPeerPrincipal())) {
- throw new SSLPeerUnverifiedException("Hostname checker" +
- " failed for Kerberos");
- }
- } else { // X.509
-
- // get the subject's certificate
- peerCerts = session.getPeerCertificates();
-
- X509Certificate peerCert;
- if (peerCerts[0] instanceof
- java.security.cert.X509Certificate) {
- peerCert = (java.security.cert.X509Certificate)peerCerts[0];
- } else {
- throw new SSLPeerUnverifiedException("");
- }
- checker.match(host, peerCert);
- }
-
- // if it doesn't throw an exception, we passed. Return.
- return;
-
- } catch (SSLPeerUnverifiedException e) {
-
- //
- // client explicitly changed default policy and enabled
- // anonymous ciphers; we can't check the standard policy
- //
- // ignore
- } catch (java.security.cert.CertificateException cpe) {
- // ignore
- }
-
- if ((cipher != null) && (cipher.indexOf("_anon_") != -1)) {
- return;
- } else if ((hostnameVerifier != null) &&
- (hostnameVerifier.verify(host, session))) {
- return;
- }
-
- serverSocket.close();
- session.invalidate();
-
- throw new IOException("HTTPS hostname wrong: should be <"
- + url.getHost() + ">");
- }
-
- @Override
- protected void putInKeepAliveCache() {
- if (inCache) {
- assert false : "Duplicate put to keep alive cache";
- return;
- }
- inCache = true;
- kac.put(url, sslSocketFactory, this);
- }
-
- /*
- * Close an idle connection to this URL (if it exists in the cache).
- */
- @Override
- public void closeIdleConnection() {
- HttpClient http = (HttpClient) kac.get(url, sslSocketFactory);
- if (http != null) {
- http.closeServer();
- }
- }
-
- /**
- * Returns the cipher suite in use on this connection.
- */
- String getCipherSuite() {
- return session.getCipherSuite();
- }
-
- /**
- * Returns the certificate chain the client sent to the
- * server, or null if the client did not authenticate.
- */
- public java.security.cert.Certificate [] getLocalCertificates() {
- return session.getLocalCertificates();
- }
-
- /**
- * Returns the certificate chain with which the server
- * authenticated itself, or throw a SSLPeerUnverifiedException
- * if the server did not authenticate.
- */
- java.security.cert.Certificate [] getServerCertificates()
- throws SSLPeerUnverifiedException
- {
- return session.getPeerCertificates();
- }
-
- /**
- * Returns the X.509 certificate chain with which the server
- * authenticated itself, or null if the server did not authenticate.
- */
- javax.security.cert.X509Certificate [] getServerCertificateChain()
- throws SSLPeerUnverifiedException
- {
- return session.getPeerCertificateChain();
- }
-
- /**
- * Returns the principal with which the server authenticated
- * itself, or throw a SSLPeerUnverifiedException if the
- * server did not authenticate.
- */
- Principal getPeerPrincipal()
- throws SSLPeerUnverifiedException
- {
- Principal principal;
- try {
- principal = session.getPeerPrincipal();
- } catch (AbstractMethodError e) {
- // if the provider does not support it, fallback to peer certs.
- // return the X500Principal of the end-entity cert.
- java.security.cert.Certificate[] certs =
- session.getPeerCertificates();
- principal = (X500Principal)
- ((X509Certificate)certs[0]).getSubjectX500Principal();
- }
- return principal;
- }
-
- /**
- * Returns the principal the client sent to the
- * server, or null if the client did not authenticate.
- */
- Principal getLocalPrincipal()
- {
- Principal principal;
- try {
- principal = session.getLocalPrincipal();
- } catch (AbstractMethodError e) {
- principal = null;
- // if the provider does not support it, fallback to local certs.
- // return the X500Principal of the end-entity cert.
- java.security.cert.Certificate[] certs =
- session.getLocalCertificates();
- if (certs != null) {
- principal = (X500Principal)
- ((X509Certificate)certs[0]).getSubjectX500Principal();
- }
- }
- return principal;
- }
-
- /**
- * This method implements the SSL HandshakeCompleted callback,
- * remembering the resulting session so that it may be queried
- * for the current cipher suite and peer certificates. Servers
- * sometimes re-initiate handshaking, so the session in use on
- * a given connection may change. When sessions change, so may
- * peer identities and cipher suites.
- */
- public void handshakeCompleted(HandshakeCompletedEvent event)
- {
- session = event.getSession();
- }
-
- /**
- * @return the proxy host being used for this client, or null
- * if we're not going through a proxy
- */
- @Override
- public String getProxyHostUsed() {
- if (!needsTunneling()) {
- return null;
- } else {
- return super.getProxyHostUsed();
- }
- }
-
- /**
- * @return the proxy port being used for this client. Meaningless
- * if getProxyHostUsed() gives null.
- */
- @Override
- public int getProxyPortUsed() {
- return (proxy == null || proxy.type() == Proxy.Type.DIRECT ||
- proxy.type() == Proxy.Type.SOCKS)? -1:
- ((InetSocketAddress)proxy.address()).getPort();
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/https/HttpsURLConnectionImpl.java b/ojluni/src/main/java/sun/net/www/protocol/https/HttpsURLConnectionImpl.java
deleted file mode 100755
index 832854c..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/https/HttpsURLConnectionImpl.java
+++ /dev/null
@@ -1,537 +0,0 @@
-/*
- * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * NOTE: This class lives in the package sun.net.www.protocol.https.
- * There is a copy in com.sun.net.ssl.internal.www.protocol.https for JSSE
- * 1.0.2 compatibility. It is 100% identical except the package and extends
- * lines. Any changes should be made to be class in sun.net.* and then copied
- * to com.sun.net.*.
- */
-
-// For both copies of the file, uncomment one line and comment the other
-package sun.net.www.protocol.https;
-// package com.sun.net.ssl.internal.www.protocol.https;
-
-import java.net.URL;
-import java.net.Proxy;
-import java.net.ProtocolException;
-import java.io.*;
-import javax.net.ssl.*;
-import java.security.Permission;
-import java.security.Principal;
-import java.util.Map;
-import java.util.List;
-import sun.net.www.http.HttpClient;
-
-/**
- * A class to represent an HTTP connection to a remote object.
- *
- * Ideally, this class should subclass and inherit the http handler
- * implementation, but it can't do so because that class have the
- * wrong Java Type. Thus it uses the delegate (aka, the
- * Adapter/Wrapper design pattern) to reuse code from the http
- * handler.
- *
- * Since it would use a delegate to access
- * sun.net.www.protocol.http.HttpURLConnection functionalities, it
- * needs to implement all public methods in it's super class and all
- * the way to Object.
- *
- */
-
-// For both copies of the file, uncomment one line and comment the
-// other. The differences between the two copies are introduced for
-// plugin, and it is marked as such.
-public class HttpsURLConnectionImpl
- extends javax.net.ssl.HttpsURLConnection {
-// public class HttpsURLConnectionOldImpl
-// extends com.sun.net.ssl.HttpsURLConnection {
-
- // NOTE: made protected for plugin so that subclass can set it.
- protected DelegateHttpsURLConnection delegate;
-
-// For both copies of the file, uncomment one line and comment the other
- HttpsURLConnectionImpl(URL u, Handler handler) throws IOException {
-// HttpsURLConnectionOldImpl(URL u, Handler handler) throws IOException {
- this(u, null, handler);
- }
-
-// For both copies of the file, uncomment one line and comment the other
- HttpsURLConnectionImpl(URL u, Proxy p, Handler handler) throws IOException {
-// HttpsURLConnectionOldImpl(URL u, Proxy p, Handler handler) throws IOException {
- super(u);
- delegate = new DelegateHttpsURLConnection(url, p, handler, this);
- }
-
- // NOTE: introduced for plugin
- // subclass needs to overwrite this to set delegate to
- // the appropriate delegatee
- protected HttpsURLConnectionImpl(URL u) throws IOException {
- super(u);
- }
-
- /**
- * Create a new HttpClient object, bypassing the cache of
- * HTTP client objects/connections.
- *
- * @param url the URL being accessed
- */
- protected void setNewClient(URL url) throws IOException {
- delegate.setNewClient(url, false);
- }
-
- /**
- * Obtain a HttpClient object. Use the cached copy if specified.
- *
- * @param url the URL being accessed
- * @param useCache whether the cached connection should be used
- * if present
- */
- protected void setNewClient(URL url, boolean useCache)
- throws IOException {
- delegate.setNewClient(url, useCache);
- }
-
- /**
- * Create a new HttpClient object, set up so that it uses
- * per-instance proxying to the given HTTP proxy. This
- * bypasses the cache of HTTP client objects/connections.
- *
- * @param url the URL being accessed
- * @param proxyHost the proxy host to use
- * @param proxyPort the proxy port to use
- */
- protected void setProxiedClient(URL url, String proxyHost, int proxyPort)
- throws IOException {
- delegate.setProxiedClient(url, proxyHost, proxyPort);
- }
-
- /**
- * Obtain a HttpClient object, set up so that it uses per-instance
- * proxying to the given HTTP proxy. Use the cached copy of HTTP
- * client objects/connections if specified.
- *
- * @param url the URL being accessed
- * @param proxyHost the proxy host to use
- * @param proxyPort the proxy port to use
- * @param useCache whether the cached connection should be used
- * if present
- */
- protected void setProxiedClient(URL url, String proxyHost, int proxyPort,
- boolean useCache) throws IOException {
- delegate.setProxiedClient(url, proxyHost, proxyPort, useCache);
- }
-
- /**
- * Implements the HTTP protocol handler's "connect" method,
- * establishing an SSL connection to the server as necessary.
- */
- public void connect() throws IOException {
- delegate.connect();
- }
-
- /**
- * Used by subclass to access "connected" variable. Since we are
- * delegating the actual implementation to "delegate", we need to
- * delegate the access of "connected" as well.
- */
- protected boolean isConnected() {
- return delegate.isConnected();
- }
-
- /**
- * Used by subclass to access "connected" variable. Since we are
- * delegating the actual implementation to "delegate", we need to
- * delegate the access of "connected" as well.
- */
- protected void setConnected(boolean conn) {
- delegate.setConnected(conn);
- }
-
- /**
- * Returns the cipher suite in use on this connection.
- */
- public String getCipherSuite() {
- return delegate.getCipherSuite();
- }
-
- /**
- * Returns the certificate chain the client sent to the
- * server, or null if the client did not authenticate.
- */
- public java.security.cert.Certificate []
- getLocalCertificates() {
- return delegate.getLocalCertificates();
- }
-
- /**
- * Returns the server's certificate chain, or throws
- * SSLPeerUnverified Exception if
- * the server did not authenticate.
- */
- public java.security.cert.Certificate []
- getServerCertificates() throws SSLPeerUnverifiedException {
- return delegate.getServerCertificates();
- }
-
- /**
- * Returns the server's X.509 certificate chain, or null if
- * the server did not authenticate.
- *
- * NOTE: This method is not necessary for the version of this class
- * implementing javax.net.ssl.HttpsURLConnection, but provided for
- * compatibility with the com.sun.net.ssl.HttpsURLConnection version.
- */
- public javax.security.cert.X509Certificate[] getServerCertificateChain() {
- try {
- return delegate.getServerCertificateChain();
- } catch (SSLPeerUnverifiedException e) {
- // this method does not throw an exception as declared in
- // com.sun.net.ssl.HttpsURLConnection.
- // Return null for compatibility.
- return null;
- }
- }
-
- /**
- * Returns the principal with which the server authenticated itself,
- * or throw a SSLPeerUnverifiedException if the server did not authenticate.
- */
- public Principal getPeerPrincipal()
- throws SSLPeerUnverifiedException
- {
- return delegate.getPeerPrincipal();
- }
-
- /**
- * Returns the principal the client sent to the
- * server, or null if the client did not authenticate.
- */
- public Principal getLocalPrincipal()
- {
- return delegate.getLocalPrincipal();
- }
-
- /*
- * Allowable input/output sequences:
- * [interpreted as POST/PUT]
- * - get output, [write output,] get input, [read input]
- * - get output, [write output]
- * [interpreted as GET]
- * - get input, [read input]
- * Disallowed:
- * - get input, [read input,] get output, [write output]
- */
-
- public synchronized OutputStream getOutputStream() throws IOException {
- return delegate.getOutputStream();
- }
-
- public synchronized InputStream getInputStream() throws IOException {
- return delegate.getInputStream();
- }
-
- public InputStream getErrorStream() {
- return delegate.getErrorStream();
- }
-
- /**
- * Disconnect from the server.
- */
- public void disconnect() {
- delegate.disconnect();
- }
-
- public boolean usingProxy() {
- return delegate.usingProxy();
- }
-
- /**
- * Returns an unmodifiable Map of the header fields.
- * The Map keys are Strings that represent the
- * response-header field names. Each Map value is an
- * unmodifiable List of Strings that represents
- * the corresponding field values.
- *
- * @return a Map of header fields
- * @since 1.4
- */
- public Map<String,List<String>> getHeaderFields() {
- return delegate.getHeaderFields();
- }
-
- /**
- * Gets a header field by name. Returns null if not known.
- * @param name the name of the header field
- */
- public String getHeaderField(String name) {
- return delegate.getHeaderField(name);
- }
-
- /**
- * Gets a header field by index. Returns null if not known.
- * @param n the index of the header field
- */
- public String getHeaderField(int n) {
- return delegate.getHeaderField(n);
- }
-
- /**
- * Gets a header field by index. Returns null if not known.
- * @param n the index of the header field
- */
- public String getHeaderFieldKey(int n) {
- return delegate.getHeaderFieldKey(n);
- }
-
- /**
- * Sets request property. If a property with the key already
- * exists, overwrite its value with the new value.
- * @param value the value to be set
- */
- public void setRequestProperty(String key, String value) {
- delegate.setRequestProperty(key, value);
- }
-
- /**
- * Adds a general request property specified by a
- * key-value pair. This method will not overwrite
- * existing values associated with the same key.
- *
- * @param key the keyword by which the request is known
- * (e.g., "<code>accept</code>").
- * @param value the value associated with it.
- * @see #getRequestProperties(java.lang.String)
- * @since 1.4
- */
- public void addRequestProperty(String key, String value) {
- delegate.addRequestProperty(key, value);
- }
-
- /**
- * Overwrite super class method
- */
- public int getResponseCode() throws IOException {
- return delegate.getResponseCode();
- }
-
- public String getRequestProperty(String key) {
- return delegate.getRequestProperty(key);
- }
-
- /**
- * Returns an unmodifiable Map of general request
- * properties for this connection. The Map keys
- * are Strings that represent the request-header
- * field names. Each Map value is a unmodifiable List
- * of Strings that represents the corresponding
- * field values.
- *
- * @return a Map of the general request properties for this connection.
- * @throws IllegalStateException if already connected
- * @since 1.4
- */
- public Map<String,List<String>> getRequestProperties() {
- return delegate.getRequestProperties();
- }
-
- /*
- * We support JDK 1.2.x so we can't count on these from JDK 1.3.
- * We override and supply our own version.
- */
- public void setInstanceFollowRedirects(boolean shouldFollow) {
- delegate.setInstanceFollowRedirects(shouldFollow);
- }
-
- public boolean getInstanceFollowRedirects() {
- return delegate.getInstanceFollowRedirects();
- }
-
- public void setRequestMethod(String method) throws ProtocolException {
- delegate.setRequestMethod(method);
- }
-
- public String getRequestMethod() {
- return delegate.getRequestMethod();
- }
-
- public String getResponseMessage() throws IOException {
- return delegate.getResponseMessage();
- }
-
- public long getHeaderFieldDate(String name, long Default) {
- return delegate.getHeaderFieldDate(name, Default);
- }
-
- public Permission getPermission() throws IOException {
- return delegate.getPermission();
- }
-
- public URL getURL() {
- return delegate.getURL();
- }
-
- public int getContentLength() {
- return delegate.getContentLength();
- }
-
- public long getContentLengthLong() {
- return delegate.getContentLengthLong();
- }
-
- public String getContentType() {
- return delegate.getContentType();
- }
-
- public String getContentEncoding() {
- return delegate.getContentEncoding();
- }
-
- public long getExpiration() {
- return delegate.getExpiration();
- }
-
- public long getDate() {
- return delegate.getDate();
- }
-
- public long getLastModified() {
- return delegate.getLastModified();
- }
-
- public int getHeaderFieldInt(String name, int Default) {
- return delegate.getHeaderFieldInt(name, Default);
- }
-
- public long getHeaderFieldLong(String name, long Default) {
- return delegate.getHeaderFieldLong(name, Default);
- }
-
- public Object getContent() throws IOException {
- return delegate.getContent();
- }
-
- public Object getContent(Class[] classes) throws IOException {
- return delegate.getContent(classes);
- }
-
- public String toString() {
- return delegate.toString();
- }
-
- public void setDoInput(boolean doinput) {
- delegate.setDoInput(doinput);
- }
-
- public boolean getDoInput() {
- return delegate.getDoInput();
- }
-
- public void setDoOutput(boolean dooutput) {
- delegate.setDoOutput(dooutput);
- }
-
- public boolean getDoOutput() {
- return delegate.getDoOutput();
- }
-
- public void setAllowUserInteraction(boolean allowuserinteraction) {
- delegate.setAllowUserInteraction(allowuserinteraction);
- }
-
- public boolean getAllowUserInteraction() {
- return delegate.getAllowUserInteraction();
- }
-
- public void setUseCaches(boolean usecaches) {
- delegate.setUseCaches(usecaches);
- }
-
- public boolean getUseCaches() {
- return delegate.getUseCaches();
- }
-
- public void setIfModifiedSince(long ifmodifiedsince) {
- delegate.setIfModifiedSince(ifmodifiedsince);
- }
-
- public long getIfModifiedSince() {
- return delegate.getIfModifiedSince();
- }
-
- public boolean getDefaultUseCaches() {
- return delegate.getDefaultUseCaches();
- }
-
- public void setDefaultUseCaches(boolean defaultusecaches) {
- delegate.setDefaultUseCaches(defaultusecaches);
- }
-
- /*
- * finalize (dispose) the delegated object. Otherwise
- * sun.net.www.protocol.http.HttpURLConnection's finalize()
- * would have to be made public.
- */
- protected void finalize() throws Throwable {
- delegate.dispose();
- }
-
- public boolean equals(Object obj) {
- return delegate.equals(obj);
- }
-
- public int hashCode() {
- return delegate.hashCode();
- }
-
- public void setConnectTimeout(int timeout) {
- delegate.setConnectTimeout(timeout);
- }
-
- public int getConnectTimeout() {
- return delegate.getConnectTimeout();
- }
-
- public void setReadTimeout(int timeout) {
- delegate.setReadTimeout(timeout);
- }
-
- public int getReadTimeout() {
- return delegate.getReadTimeout();
- }
-
- public void setFixedLengthStreamingMode (int contentLength) {
- delegate.setFixedLengthStreamingMode(contentLength);
- }
-
- public void setFixedLengthStreamingMode(long contentLength) {
- delegate.setFixedLengthStreamingMode(contentLength);
- }
-
- public void setChunkedStreamingMode (int chunklen) {
- delegate.setChunkedStreamingMode(chunklen);
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/mailto/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/mailto/Handler.java
deleted file mode 100755
index 10fe684..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/mailto/Handler.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 1995, 2000, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*-
- * mailto stream opener
- */
-
-package sun.net.www.protocol.mailto;
-
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLStreamHandler;
-import java.io.*;
-import sun.net.www.*;
-//import sun.net.www.protocol.news.ArticlePoster;
-import sun.net.smtp.SmtpClient;
-
-/** open an nntp input stream given a URL */
-public class Handler extends URLStreamHandler {
-
-/*
-// private String decodePercent(String s) {
-// if (s==null || s.indexOf('%') < 0)
-// return s;
-// int limit = s.length();
-// char d[] = new char[limit];
-// int dp = 0;
-// for (int sp = 0; sp < limit; sp++) {
-// int c = s.charAt(sp);
-// if (c == '%' && sp + 2 < limit) {
-// int s1 = s.charAt(sp + 1);
-// int s2 = s.charAt(sp + 2);
-// if ('0' <= s1 && s1 <= '9')
-// s1 = s1 - '0';
-// else if ('a' <= s1 && s1 <= 'f')
-// s1 = s1 - 'a' + 10;
-// else if ('A' <= s1 && s1 <= 'F')
-// s1 = s1 - 'A' + 10;
-// else
-// s1 = -1;
-// if ('0' <= s2 && s2 <= '9')
-// s2 = s2 - '0';
-// else if ('a' <= s2 && s2 <= 'f')
-// s2 = s2 - 'a' + 10;
-// else if ('A' <= s2 && s2 <= 'F')
-// s2 = s2 - 'A' + 10;
-// else
-// s2 = -1;
-// if (s1 >= 0 && s2 >= 0) {
-// c = (s1 << 4) | s2;
-// sp += 2;
-// }
-// }
-// d[dp++] = (char) c;
-// }
-// return new String(d, 0, dp);
-// }
-
-// public InputStream openStream(URL u) {
-// String dest = u.file;
-// String subj = "";
-// int lastsl = dest.lastIndexOf('/');
-// if (lastsl >= 0) {
-// int st = dest.charAt(0) == '/' ? 1 : 0;
-// if (lastsl > st)
-// subj = dest.substring(st, lastsl);
-// dest = dest.substring(lastsl + 1);
-// }
-// if (u.postData != null) {
-// ArticlePoster.MailTo("Posted form",
-// decodePercent(dest),
-// u.postData);
-// }
-// else
-// ArticlePoster.MailTo(decodePercent(subj), decodePercent(dest));
-// return null;
-// }
- */
-
- public synchronized URLConnection openConnection(URL u) {
- return new MailToURLConnection(u);
- }
-
- /**
- * This method is called to parse the string spec into URL u for a
- * mailto protocol.
- *
- * @param u the URL to receive the result of parsing the spec
- * @param spec the URL string to parse
- * @param start the character position to start parsing at. This is
- * just past the ':'.
- * @param limit the character position to stop parsing at.
- */
- public void parseURL(URL u, String spec, int start, int limit) {
-
- String protocol = u.getProtocol();
- String host = "";
- int port = u.getPort();
- String file = "";
-
- if (start < limit) {
- file = spec.substring(start, limit);
- }
- /*
- * Let's just make sure we DO have an Email address in the URL.
- */
- boolean nogood = false;
- if (file == null || file.equals(""))
- nogood = true;
- else {
- boolean allwhites = true;
- for (int i = 0; i < file.length(); i++)
- if (!Character.isWhitespace(file.charAt(i)))
- allwhites = false;
- if (allwhites)
- nogood = true;
- }
- if (nogood)
- throw new RuntimeException("No email address");
- setURL(u, protocol, host, port, file, null);
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/mailto/MailToURLConnection.java b/ojluni/src/main/java/sun/net/www/protocol/mailto/MailToURLConnection.java
deleted file mode 100755
index df4d330..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/mailto/MailToURLConnection.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.net.www.protocol.mailto;
-
-import java.net.URL;
-import java.net.InetAddress;
-import java.net.SocketPermission;
-import java.io.*;
-import java.security.Permission;
-import sun.net.www.*;
-import sun.net.smtp.SmtpClient;
-import sun.net.www.ParseUtil;
-
-
-/**
- * Handle mailto URLs. To send mail using a mailto URLConnection,
- * call <code>getOutputStream</code>, write the message to the output
- * stream, and close it.
- *
- */
-public class MailToURLConnection extends URLConnection {
- InputStream is = null;
- OutputStream os = null;
-
- SmtpClient client;
- Permission permission;
- private int connectTimeout = -1;
- private int readTimeout = -1;
-
- MailToURLConnection(URL u) {
- super(u);
-
- MessageHeader props = new MessageHeader();
- props.add("content-type", "text/html");
- setProperties(props);
- }
-
- /**
- * Get the user's full email address - stolen from
- * HotJavaApplet.getMailAddress().
- */
- String getFromAddress() {
- String str = System.getProperty("user.fromaddr");
- if (str == null) {
- str = System.getProperty("user.name");
- if (str != null) {
- String host = System.getProperty("mail.host");
- if (host == null) {
- try {
- host = InetAddress.getLocalHost().getHostName();
- } catch (java.net.UnknownHostException e) {
- }
- }
- str += "@" + host;
- } else {
- str = "";
- }
- }
- return str;
- }
-
- public void connect() throws IOException {
- client = new SmtpClient(connectTimeout);
- client.setReadTimeout(readTimeout);
- }
-
- @Override
- public synchronized OutputStream getOutputStream() throws IOException {
- if (os != null) {
- return os;
- } else if (is != null) {
- throw new IOException("Cannot write output after reading input.");
- }
- connect();
-
- String to = ParseUtil.decode(url.getPath());
- client.from(getFromAddress());
- client.to(to);
-
- os = client.startMessage();
- return os;
- }
-
- @Override
- public Permission getPermission() throws IOException {
- if (permission == null) {
- connect();
- String host = client.getMailHost() + ":" + 25;
- permission = new SocketPermission(host, "connect");
- }
- return permission;
- }
-
- @Override
- public void setConnectTimeout(int timeout) {
- if (timeout < 0)
- throw new IllegalArgumentException("timeouts can't be negative");
- connectTimeout = timeout;
- }
-
- @Override
- public int getConnectTimeout() {
- return (connectTimeout < 0 ? 0 : connectTimeout);
- }
-
- @Override
- public void setReadTimeout(int timeout) {
- if (timeout < 0)
- throw new IllegalArgumentException("timeouts can't be negative");
- readTimeout = timeout;
- }
-
- @Override
- public int getReadTimeout() {
- return readTimeout < 0 ? 0 : readTimeout;
- }
-}
diff --git a/ojluni/src/main/java/sun/net/www/protocol/netdoc/Handler.java b/ojluni/src/main/java/sun/net/www/protocol/netdoc/Handler.java
deleted file mode 100755
index fbcddcb..0000000
--- a/ojluni/src/main/java/sun/net/www/protocol/netdoc/Handler.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*-
- * netdoc urls point either into the local filesystem or externally
- * through an http url, with network documents being preferred. Useful for
- * FAQs & other documents which are likely to be changing over time at the
- * central site, and where the user will want the most recent edition.
- *
- * @author Steven B. Byrne
- */
-
-package sun.net.www.protocol.netdoc;
-
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.MalformedURLException;
-import java.net.URLStreamHandler;
-import java.io.InputStream;
-import java.io.IOException;
-
-public class Handler extends URLStreamHandler {
- static URL base;
-
- /*
- * Attempt to find a load the given url using the default (network)
- * documentation location. If that fails, use the local copy
- */
- public synchronized URLConnection openConnection(URL u)
- throws IOException
- {
- URLConnection uc = null;
- URL ru;
-
- Boolean tmp = java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction("newdoc.localonly"));
- boolean localonly = tmp.booleanValue();
-
- String docurl = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("doc.url"));
-
- String file = u.getFile();
- if (!localonly) {
- try {
- if (base == null) {
- base = new URL(docurl);
- }
- ru = new URL(base, file);
- } catch (MalformedURLException e) {
- ru = null;
- }
- if (ru != null) {
- uc = ru.openConnection();
- }
- }
-
- if (uc == null) {
- try {
- ru = new URL("file", "~", file);
-
- uc = ru.openConnection();
- InputStream is = uc.getInputStream(); // Check for success.
- } catch (MalformedURLException e) {
- uc = null;
- } catch (IOException e) {
- uc = null;
- }
- }
-
- if (uc == null) {
- throw new IOException("Can't find file for URL: "
- +u.toExternalForm());
- }
- return uc;
- }
-}
diff --git a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
index 50732eb..d1b398fa 100755
--- a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
@@ -763,6 +763,26 @@
// set or refresh local address
localAddress = Net.localAddress(fd);
+
+ // flush any packets already received.
+ boolean blocking = false;
+ synchronized (blockingLock()) {
+ try {
+ blocking = isBlocking();
+ // remainder of each packet thrown away
+ ByteBuffer tmpBuf = ByteBuffer.allocate(1);
+ if (blocking) {
+ configureBlocking(false);
+ }
+ do {
+ tmpBuf.clear();
+ } while (read(tmpBuf) > 0);
+ } finally {
+ if (blocking) {
+ configureBlocking(true);
+ }
+ }
+ }
}
}
}
diff --git a/ojluni/src/main/java/sun/nio/ch/DevPollArrayWrapper.java b/ojluni/src/main/java/sun/nio/ch/DevPollArrayWrapper.java
deleted file mode 100755
index 3151b22..0000000
--- a/ojluni/src/main/java/sun/nio/ch/DevPollArrayWrapper.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.nio.ch;
-
-import java.io.IOException;
-import java.util.BitSet;
-import java.util.Map;
-import java.util.HashMap;
-
-
-/**
- * Manipulates a native array of pollfd structs on Solaris:
- *
- * typedef struct pollfd {
- * int fd;
- * short events;
- * short revents;
- * } pollfd_t;
- *
- * @author Mike McCloskey
- * @since 1.4
- */
-
-class DevPollArrayWrapper {
-
- // Event masks
- static final short POLLIN = 0x0001;
- static final short POLLPRI = 0x0002;
- static final short POLLOUT = 0x0004;
- static final short POLLRDNORM = 0x0040;
- static final short POLLWRNORM = POLLOUT;
- static final short POLLRDBAND = 0x0080;
- static final short POLLWRBAND = 0x0100;
- static final short POLLNORM = POLLRDNORM;
- static final short POLLERR = 0x0008;
- static final short POLLHUP = 0x0010;
- static final short POLLNVAL = 0x0020;
- static final short POLLREMOVE = 0x0800;
- static final short POLLCONN = POLLOUT;
-
- // Miscellaneous constants
- static final short SIZE_POLLFD = 8;
- static final short FD_OFFSET = 0;
- static final short EVENT_OFFSET = 4;
- static final short REVENT_OFFSET = 6;
-
- // Special value to indicate that an update should be ignored
- static final byte IGNORE = (byte)-1;
-
- // Maximum number of open file descriptors
- static final int OPEN_MAX = IOUtil.fdLimit();
-
- // Number of pollfd structures to create.
- // dpwrite/ioctl(DP_POLL) allows up to OPEN_MAX-1
- static final int NUM_POLLFDS = Math.min(OPEN_MAX-1, 8192);
-
- // Initial size of arrays for fd registration changes
- private final int INITIAL_PENDING_UPDATE_SIZE = 64;
-
- // maximum size of updatesLow
- private final int MAX_UPDATE_ARRAY_SIZE = Math.min(OPEN_MAX, 64*1024);
-
- // The pollfd array for results from devpoll driver
- private final AllocatedNativeObject pollArray;
-
- // Base address of the native pollArray
- private final long pollArrayAddress;
-
- // The fd of the devpoll driver
- private int wfd;
-
- // The fd of the interrupt line going out
- private int outgoingInterruptFD;
-
- // The fd of the interrupt line coming in
- private int incomingInterruptFD;
-
- // The index of the interrupt FD
- private int interruptedIndex;
-
- // Number of updated pollfd entries
- int updated;
-
- // object to synchronize fd registration changes
- private final Object updateLock = new Object();
-
- // number of file descriptors with registration changes pending
- private int updateCount;
-
- // file descriptors with registration changes pending
- private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
-
- // events for file descriptors with registration changes pending, indexed
- // by file descriptor and stored as bytes for efficiency reasons. For
- // file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
- // least then the update is stored in a map.
- private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
- private Map<Integer,Byte> eventsHigh;
-
- // Used by release and updateRegistrations to track whether a file
- // descriptor is registered with /dev/poll.
- private final BitSet registered = new BitSet();
-
- DevPollArrayWrapper() {
- int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
- pollArray = new AllocatedNativeObject(allocationSize, true);
- pollArrayAddress = pollArray.address();
- wfd = init();
- if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
- eventsHigh = new HashMap<>();
- }
-
- void initInterrupt(int fd0, int fd1) {
- outgoingInterruptFD = fd1;
- incomingInterruptFD = fd0;
- register(wfd, fd0, POLLIN);
- }
-
- void putReventOps(int i, int revent) {
- int offset = SIZE_POLLFD * i + REVENT_OFFSET;
- pollArray.putShort(offset, (short)revent);
- }
-
- int getEventOps(int i) {
- int offset = SIZE_POLLFD * i + EVENT_OFFSET;
- return pollArray.getShort(offset);
- }
-
- int getReventOps(int i) {
- int offset = SIZE_POLLFD * i + REVENT_OFFSET;
- return pollArray.getShort(offset);
- }
-
- int getDescriptor(int i) {
- int offset = SIZE_POLLFD * i + FD_OFFSET;
- return pollArray.getInt(offset);
- }
-
- private void setUpdateEvents(int fd, byte events) {
- if (fd < MAX_UPDATE_ARRAY_SIZE) {
- eventsLow[fd] = events;
- } else {
- eventsHigh.put(Integer.valueOf(fd), Byte.valueOf(events));
- }
- }
-
- private byte getUpdateEvents(int fd) {
- if (fd < MAX_UPDATE_ARRAY_SIZE) {
- return eventsLow[fd];
- } else {
- Byte result = eventsHigh.get(Integer.valueOf(fd));
- // result should never be null
- return result.byteValue();
- }
- }
-
- void setInterest(int fd, int mask) {
- synchronized (updateLock) {
- // record the file descriptor and events, expanding the
- // respective arrays first if necessary.
- int oldCapacity = updateDescriptors.length;
- if (updateCount == oldCapacity) {
- int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
- int[] newDescriptors = new int[newCapacity];
- System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
- updateDescriptors = newDescriptors;
- }
- updateDescriptors[updateCount++] = fd;
-
- // events are stored as bytes for efficiency reasons
- byte b = (byte)mask;
- assert (b == mask) && (b != IGNORE);
- setUpdateEvents(fd, b);
- }
- }
-
- void release(int fd) {
- synchronized (updateLock) {
- // ignore any pending update for this file descriptor
- setUpdateEvents(fd, IGNORE);
-
- // remove from /dev/poll
- if (registered.get(fd)) {
- register(wfd, fd, POLLREMOVE);
- registered.clear(fd);
- }
- }
- }
-
- void closeDevPollFD() throws IOException {
- FileDispatcherImpl.closeIntFD(wfd);
- pollArray.free();
- }
-
- int poll(long timeout) throws IOException {
- updateRegistrations();
- updated = poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
- for (int i=0; i<updated; i++) {
- if (getDescriptor(i) == incomingInterruptFD) {
- interruptedIndex = i;
- interrupted = true;
- break;
- }
- }
- return updated;
- }
-
- void updateRegistrations() throws IOException {
- synchronized (updateLock) {
- // Populate pollfd array with updated masks
- int j = 0;
- int index = 0;
- while (j < updateCount) {
- int fd = updateDescriptors[j];
- short events = getUpdateEvents(fd);
- boolean wasRegistered = registered.get(fd);
-
- // events = 0 => POLLREMOVE or do-nothing
- if (events != IGNORE) {
- if (events == 0) {
- if (wasRegistered) {
- events = POLLREMOVE;
- registered.clear(fd);
- } else {
- events = IGNORE;
- }
- } else {
- if (!wasRegistered) {
- registered.set(fd);
- }
- }
- }
-
- // populate pollfd array with updated event
- if (events != IGNORE) {
- // insert POLLREMOVE if changing events
- if (wasRegistered && events != POLLREMOVE) {
- putPollFD(pollArray, index, fd, POLLREMOVE);
- index++;
- }
- putPollFD(pollArray, index, fd, events);
- index++;
- if (index >= (NUM_POLLFDS-1)) {
- registerMultiple(wfd, pollArray.address(), index);
- index = 0;
- }
-
- // events for this fd now up to date
- setUpdateEvents(fd, IGNORE);
- }
- j++;
- }
-
- // write any remaining updates
- if (index > 0)
- registerMultiple(wfd, pollArray.address(), index);
-
- updateCount = 0;
- }
- }
-
- private void putPollFD(AllocatedNativeObject array, int index, int fd,
- short event)
- {
- int structIndex = SIZE_POLLFD * index;
- array.putInt(structIndex + FD_OFFSET, fd);
- array.putShort(structIndex + EVENT_OFFSET, event);
- array.putShort(structIndex + REVENT_OFFSET, (short)0);
- }
-
- boolean interrupted = false;
-
- public void interrupt() {
- interrupt(outgoingInterruptFD);
- }
-
- public int interruptedIndex() {
- return interruptedIndex;
- }
-
- boolean interrupted() {
- return interrupted;
- }
-
- void clearInterrupted() {
- interrupted = false;
- }
-
- private native int init();
- private native void register(int wfd, int fd, int mask);
- private native void registerMultiple(int wfd, long address, int len)
- throws IOException;
- private native int poll0(long pollAddress, int numfds, long timeout,
- int wfd);
- private static native void interrupt(int fd);
-}
diff --git a/ojluni/src/main/java/sun/nio/ch/DevPollSelectorImpl.java b/ojluni/src/main/java/sun/nio/ch/DevPollSelectorImpl.java
deleted file mode 100755
index 047d6f9..0000000
--- a/ojluni/src/main/java/sun/nio/ch/DevPollSelectorImpl.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.nio.ch;
-
-import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
-import java.util.*;
-import sun.misc.*;
-
-
-/**
- * An implementation of Selector for Solaris.
- */
-class DevPollSelectorImpl
- extends SelectorImpl
-{
-
- // File descriptors used for interrupt
- protected int fd0;
- protected int fd1;
-
- // The poll object
- DevPollArrayWrapper pollWrapper;
-
- // Maps from file descriptors to keys
- private Map<Integer,SelectionKeyImpl> fdToKey;
-
- // True if this Selector has been closed
- private boolean closed = false;
-
- // Lock for close/cleanup
- private Object closeLock = new Object();
-
- // Lock for interrupt triggering and clearing
- private Object interruptLock = new Object();
- private boolean interruptTriggered = false;
-
- /**
- * Package private constructor called by factory method in
- * the abstract superclass Selector.
- */
- DevPollSelectorImpl(SelectorProvider sp) {
- super(sp);
- long pipeFds = IOUtil.makePipe(false);
- fd0 = (int) (pipeFds >>> 32);
- fd1 = (int) pipeFds;
- pollWrapper = new DevPollArrayWrapper();
- pollWrapper.initInterrupt(fd0, fd1);
- fdToKey = new HashMap<Integer,SelectionKeyImpl>();
- }
-
- protected int doSelect(long timeout)
- throws IOException
- {
- if (closed)
- throw new ClosedSelectorException();
- processDeregisterQueue();
- try {
- begin();
- pollWrapper.poll(timeout);
- } finally {
- end();
- }
- processDeregisterQueue();
- int numKeysUpdated = updateSelectedKeys();
- if (pollWrapper.interrupted()) {
- // Clear the wakeup pipe
- pollWrapper.putReventOps(pollWrapper.interruptedIndex(), 0);
- synchronized (interruptLock) {
- pollWrapper.clearInterrupted();
- IOUtil.drain(fd0);
- interruptTriggered = false;
- }
- }
- return numKeysUpdated;
- }
-
- /**
- * Update the keys whose fd's have been selected by the devpoll
- * driver. Add the ready keys to the ready queue.
- */
- private int updateSelectedKeys() {
- int entries = pollWrapper.updated;
- int numKeysUpdated = 0;
- for (int i=0; i<entries; i++) {
- int nextFD = pollWrapper.getDescriptor(i);
- SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
- // ski is null in the case of an interrupt
- if (ski != null) {
- int rOps = pollWrapper.getReventOps(i);
- if (selectedKeys.contains(ski)) {
- if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
- numKeysUpdated++;
- }
- } else {
- ski.channel.translateAndSetReadyOps(rOps, ski);
- if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
- selectedKeys.add(ski);
- numKeysUpdated++;
- }
- }
- }
- }
- return numKeysUpdated;
- }
-
- protected void implClose() throws IOException {
- if (closed)
- return;
- closed = true;
-
- // prevent further wakeup
- synchronized (interruptLock) {
- interruptTriggered = true;
- }
-
- FileDispatcherImpl.closeIntFD(fd0);
- FileDispatcherImpl.closeIntFD(fd1);
-
- pollWrapper.release(fd0);
- pollWrapper.closeDevPollFD();
- selectedKeys = null;
-
- // Deregister channels
- Iterator<SelectionKey> i = keys.iterator();
- while (i.hasNext()) {
- SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
- deregister(ski);
- SelectableChannel selch = ski.channel();
- if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
- i.remove();
- }
- fd0 = -1;
- fd1 = -1;
- }
-
- protected void implRegister(SelectionKeyImpl ski) {
- int fd = IOUtil.fdVal(ski.channel.getFD());
- fdToKey.put(Integer.valueOf(fd), ski);
- keys.add(ski);
- }
-
- protected void implDereg(SelectionKeyImpl ski) throws IOException {
- int i = ski.getIndex();
- assert (i >= 0);
- int fd = ski.channel.getFDVal();
- fdToKey.remove(Integer.valueOf(fd));
- pollWrapper.release(fd);
- ski.setIndex(-1);
- keys.remove(ski);
- selectedKeys.remove(ski);
- deregister((AbstractSelectionKey)ski);
- SelectableChannel selch = ski.channel();
- if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
- }
-
- void putEventOps(SelectionKeyImpl sk, int ops) {
- if (closed)
- throw new ClosedSelectorException();
- int fd = IOUtil.fdVal(sk.channel.getFD());
- pollWrapper.setInterest(fd, ops);
- }
-
- public Selector wakeup() {
- synchronized (interruptLock) {
- if (!interruptTriggered) {
- pollWrapper.interrupt();
- interruptTriggered = true;
- }
- }
- return this;
- }
-}
diff --git a/ojluni/src/main/java/sun/nio/ch/DevPollSelectorProvider.java b/ojluni/src/main/java/sun/nio/ch/DevPollSelectorProvider.java
deleted file mode 100755
index dbd6170..0000000
--- a/ojluni/src/main/java/sun/nio/ch/DevPollSelectorProvider.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.nio.ch;
-
-import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
-
-public class DevPollSelectorProvider
- extends SelectorProviderImpl
-{
- public AbstractSelector openSelector() throws IOException {
- return new DevPollSelectorImpl(this);
- }
-
- public Channel inheritedChannel() throws IOException {
- return InheritedChannel.getChannel();
- }
-}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/CollectionCertStore.java b/ojluni/src/main/java/sun/security/provider/certpath/CollectionCertStore.java
deleted file mode 100644
index f991434..0000000
--- a/ojluni/src/main/java/sun/security/provider/certpath/CollectionCertStore.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider.certpath;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.cert.Certificate;
-import java.security.cert.CRL;
-import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.HashSet;
-import java.security.cert.CertSelector;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
-import java.security.cert.CertStoreParameters;
-import java.security.cert.CollectionCertStoreParameters;
-import java.security.cert.CRLSelector;
-import java.security.cert.CertStoreSpi;
-
-/**
- * A <code>CertStore</code> that retrieves <code>Certificates</code> and
- * <code>CRL</code>s from a <code>Collection</code>.
- * <p>
- * Before calling the {@link #engineGetCertificates engineGetCertificates} or
- * {@link #engineGetCRLs engineGetCRLs} methods, the
- * {@link #CollectionCertStore(CertStoreParameters)
- * CollectionCertStore(CertStoreParameters)} constructor is called to
- * create the <code>CertStore</code> and establish the
- * <code>Collection</code> from which <code>Certificate</code>s and
- * <code>CRL</code>s will be retrieved. If the specified
- * <code>Collection</code> contains an object that is not a
- * <code>Certificate</code> or <code>CRL</code>, that object will be
- * ignored.
- * <p>
- * <b>Concurrent Access</b>
- * <p>
- * As described in the javadoc for <code>CertStoreSpi</code>, the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
- * must be thread-safe. That is, multiple threads may concurrently
- * invoke these methods on a single <code>CollectionCertStore</code>
- * object (or more than one) with no ill effects.
- * <p>
- * This is achieved by requiring that the <code>Collection</code> passed to
- * the {@link #CollectionCertStore(CertStoreParameters)
- * CollectionCertStore(CertStoreParameters)} constructor (via the
- * <code>CollectionCertStoreParameters</code> object) must have fail-fast
- * iterators. Simultaneous modifications to the <code>Collection</code> can thus be
- * detected and certificate or CRL retrieval can be retried. The fact that
- * <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
- * essential.
- *
- * @see java.security.cert.CertStore
- *
- * @since 1.4
- * @author Steve Hanna
- */
-public class CollectionCertStore extends CertStoreSpi {
-
- private Collection<?> coll;
-
- /**
- * Creates a <code>CertStore</code> with the specified parameters.
- * For this class, the parameters object must be an instance of
- * <code>CollectionCertStoreParameters</code>. The <code>Collection</code>
- * included in the <code>CollectionCertStoreParameters</code> object
- * must be thread-safe.
- *
- * @param params the algorithm parameters
- * @exception InvalidAlgorithmParameterException if params is not an
- * instance of <code>CollectionCertStoreParameters</code>
- */
- public CollectionCertStore(CertStoreParameters params)
- throws InvalidAlgorithmParameterException
- {
- super(params);
- if (!(params instanceof CollectionCertStoreParameters))
- throw new InvalidAlgorithmParameterException(
- "parameters must be CollectionCertStoreParameters");
- coll = ((CollectionCertStoreParameters) params).getCollection();
- }
-
- /**
- * Returns a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector. If no <code>Certificate</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- *
- * @param selector a <code>CertSelector</code> used to select which
- * <code>Certificate</code>s should be returned. Specify <code>null</code>
- * to return all <code>Certificate</code>s.
- * @return a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- @Override
- public Collection<Certificate> engineGetCertificates
- (CertSelector selector) throws CertStoreException {
- if (coll == null) {
- throw new CertStoreException("Collection is null");
- }
- // Tolerate a few ConcurrentModificationExceptions
- for (int c = 0; c < 10; c++) {
- try {
- HashSet<Certificate> result = new HashSet<>();
- if (selector != null) {
- for (Object o : coll) {
- if ((o instanceof Certificate) &&
- selector.match((Certificate) o))
- result.add((Certificate)o);
- }
- } else {
- for (Object o : coll) {
- if (o instanceof Certificate)
- result.add((Certificate)o);
- }
- }
- return(result);
- } catch (ConcurrentModificationException e) { }
- }
- throw new ConcurrentModificationException("Too many "
- + "ConcurrentModificationExceptions");
- }
-
- /**
- * Returns a <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector. If no <code>CRL</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- *
- * @param selector a <code>CRLSelector</code> used to select which
- * <code>CRL</code>s should be returned. Specify <code>null</code>
- * to return all <code>CRL</code>s.
- * @return a <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- @Override
- public Collection<CRL> engineGetCRLs(CRLSelector selector)
- throws CertStoreException
- {
- if (coll == null)
- throw new CertStoreException("Collection is null");
-
- // Tolerate a few ConcurrentModificationExceptions
- for (int c = 0; c < 10; c++) {
- try {
- HashSet<CRL> result = new HashSet<>();
- if (selector != null) {
- for (Object o : coll) {
- if ((o instanceof CRL) && selector.match((CRL) o))
- result.add((CRL)o);
- }
- } else {
- for (Object o : coll) {
- if (o instanceof CRL)
- result.add((CRL)o);
- }
- }
- return result;
- } catch (ConcurrentModificationException e) { }
- }
- throw new ConcurrentModificationException("Too many "
- + "ConcurrentModificationExceptions");
- }
-}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/IndexedCollectionCertStore.java b/ojluni/src/main/java/sun/security/provider/certpath/IndexedCollectionCertStore.java
deleted file mode 100644
index 64fcc56..0000000
--- a/ojluni/src/main/java/sun/security/provider/certpath/IndexedCollectionCertStore.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider.certpath;
-
-import java.util.*;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.cert.*;
-
-import javax.security.auth.x500.X500Principal;
-
-/**
- * A <code>CertStore</code> that retrieves <code>Certificates</code> and
- * <code>CRL</code>s from a <code>Collection</code>.
- * <p>
- * This implementation is functionally equivalent to CollectionCertStore
- * with two differences:
- * <ol>
- * <li>Upon construction, the elements in the specified Collection are
- * partially indexed. X509Certificates are indexed by subject, X509CRLs
- * by issuer, non-X509 Certificates and CRLs are copied without indexing,
- * other objects are ignored. This increases CertStore construction time
- * but allows significant speedups for searches which specify the indexed
- * attributes, in particular for large Collections (reduction from linear
- * time to effectively constant time). Searches for non-indexed queries
- * are as fast (or marginally faster) than for the standard
- * CollectionCertStore. Certificate subjects and CRL issuers
- * were found to be specified in most searches used internally by the
- * CertPath provider. Additional attributes could indexed if there are
- * queries that justify the effort.
- *
- * <li>Changes to the specified Collection after construction time are
- * not detected and ignored. This is because there is no way to efficiently
- * detect if a Collection has been modified, a full traversal would be
- * required. That would degrade lookup performance to linear time and
- * eliminated the benefit of indexing. We may fix this via the introduction
- * of new public APIs in the future.
- * </ol>
- * <p>
- * Before calling the {@link #engineGetCertificates engineGetCertificates} or
- * {@link #engineGetCRLs engineGetCRLs} methods, the
- * {@link #CollectionCertStore(CertStoreParameters)
- * CollectionCertStore(CertStoreParameters)} constructor is called to
- * create the <code>CertStore</code> and establish the
- * <code>Collection</code> from which <code>Certificate</code>s and
- * <code>CRL</code>s will be retrieved. If the specified
- * <code>Collection</code> contains an object that is not a
- * <code>Certificate</code> or <code>CRL</code>, that object will be
- * ignored.
- * <p>
- * <b>Concurrent Access</b>
- * <p>
- * As described in the javadoc for <code>CertStoreSpi</code>, the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
- * must be thread-safe. That is, multiple threads may concurrently
- * invoke these methods on a single <code>CollectionCertStore</code>
- * object (or more than one) with no ill effects.
- * <p>
- * This is achieved by requiring that the <code>Collection</code> passed to
- * the {@link #CollectionCertStore(CertStoreParameters)
- * CollectionCertStore(CertStoreParameters)} constructor (via the
- * <code>CollectionCertStoreParameters</code> object) must have fail-fast
- * iterators. Simultaneous modifications to the <code>Collection</code> can thus be
- * detected and certificate or CRL retrieval can be retried. The fact that
- * <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also
- * essential.
- *
- * @see java.security.cert.CertStore
- * @see CollectionCertStore
- *
- * @author Andreas Sterbenz
- */
-public class IndexedCollectionCertStore extends CertStoreSpi {
-
- /**
- * Map X500Principal(subject) -> X509Certificate | List of X509Certificate
- */
- private Map<X500Principal, Object> certSubjects;
- /**
- * Map X500Principal(issuer) -> X509CRL | List of X509CRL
- */
- private Map<X500Principal, Object> crlIssuers;
- /**
- * Sets of non-X509 certificates and CRLs
- */
- private Set<Certificate> otherCertificates;
- private Set<CRL> otherCRLs;
-
- /**
- * Creates a <code>CertStore</code> with the specified parameters.
- * For this class, the parameters object must be an instance of
- * <code>CollectionCertStoreParameters</code>.
- *
- * @param params the algorithm parameters
- * @exception InvalidAlgorithmParameterException if params is not an
- * instance of <code>CollectionCertStoreParameters</code>
- */
- public IndexedCollectionCertStore(CertStoreParameters params)
- throws InvalidAlgorithmParameterException {
- super(params);
- if (!(params instanceof CollectionCertStoreParameters)) {
- throw new InvalidAlgorithmParameterException(
- "parameters must be CollectionCertStoreParameters");
- }
- Collection<?> coll = ((CollectionCertStoreParameters)params).getCollection();
- if (coll == null) {
- throw new InvalidAlgorithmParameterException
- ("Collection must not be null");
- }
- buildIndex(coll);
- }
-
- /**
- * Index the specified Collection copying all references to Certificates
- * and CRLs.
- */
- private void buildIndex(Collection<?> coll) {
- certSubjects = new HashMap<X500Principal, Object>();
- crlIssuers = new HashMap<X500Principal, Object>();
- otherCertificates = null;
- otherCRLs = null;
- for (Object obj : coll) {
- if (obj instanceof X509Certificate) {
- indexCertificate((X509Certificate)obj);
- } else if (obj instanceof X509CRL) {
- indexCRL((X509CRL)obj);
- } else if (obj instanceof Certificate) {
- if (otherCertificates == null) {
- otherCertificates = new HashSet<Certificate>();
- }
- otherCertificates.add((Certificate)obj);
- } else if (obj instanceof CRL) {
- if (otherCRLs == null) {
- otherCRLs = new HashSet<CRL>();
- }
- otherCRLs.add((CRL)obj);
- } else {
- // ignore
- }
- }
- if (otherCertificates == null) {
- otherCertificates = Collections.<Certificate>emptySet();
- }
- if (otherCRLs == null) {
- otherCRLs = Collections.<CRL>emptySet();
- }
- }
-
- /**
- * Add an X509Certificate to the index.
- */
- private void indexCertificate(X509Certificate cert) {
- X500Principal subject = cert.getSubjectX500Principal();
- Object oldEntry = certSubjects.put(subject, cert);
- if (oldEntry != null) { // assume this is unlikely
- if (oldEntry instanceof X509Certificate) {
- if (cert.equals(oldEntry)) {
- return;
- }
- List<X509Certificate> list = new ArrayList<>(2);
- list.add(cert);
- list.add((X509Certificate)oldEntry);
- certSubjects.put(subject, list);
- } else {
- @SuppressWarnings("unchecked") // See certSubjects javadoc.
- List<X509Certificate> list = (List<X509Certificate>)oldEntry;
- if (list.contains(cert) == false) {
- list.add(cert);
- }
- certSubjects.put(subject, list);
- }
- }
- }
-
- /**
- * Add an X509CRL to the index.
- */
- private void indexCRL(X509CRL crl) {
- X500Principal issuer = crl.getIssuerX500Principal();
- Object oldEntry = crlIssuers.put(issuer, crl);
- if (oldEntry != null) { // assume this is unlikely
- if (oldEntry instanceof X509CRL) {
- if (crl.equals(oldEntry)) {
- return;
- }
- List<X509CRL> list = new ArrayList<>(2);
- list.add(crl);
- list.add((X509CRL)oldEntry);
- crlIssuers.put(issuer, list);
- } else {
- // See crlIssuers javadoc.
- @SuppressWarnings("unchecked")
- List<X509CRL> list = (List<X509CRL>)oldEntry;
- if (list.contains(crl) == false) {
- list.add(crl);
- }
- crlIssuers.put(issuer, list);
- }
- }
- }
-
- /**
- * Returns a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector. If no <code>Certificate</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- *
- * @param selector a <code>CertSelector</code> used to select which
- * <code>Certificate</code>s should be returned. Specify <code>null</code>
- * to return all <code>Certificate</code>s.
- * @return a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- @Override
- public Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
- throws CertStoreException {
-
- // no selector means match all
- if (selector == null) {
- Set<Certificate> matches = new HashSet<>();
- matchX509Certs(new X509CertSelector(), matches);
- matches.addAll(otherCertificates);
- return matches;
- }
-
- if (selector instanceof X509CertSelector == false) {
- Set<Certificate> matches = new HashSet<>();
- matchX509Certs(selector, matches);
- for (Certificate cert : otherCertificates) {
- if (selector.match(cert)) {
- matches.add(cert);
- }
- }
- return matches;
- }
-
- if (certSubjects.isEmpty()) {
- return Collections.<X509Certificate>emptySet();
- }
- X509CertSelector x509Selector = (X509CertSelector)selector;
- // see if the subject is specified
- X500Principal subject;
- X509Certificate matchCert = x509Selector.getCertificate();
- if (matchCert != null) {
- subject = matchCert.getSubjectX500Principal();
- } else {
- subject = x509Selector.getSubject();
- }
- if (subject != null) {
- // yes, narrow down candidates to indexed possibilities
- Object entry = certSubjects.get(subject);
- if (entry == null) {
- return Collections.<X509Certificate>emptySet();
- }
- if (entry instanceof X509Certificate) {
- X509Certificate x509Entry = (X509Certificate)entry;
- if (x509Selector.match(x509Entry)) {
- return Collections.singleton(x509Entry);
- } else {
- return Collections.<X509Certificate>emptySet();
- }
- } else {
- // See certSubjects javadoc.
- @SuppressWarnings("unchecked")
- List<X509Certificate> list = (List<X509Certificate>)entry;
- Set<X509Certificate> matches = new HashSet<>(16);
- for (X509Certificate cert : list) {
- if (x509Selector.match(cert)) {
- matches.add(cert);
- }
- }
- return matches;
- }
- }
- // cannot use index, iterate all
- Set<Certificate> matches = new HashSet<>(16);
- matchX509Certs(x509Selector, matches);
- return matches;
- }
-
- /**
- * Iterate through all the X509Certificates and add matches to the
- * collection.
- */
- private void matchX509Certs(CertSelector selector,
- Collection<Certificate> matches) {
-
- for (Object obj : certSubjects.values()) {
- if (obj instanceof X509Certificate) {
- X509Certificate cert = (X509Certificate)obj;
- if (selector.match(cert)) {
- matches.add(cert);
- }
- } else {
- // See certSubjects javadoc.
- @SuppressWarnings("unchecked")
- List<X509Certificate> list = (List<X509Certificate>)obj;
- for (X509Certificate cert : list) {
- if (selector.match(cert)) {
- matches.add(cert);
- }
- }
- }
- }
- }
-
- /**
- * Returns a <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector. If no <code>CRL</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- *
- * @param selector a <code>CRLSelector</code> used to select which
- * <code>CRL</code>s should be returned. Specify <code>null</code>
- * to return all <code>CRL</code>s.
- * @return a <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- @Override
- public Collection<CRL> engineGetCRLs(CRLSelector selector)
- throws CertStoreException {
-
- if (selector == null) {
- Set<CRL> matches = new HashSet<>();
- matchX509CRLs(new X509CRLSelector(), matches);
- matches.addAll(otherCRLs);
- return matches;
- }
-
- if (selector instanceof X509CRLSelector == false) {
- Set<CRL> matches = new HashSet<>();
- matchX509CRLs(selector, matches);
- for (CRL crl : otherCRLs) {
- if (selector.match(crl)) {
- matches.add(crl);
- }
- }
- return matches;
- }
-
- if (crlIssuers.isEmpty()) {
- return Collections.<CRL>emptySet();
- }
- X509CRLSelector x509Selector = (X509CRLSelector)selector;
- // see if the issuer is specified
- Collection<X500Principal> issuers = x509Selector.getIssuers();
- if (issuers != null) {
- HashSet<CRL> matches = new HashSet<>(16);
- for (X500Principal issuer : issuers) {
- Object entry = crlIssuers.get(issuer);
- if (entry == null) {
- // empty
- } else if (entry instanceof X509CRL) {
- X509CRL crl = (X509CRL)entry;
- if (x509Selector.match(crl)) {
- matches.add(crl);
- }
- } else { // List
- // See crlIssuers javadoc.
- @SuppressWarnings("unchecked")
- List<X509CRL> list = (List<X509CRL>)entry;
- for (X509CRL crl : list) {
- if (x509Selector.match(crl)) {
- matches.add(crl);
- }
- }
- }
- }
- return matches;
- }
- // cannot use index, iterate all
- Set<CRL> matches = new HashSet<>(16);
- matchX509CRLs(x509Selector, matches);
- return matches;
- }
-
- /**
- * Iterate through all the X509CRLs and add matches to the
- * collection.
- */
- private void matchX509CRLs(CRLSelector selector, Collection<CRL> matches) {
- for (Object obj : crlIssuers.values()) {
- if (obj instanceof X509CRL) {
- X509CRL crl = (X509CRL)obj;
- if (selector.match(crl)) {
- matches.add(crl);
- }
- } else {
- // See crlIssuers javadoc.
- @SuppressWarnings("unchecked")
- List<X509CRL> list = (List<X509CRL>)obj;
- for (X509CRL crl : list) {
- if (selector.match(crl)) {
- matches.add(crl);
- }
- }
- }
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStore.java b/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStore.java
deleted file mode 100644
index 5a24a69..0000000
--- a/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStore.java
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider.certpath.ldap;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.net.URI;
-import java.util.*;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.NameNotFoundException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-import java.security.*;
-import java.security.cert.Certificate;
-import java.security.cert.*;
-import javax.security.auth.x500.X500Principal;
-
-import sun.misc.HexDumpEncoder;
-import sun.security.provider.certpath.X509CertificatePair;
-import sun.security.util.Cache;
-import sun.security.util.Debug;
-import sun.security.x509.X500Name;
-import sun.security.action.GetBooleanAction;
-import sun.security.action.GetPropertyAction;
-
-/**
- * A <code>CertStore</code> that retrieves <code>Certificates</code> and
- * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema
- * (RFC 2587):
- * <a href="http://www.ietf.org/rfc/rfc2587.txt">
- * http://www.ietf.org/rfc/rfc2587.txt</a>.
- * <p>
- * Before calling the {@link #engineGetCertificates engineGetCertificates} or
- * {@link #engineGetCRLs engineGetCRLs} methods, the
- * {@link #LDAPCertStore(CertStoreParameters)
- * LDAPCertStore(CertStoreParameters)} constructor is called to create the
- * <code>CertStore</code> and establish the DNS name and port of the LDAP
- * server from which <code>Certificate</code>s and <code>CRL</code>s will be
- * retrieved.
- * <p>
- * <b>Concurrent Access</b>
- * <p>
- * As described in the javadoc for <code>CertStoreSpi</code>, the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
- * must be thread-safe. That is, multiple threads may concurrently
- * invoke these methods on a single <code>LDAPCertStore</code> object
- * (or more than one) with no ill effects. This allows a
- * <code>CertPathBuilder</code> to search for a CRL while simultaneously
- * searching for further certificates, for instance.
- * <p>
- * This is achieved by adding the <code>synchronized</code> keyword to the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods.
- * <p>
- * This classes uses caching and requests multiple attributes at once to
- * minimize LDAP round trips. The cache is associated with the CertStore
- * instance. It uses soft references to hold the values to minimize impact
- * on footprint and currently has a maximum size of 750 attributes and a
- * 30 second default lifetime.
- * <p>
- * We always request CA certificates, cross certificate pairs, and ARLs in
- * a single LDAP request when any one of them is needed. The reason is that
- * we typically need all of them anyway and requesting them in one go can
- * reduce the number of requests to a third. Even if we don't need them,
- * these attributes are typically small enough not to cause a noticeable
- * overhead. In addition, when the prefetchCRLs flag is true, we also request
- * the full CRLs. It is currently false initially but set to true once any
- * request for an ARL to the server returns an null value. The reason is
- * that CRLs could be rather large but are rarely used. This implementation
- * should improve performance in most cases.
- *
- * @see java.security.cert.CertStore
- *
- * @since 1.4
- * @author Steve Hanna
- * @author Andreas Sterbenz
- */
-public final class LDAPCertStore extends CertStoreSpi {
-
- private static final Debug debug = Debug.getInstance("certpath");
-
- private final static boolean DEBUG = false;
-
- /**
- * LDAP attribute identifiers.
- */
- private static final String USER_CERT = "userCertificate;binary";
- private static final String CA_CERT = "cACertificate;binary";
- private static final String CROSS_CERT = "crossCertificatePair;binary";
- private static final String CRL = "certificateRevocationList;binary";
- private static final String ARL = "authorityRevocationList;binary";
- private static final String DELTA_CRL = "deltaRevocationList;binary";
-
- // Constants for various empty values
- private final static String[] STRING0 = new String[0];
-
- private final static byte[][] BB0 = new byte[0][];
-
- private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes();
-
- // cache related constants
- private final static int DEFAULT_CACHE_SIZE = 750;
- private final static int DEFAULT_CACHE_LIFETIME = 30;
-
- private final static int LIFETIME;
-
- private final static String PROP_LIFETIME =
- "sun.security.certpath.ldap.cache.lifetime";
-
- /*
- * Internal system property, that when set to "true", disables the
- * JNDI application resource files lookup to prevent recursion issues
- * when validating signed JARs with LDAP URLs in certificates.
- */
- private final static String PROP_DISABLE_APP_RESOURCE_FILES =
- "sun.security.certpath.ldap.disable.app.resource.files";
-
- static {
- String s = AccessController.doPrivileged(
- new GetPropertyAction(PROP_LIFETIME));
- if (s != null) {
- LIFETIME = Integer.parseInt(s); // throws NumberFormatException
- } else {
- LIFETIME = DEFAULT_CACHE_LIFETIME;
- }
- }
-
- /**
- * The CertificateFactory used to decode certificates from
- * their binary stored form.
- */
- private CertificateFactory cf;
- /**
- * The JNDI directory context.
- */
- private DirContext ctx;
-
- /**
- * Flag indicating whether we should prefetch CRLs.
- */
- private boolean prefetchCRLs = false;
-
- private final Cache<String, byte[][]> valueCache;
-
- private int cacheHits = 0;
- private int cacheMisses = 0;
- private int requests = 0;
-
- /**
- * Creates a <code>CertStore</code> with the specified parameters.
- * For this class, the parameters object must be an instance of
- * <code>LDAPCertStoreParameters</code>.
- *
- * @param params the algorithm parameters
- * @exception InvalidAlgorithmParameterException if params is not an
- * instance of <code>LDAPCertStoreParameters</code>
- */
- public LDAPCertStore(CertStoreParameters params)
- throws InvalidAlgorithmParameterException {
- super(params);
- if (!(params instanceof LDAPCertStoreParameters))
- throw new InvalidAlgorithmParameterException(
- "parameters must be LDAPCertStoreParameters");
-
- LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params;
-
- // Create InitialDirContext needed to communicate with the server
- createInitialDirContext(lparams.getServerName(), lparams.getPort());
-
- // Create CertificateFactory for use later on
- try {
- cf = CertificateFactory.getInstance("X.509");
- } catch (CertificateException e) {
- throw new InvalidAlgorithmParameterException(
- "unable to create CertificateFactory for X.509");
- }
- if (LIFETIME == 0) {
- valueCache = Cache.newNullCache();
- } else if (LIFETIME < 0) {
- valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE);
- } else {
- valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME);
- }
- }
-
- /**
- * Returns an LDAP CertStore. This method consults a cache of
- * CertStores (shared per JVM) using the LDAP server/port as a key.
- */
- private static final Cache<LDAPCertStoreParameters, CertStore>
- certStoreCache = Cache.newSoftMemoryCache(185);
- static synchronized CertStore getInstance(LDAPCertStoreParameters params)
- throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
- CertStore lcs = certStoreCache.get(params);
- if (lcs == null) {
- lcs = CertStore.getInstance("LDAP", params);
- certStoreCache.put(params, lcs);
- } else {
- if (debug != null) {
- debug.println("LDAPCertStore.getInstance: cache hit");
- }
- }
- return lcs;
- }
-
- /**
- * Create InitialDirContext.
- *
- * @param server Server DNS name hosting LDAP service
- * @param port Port at which server listens for requests
- * @throws InvalidAlgorithmParameterException if creation fails
- */
- private void createInitialDirContext(String server, int port)
- throws InvalidAlgorithmParameterException {
- String url = "ldap://" + server + ":" + port;
- Hashtable<String,Object> env = new Hashtable<>();
- env.put(Context.INITIAL_CONTEXT_FACTORY,
- "com.sun.jndi.ldap.LdapCtxFactory");
- env.put(Context.PROVIDER_URL, url);
-
- // If property is set to true, disable application resource file lookup.
- boolean disableAppResourceFiles = AccessController.doPrivileged(
- new GetBooleanAction(PROP_DISABLE_APP_RESOURCE_FILES));
- if (disableAppResourceFiles) {
- if (debug != null) {
- debug.println("LDAPCertStore disabling app resource files");
- }
- env.put("com.sun.naming.disable.app.resource.files", "true");
- }
-
- try {
- ctx = new InitialDirContext(env);
- /*
- * By default, follow referrals unless application has
- * overridden property in an application resource file.
- */
- Hashtable<?,?> currentEnv = ctx.getEnvironment();
- if (currentEnv.get(Context.REFERRAL) == null) {
- ctx.addToEnvironment(Context.REFERRAL, "follow");
- }
- } catch (NamingException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.engineInit about to throw "
- + "InvalidAlgorithmParameterException");
- e.printStackTrace();
- }
- Exception ee = new InvalidAlgorithmParameterException
- ("unable to create InitialDirContext using supplied parameters");
- ee.initCause(e);
- throw (InvalidAlgorithmParameterException)ee;
- }
- }
-
- /**
- * Private class encapsulating the actual LDAP operations and cache
- * handling. Use:
- *
- * LDAPRequest request = new LDAPRequest(dn);
- * request.addRequestedAttribute(CROSS_CERT);
- * request.addRequestedAttribute(CA_CERT);
- * byte[][] crossValues = request.getValues(CROSS_CERT);
- * byte[][] caValues = request.getValues(CA_CERT);
- *
- * At most one LDAP request is sent for each instance created. If all
- * getValues() calls can be satisfied from the cache, no request
- * is sent at all. If a request is sent, all requested attributes
- * are always added to the cache irrespective of whether the getValues()
- * method is called.
- */
- private class LDAPRequest {
-
- private final String name;
- private Map<String, byte[][]> valueMap;
- private final List<String> requestedAttributes;
-
- LDAPRequest(String name) {
- this.name = name;
- requestedAttributes = new ArrayList<>(5);
- }
-
- String getName() {
- return name;
- }
-
- void addRequestedAttribute(String attrId) {
- if (valueMap != null) {
- throw new IllegalStateException("Request already sent");
- }
- requestedAttributes.add(attrId);
- }
-
- /**
- * Gets one or more binary values from an attribute.
- *
- * @param name the location holding the attribute
- * @param attrId the attribute identifier
- * @return an array of binary values (byte arrays)
- * @throws NamingException if a naming exception occurs
- */
- byte[][] getValues(String attrId) throws NamingException {
- if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) {
- System.out.println("Cache hits: " + cacheHits + "; misses: "
- + cacheMisses);
- }
- String cacheKey = name + "|" + attrId;
- byte[][] values = valueCache.get(cacheKey);
- if (values != null) {
- cacheHits++;
- return values;
- }
- cacheMisses++;
- Map<String, byte[][]> attrs = getValueMap();
- values = attrs.get(attrId);
- return values;
- }
-
- /**
- * Get a map containing the values for this request. The first time
- * this method is called on an object, the LDAP request is sent,
- * the results parsed and added to a private map and also to the
- * cache of this LDAPCertStore. Subsequent calls return the private
- * map immediately.
- *
- * The map contains an entry for each requested attribute. The
- * attribute name is the key, values are byte[][]. If there are no
- * values for that attribute, values are byte[0][].
- *
- * @return the value Map
- * @throws NamingException if a naming exception occurs
- */
- private Map<String, byte[][]> getValueMap() throws NamingException {
- if (valueMap != null) {
- return valueMap;
- }
- if (DEBUG) {
- System.out.println("Request: " + name + ":" + requestedAttributes);
- requests++;
- if (requests % 5 == 0) {
- System.out.println("LDAP requests: " + requests);
- }
- }
- valueMap = new HashMap<>(8);
- String[] attrIds = requestedAttributes.toArray(STRING0);
- Attributes attrs;
- try {
- attrs = ctx.getAttributes(name, attrIds);
- } catch (NameNotFoundException e) {
- // name does not exist on this LDAP server
- // treat same as not attributes found
- attrs = EMPTY_ATTRIBUTES;
- }
- for (String attrId : requestedAttributes) {
- Attribute attr = attrs.get(attrId);
- byte[][] values = getAttributeValues(attr);
- cacheAttribute(attrId, values);
- valueMap.put(attrId, values);
- }
- return valueMap;
- }
-
- /**
- * Add the values to the cache.
- */
- private void cacheAttribute(String attrId, byte[][] values) {
- String cacheKey = name + "|" + attrId;
- valueCache.put(cacheKey, values);
- }
-
- /**
- * Get the values for the given attribute. If the attribute is null
- * or does not contain any values, a zero length byte array is
- * returned. NOTE that it is assumed that all values are byte arrays.
- */
- private byte[][] getAttributeValues(Attribute attr)
- throws NamingException {
- byte[][] values;
- if (attr == null) {
- values = BB0;
- } else {
- values = new byte[attr.size()][];
- int i = 0;
- NamingEnumeration<?> enum_ = attr.getAll();
- while (enum_.hasMore()) {
- Object obj = enum_.next();
- if (debug != null) {
- if (obj instanceof String) {
- debug.println("LDAPCertStore.getAttrValues() "
- + "enum.next is a string!: " + obj);
- }
- }
- byte[] value = (byte[])obj;
- values[i++] = value;
- }
- }
- return values;
- }
-
- }
-
- /*
- * Gets certificates from an attribute id and location in the LDAP
- * directory. Returns a Collection containing only the Certificates that
- * match the specified CertSelector.
- *
- * @param name the location holding the attribute
- * @param id the attribute identifier
- * @param sel a CertSelector that the Certificates must match
- * @return a Collection of Certificates found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509Certificate> getCertificates(LDAPRequest request,
- String id, X509CertSelector sel) throws CertStoreException {
-
- /* fetch encoded certs from storage */
- byte[][] encodedCert;
- try {
- encodedCert = request.getValues(id);
- } catch (NamingException namingEx) {
- throw new CertStoreException(namingEx);
- }
-
- int n = encodedCert.length;
- if (n == 0) {
- return Collections.emptySet();
- }
-
- List<X509Certificate> certs = new ArrayList<>(n);
- /* decode certs and check if they satisfy selector */
- for (int i = 0; i < n; i++) {
- ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
- try {
- Certificate cert = cf.generateCertificate(bais);
- if (sel.match(cert)) {
- certs.add((X509Certificate)cert);
- }
- } catch (CertificateException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.getCertificates() encountered "
- + "exception while parsing cert, skipping the bad data: ");
- HexDumpEncoder encoder = new HexDumpEncoder();
- debug.println(
- "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]");
- }
- }
- }
-
- return certs;
- }
-
- /*
- * Gets certificate pairs from an attribute id and location in the LDAP
- * directory.
- *
- * @param name the location holding the attribute
- * @param id the attribute identifier
- * @return a Collection of X509CertificatePairs found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509CertificatePair> getCertPairs(
- LDAPRequest request, String id) throws CertStoreException {
-
- /* fetch the encoded cert pairs from storage */
- byte[][] encodedCertPair;
- try {
- encodedCertPair = request.getValues(id);
- } catch (NamingException namingEx) {
- throw new CertStoreException(namingEx);
- }
-
- int n = encodedCertPair.length;
- if (n == 0) {
- return Collections.emptySet();
- }
-
- List<X509CertificatePair> certPairs = new ArrayList<>(n);
- /* decode each cert pair and add it to the Collection */
- for (int i = 0; i < n; i++) {
- try {
- X509CertificatePair certPair =
- X509CertificatePair.generateCertificatePair(encodedCertPair[i]);
- certPairs.add(certPair);
- } catch (CertificateException e) {
- if (debug != null) {
- debug.println(
- "LDAPCertStore.getCertPairs() encountered exception "
- + "while parsing cert, skipping the bad data: ");
- HexDumpEncoder encoder = new HexDumpEncoder();
- debug.println(
- "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]");
- }
- }
- }
-
- return certPairs;
- }
-
- /*
- * Looks at certificate pairs stored in the crossCertificatePair attribute
- * at the specified location in the LDAP directory. Returns a Collection
- * containing all Certificates stored in the forward component that match
- * the forward CertSelector and all Certificates stored in the reverse
- * component that match the reverse CertSelector.
- * <p>
- * If either forward or reverse is null, all certificates from the
- * corresponding component will be rejected.
- *
- * @param name the location to look in
- * @param forward the forward CertSelector (or null)
- * @param reverse the reverse CertSelector (or null)
- * @return a Collection of Certificates found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509Certificate> getMatchingCrossCerts(
- LDAPRequest request, X509CertSelector forward,
- X509CertSelector reverse)
- throws CertStoreException {
- // Get the cert pairs
- Collection<X509CertificatePair> certPairs =
- getCertPairs(request, CROSS_CERT);
-
- // Find Certificates that match and put them in a list
- ArrayList<X509Certificate> matchingCerts = new ArrayList<>();
- for (X509CertificatePair certPair : certPairs) {
- X509Certificate cert;
- if (forward != null) {
- cert = certPair.getForward();
- if ((cert != null) && forward.match(cert)) {
- matchingCerts.add(cert);
- }
- }
- if (reverse != null) {
- cert = certPair.getReverse();
- if ((cert != null) && reverse.match(cert)) {
- matchingCerts.add(cert);
- }
- }
- }
- return matchingCerts;
- }
-
- /**
- * Returns a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector. If no <code>Certificate</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- * <p>
- * It is not practical to search every entry in the LDAP database for
- * matching <code>Certificate</code>s. Instead, the <code>CertSelector</code>
- * is examined in order to determine where matching <code>Certificate</code>s
- * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
- * If the subject is specified, its directory entry is searched. If the
- * issuer is specified, its directory entry is searched. If neither the
- * subject nor the issuer are specified (or the selector is not an
- * <code>X509CertSelector</code>), a <code>CertStoreException</code> is
- * thrown.
- *
- * @param selector a <code>CertSelector</code> used to select which
- * <code>Certificate</code>s should be returned.
- * @return a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- public synchronized Collection<X509Certificate> engineGetCertificates
- (CertSelector selector) throws CertStoreException {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() selector: "
- + String.valueOf(selector));
- }
-
- if (selector == null) {
- selector = new X509CertSelector();
- }
- if (!(selector instanceof X509CertSelector)) {
- throw new CertStoreException("LDAPCertStore needs an X509CertSelector " +
- "to find certs");
- }
- X509CertSelector xsel = (X509CertSelector) selector;
- int basicConstraints = xsel.getBasicConstraints();
- String subject = xsel.getSubjectAsString();
- String issuer = xsel.getIssuerAsString();
- HashSet<X509Certificate> certs = new HashSet<>();
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
- + basicConstraints);
- }
-
- // basicConstraints:
- // -2: only EE certs accepted
- // -1: no check is done
- // 0: any CA certificate accepted
- // >1: certificate's basicConstraints extension pathlen must match
- if (subject != null) {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() "
- + "subject is not null");
- }
- LDAPRequest request = new LDAPRequest(subject);
- if (basicConstraints > -2) {
- request.addRequestedAttribute(CROSS_CERT);
- request.addRequestedAttribute(CA_CERT);
- request.addRequestedAttribute(ARL);
- if (prefetchCRLs) {
- request.addRequestedAttribute(CRL);
- }
- }
- if (basicConstraints < 0) {
- request.addRequestedAttribute(USER_CERT);
- }
-
- if (basicConstraints > -2) {
- certs.addAll(getMatchingCrossCerts(request, xsel, null));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getMatchingCrossCerts(subject,xsel,null),certs.size(): "
- + certs.size());
- }
- certs.addAll(getCertificates(request, CA_CERT, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getCertificates(subject,CA_CERT,xsel),certs.size(): "
- + certs.size());
- }
- }
- if (basicConstraints < 0) {
- certs.addAll(getCertificates(request, USER_CERT, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getCertificates(subject,USER_CERT, xsel),certs.size(): "
- + certs.size());
- }
- }
- } else {
- if (debug != null) {
- debug.println
- ("LDAPCertStore.engineGetCertificates() subject is null");
- }
- if (basicConstraints == -2) {
- throw new CertStoreException("need subject to find EE certs");
- }
- if (issuer == null) {
- throw new CertStoreException("need subject or issuer to find certs");
- }
- }
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() about to "
- + "getMatchingCrossCerts...");
- }
- if ((issuer != null) && (basicConstraints > -2)) {
- LDAPRequest request = new LDAPRequest(issuer);
- request.addRequestedAttribute(CROSS_CERT);
- request.addRequestedAttribute(CA_CERT);
- request.addRequestedAttribute(ARL);
- if (prefetchCRLs) {
- request.addRequestedAttribute(CRL);
- }
-
- certs.addAll(getMatchingCrossCerts(request, null, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getMatchingCrossCerts(issuer,null,xsel),certs.size(): "
- + certs.size());
- }
- certs.addAll(getCertificates(request, CA_CERT, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getCertificates(issuer,CA_CERT,xsel),certs.size(): "
- + certs.size());
- }
- }
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() returning certs");
- }
- return certs;
- }
-
- /*
- * Gets CRLs from an attribute id and location in the LDAP directory.
- * Returns a Collection containing only the CRLs that match the
- * specified CRLSelector.
- *
- * @param name the location holding the attribute
- * @param id the attribute identifier
- * @param sel a CRLSelector that the CRLs must match
- * @return a Collection of CRLs found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509CRL> getCRLs(LDAPRequest request, String id,
- X509CRLSelector sel) throws CertStoreException {
-
- /* fetch the encoded crls from storage */
- byte[][] encodedCRL;
- try {
- encodedCRL = request.getValues(id);
- } catch (NamingException namingEx) {
- throw new CertStoreException(namingEx);
- }
-
- int n = encodedCRL.length;
- if (n == 0) {
- return Collections.emptySet();
- }
-
- List<X509CRL> crls = new ArrayList<>(n);
- /* decode each crl and check if it matches selector */
- for (int i = 0; i < n; i++) {
- try {
- CRL crl = cf.generateCRL(new ByteArrayInputStream(encodedCRL[i]));
- if (sel.match(crl)) {
- crls.add((X509CRL)crl);
- }
- } catch (CRLException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.getCRLs() encountered exception"
- + " while parsing CRL, skipping the bad data: ");
- HexDumpEncoder encoder = new HexDumpEncoder();
- debug.println("[ " + encoder.encodeBuffer(encodedCRL[i]) + " ]");
- }
- }
- }
-
- return crls;
- }
-
- /**
- * Returns a <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector. If no <code>CRL</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- * <p>
- * It is not practical to search every entry in the LDAP database for
- * matching <code>CRL</code>s. Instead, the <code>CRLSelector</code>
- * is examined in order to determine where matching <code>CRL</code>s
- * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
- * If issuerNames or certChecking are specified, the issuer's directory
- * entry is searched. If neither issuerNames or certChecking are specified
- * (or the selector is not an <code>X509CRLSelector</code>), a
- * <code>CertStoreException</code> is thrown.
- *
- * @param selector A <code>CRLSelector</code> used to select which
- * <code>CRL</code>s should be returned. Specify <code>null</code>
- * to return all <code>CRL</code>s.
- * @return A <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
- throws CertStoreException {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCRLs() selector: "
- + selector);
- }
- // Set up selector and collection to hold CRLs
- if (selector == null) {
- selector = new X509CRLSelector();
- }
- if (!(selector instanceof X509CRLSelector)) {
- throw new CertStoreException("need X509CRLSelector to find CRLs");
- }
- X509CRLSelector xsel = (X509CRLSelector) selector;
- HashSet<X509CRL> crls = new HashSet<>();
-
- // Look in directory entry for issuer of cert we're checking.
- Collection<Object> issuerNames;
- X509Certificate certChecking = xsel.getCertificateChecking();
- if (certChecking != null) {
- issuerNames = new HashSet<>();
- X500Principal issuer = certChecking.getIssuerX500Principal();
- issuerNames.add(issuer.getName(X500Principal.RFC2253));
- } else {
- // But if we don't know which cert we're checking, try the directory
- // entries of all acceptable CRL issuers
- issuerNames = xsel.getIssuerNames();
- if (issuerNames == null) {
- throw new CertStoreException("need issuerNames or certChecking to "
- + "find CRLs");
- }
- }
- for (Object nameObject : issuerNames) {
- String issuerName;
- if (nameObject instanceof byte[]) {
- try {
- X500Principal issuer = new X500Principal((byte[])nameObject);
- issuerName = issuer.getName(X500Principal.RFC2253);
- } catch (IllegalArgumentException e) {
- continue;
- }
- } else {
- issuerName = (String)nameObject;
- }
- // If all we want is CA certs, try to get the (probably shorter) ARL
- Collection<X509CRL> entryCRLs = Collections.emptySet();
- if (certChecking == null || certChecking.getBasicConstraints() != -1) {
- LDAPRequest request = new LDAPRequest(issuerName);
- request.addRequestedAttribute(CROSS_CERT);
- request.addRequestedAttribute(CA_CERT);
- request.addRequestedAttribute(ARL);
- if (prefetchCRLs) {
- request.addRequestedAttribute(CRL);
- }
- try {
- entryCRLs = getCRLs(request, ARL, xsel);
- if (entryCRLs.isEmpty()) {
- // no ARLs found. We assume that means that there are
- // no ARLs on this server at all and prefetch the CRLs.
- prefetchCRLs = true;
- } else {
- crls.addAll(entryCRLs);
- }
- } catch (CertStoreException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCRLs non-fatal error "
- + "retrieving ARLs:" + e);
- e.printStackTrace();
- }
- }
- }
- // Otherwise, get the CRL
- // if certChecking is null, we don't know if we should look in ARL or CRL
- // attribute, so check both for matching CRLs.
- if (entryCRLs.isEmpty() || certChecking == null) {
- LDAPRequest request = new LDAPRequest(issuerName);
- request.addRequestedAttribute(CRL);
- entryCRLs = getCRLs(request, CRL, xsel);
- crls.addAll(entryCRLs);
- }
- }
- return crls;
- }
-
- // converts an LDAP URI into LDAPCertStoreParameters
- static LDAPCertStoreParameters getParameters(URI uri) {
- String host = uri.getHost();
- if (host == null) {
- return new SunLDAPCertStoreParameters();
- } else {
- int port = uri.getPort();
- return (port == -1
- ? new SunLDAPCertStoreParameters(host)
- : new SunLDAPCertStoreParameters(host, port));
- }
- }
-
- /*
- * Subclass of LDAPCertStoreParameters with overridden equals/hashCode
- * methods. This is necessary because the parameters are used as
- * keys in the LDAPCertStore cache.
- */
- private static class SunLDAPCertStoreParameters
- extends LDAPCertStoreParameters {
-
- private volatile int hashCode = 0;
-
- SunLDAPCertStoreParameters(String serverName, int port) {
- super(serverName, port);
- }
- SunLDAPCertStoreParameters(String serverName) {
- super(serverName);
- }
- SunLDAPCertStoreParameters() {
- super();
- }
- public boolean equals(Object obj) {
- if (!(obj instanceof LDAPCertStoreParameters)) {
- return false;
- }
- LDAPCertStoreParameters params = (LDAPCertStoreParameters) obj;
- return (getPort() == params.getPort() &&
- getServerName().equalsIgnoreCase(params.getServerName()));
- }
- public int hashCode() {
- if (hashCode == 0) {
- int result = 17;
- result = 37*result + getPort();
- result = 37*result +
- getServerName().toLowerCase(Locale.ENGLISH).hashCode();
- hashCode = result;
- }
- return hashCode;
- }
- }
-
- /*
- * This inner class wraps an existing X509CertSelector and adds
- * additional criteria to match on when the certificate's subject is
- * different than the LDAP Distinguished Name entry. The LDAPCertStore
- * implementation uses the subject DN as the directory entry for
- * looking up certificates. This can be problematic if the certificates
- * that you want to fetch have a different subject DN than the entry
- * where they are stored. You could set the selector's subject to the
- * LDAP DN entry, but then the resulting match would fail to find the
- * desired certificates because the subject DNs would not match. This
- * class avoids that problem by introducing a certSubject which should
- * be set to the certificate's subject DN when it is different than
- * the LDAP DN.
- */
- static class LDAPCertSelector extends X509CertSelector {
-
- private X500Principal certSubject;
- private X509CertSelector selector;
- private X500Principal subject;
-
- /**
- * Creates an LDAPCertSelector.
- *
- * @param selector the X509CertSelector to wrap
- * @param certSubject the subject DN of the certificate that you want
- * to retrieve via LDAP
- * @param ldapDN the LDAP DN where the certificate is stored
- */
- LDAPCertSelector(X509CertSelector selector, X500Principal certSubject,
- String ldapDN) throws IOException {
- this.selector = selector == null ? new X509CertSelector() : selector;
- this.certSubject = certSubject;
- this.subject = new X500Name(ldapDN).asX500Principal();
- }
-
- // we only override the get (accessor methods) since the set methods
- // will not be invoked by the code that uses this LDAPCertSelector.
- public X509Certificate getCertificate() {
- return selector.getCertificate();
- }
- public BigInteger getSerialNumber() {
- return selector.getSerialNumber();
- }
- public X500Principal getIssuer() {
- return selector.getIssuer();
- }
- public String getIssuerAsString() {
- return selector.getIssuerAsString();
- }
- public byte[] getIssuerAsBytes() throws IOException {
- return selector.getIssuerAsBytes();
- }
- public X500Principal getSubject() {
- // return the ldap DN
- return subject;
- }
- public String getSubjectAsString() {
- // return the ldap DN
- return subject.getName();
- }
- public byte[] getSubjectAsBytes() throws IOException {
- // return the encoded ldap DN
- return subject.getEncoded();
- }
- public byte[] getSubjectKeyIdentifier() {
- return selector.getSubjectKeyIdentifier();
- }
- public byte[] getAuthorityKeyIdentifier() {
- return selector.getAuthorityKeyIdentifier();
- }
- public Date getCertificateValid() {
- return selector.getCertificateValid();
- }
- public Date getPrivateKeyValid() {
- return selector.getPrivateKeyValid();
- }
- public String getSubjectPublicKeyAlgID() {
- return selector.getSubjectPublicKeyAlgID();
- }
- public PublicKey getSubjectPublicKey() {
- return selector.getSubjectPublicKey();
- }
- public boolean[] getKeyUsage() {
- return selector.getKeyUsage();
- }
- public Set<String> getExtendedKeyUsage() {
- return selector.getExtendedKeyUsage();
- }
- public boolean getMatchAllSubjectAltNames() {
- return selector.getMatchAllSubjectAltNames();
- }
- public Collection<List<?>> getSubjectAlternativeNames() {
- return selector.getSubjectAlternativeNames();
- }
- public byte[] getNameConstraints() {
- return selector.getNameConstraints();
- }
- public int getBasicConstraints() {
- return selector.getBasicConstraints();
- }
- public Set<String> getPolicy() {
- return selector.getPolicy();
- }
- public Collection<List<?>> getPathToNames() {
- return selector.getPathToNames();
- }
-
- public boolean match(Certificate cert) {
- // temporarily set the subject criterion to the certSubject
- // so that match will not reject the desired certificates
- selector.setSubject(certSubject);
- boolean match = selector.match(cert);
- selector.setSubject(subject);
- return match;
- }
- }
-
- /**
- * This class has the same purpose as LDAPCertSelector except it is for
- * X.509 CRLs.
- */
- static class LDAPCRLSelector extends X509CRLSelector {
-
- private X509CRLSelector selector;
- private Collection<X500Principal> certIssuers;
- private Collection<X500Principal> issuers;
- private HashSet<Object> issuerNames;
-
- /**
- * Creates an LDAPCRLSelector.
- *
- * @param selector the X509CRLSelector to wrap
- * @param certIssuers the issuer DNs of the CRLs that you want
- * to retrieve via LDAP
- * @param ldapDN the LDAP DN where the CRL is stored
- */
- LDAPCRLSelector(X509CRLSelector selector,
- Collection<X500Principal> certIssuers, String ldapDN)
- throws IOException {
- this.selector = selector == null ? new X509CRLSelector() : selector;
- this.certIssuers = certIssuers;
- issuerNames = new HashSet<>();
- issuerNames.add(ldapDN);
- issuers = new HashSet<>();
- issuers.add(new X500Name(ldapDN).asX500Principal());
- }
- // we only override the get (accessor methods) since the set methods
- // will not be invoked by the code that uses this LDAPCRLSelector.
- public Collection<X500Principal> getIssuers() {
- // return the ldap DN
- return Collections.unmodifiableCollection(issuers);
- }
- public Collection<Object> getIssuerNames() {
- // return the ldap DN
- return Collections.unmodifiableCollection(issuerNames);
- }
- public BigInteger getMinCRL() {
- return selector.getMinCRL();
- }
- public BigInteger getMaxCRL() {
- return selector.getMaxCRL();
- }
- public Date getDateAndTime() {
- return selector.getDateAndTime();
- }
- public X509Certificate getCertificateChecking() {
- return selector.getCertificateChecking();
- }
- public boolean match(CRL crl) {
- // temporarily set the issuer criterion to the certIssuers
- // so that match will not reject the desired CRL
- selector.setIssuers(certIssuers);
- boolean match = selector.match(crl);
- selector.setIssuers(issuers);
- return match;
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java b/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java
deleted file mode 100644
index 8e6899b..0000000
--- a/ojluni/src/main/java/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.provider.certpath.ldap;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.Collection;
-import java.security.NoSuchAlgorithmException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
-import java.security.cert.X509CertSelector;
-import java.security.cert.X509CRLSelector;
-import javax.naming.CommunicationException;
-import javax.naming.ServiceUnavailableException;
-import javax.security.auth.x500.X500Principal;
-
-import sun.security.provider.certpath.CertStoreHelper;
-
-/**
- * LDAP implementation of CertStoreHelper.
- */
-
-public final class LDAPCertStoreHelper
- extends CertStoreHelper
-{
- @Override
- public CertStore getCertStore(URI uri)
- throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
- {
- return LDAPCertStore.getInstance(LDAPCertStore.getParameters(uri));
- }
-
- @Override
- public X509CertSelector wrap(X509CertSelector selector,
- X500Principal certSubject,
- String ldapDN)
- throws IOException
- {
- return new LDAPCertStore.LDAPCertSelector(selector, certSubject, ldapDN);
- }
-
- @Override
- public X509CRLSelector wrap(X509CRLSelector selector,
- Collection<X500Principal> certIssuers,
- String ldapDN)
- throws IOException
- {
- return new LDAPCertStore.LDAPCRLSelector(selector, certIssuers, ldapDN);
- }
-
- @Override
- public boolean isCausedByNetworkIssue(CertStoreException e) {
- Throwable t = e.getCause();
- return (t != null && (t instanceof ServiceUnavailableException ||
- t instanceof CommunicationException));
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/Alerts.java b/ojluni/src/main/java/sun/security/ssl/Alerts.java
deleted file mode 100755
index 672d9b7..0000000
--- a/ojluni/src/main/java/sun/security/ssl/Alerts.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import javax.net.ssl.*;
-
-/*
- * A simple class to congregate alerts, their definitions, and common
- * support methods.
- */
-
-final class Alerts {
-
- /*
- * Alerts are always a fixed two byte format (level/description).
- */
-
- // warnings and fatal errors are package private facilities/constants
-
- // Alert levels (enum AlertLevel)
- static final byte alert_warning = 1;
- static final byte alert_fatal = 2;
-
- /*
- * Alert descriptions (enum AlertDescription)
- *
- * We may not use them all in our processing, but if someone
- * sends us one, we can at least convert it to a string for the
- * user.
- */
- static final byte alert_close_notify = 0;
- static final byte alert_unexpected_message = 10;
- static final byte alert_bad_record_mac = 20;
- static final byte alert_decryption_failed = 21;
- static final byte alert_record_overflow = 22;
- static final byte alert_decompression_failure = 30;
- static final byte alert_handshake_failure = 40;
- static final byte alert_no_certificate = 41;
- static final byte alert_bad_certificate = 42;
- static final byte alert_unsupported_certificate = 43;
- static final byte alert_certificate_revoked = 44;
- static final byte alert_certificate_expired = 45;
- static final byte alert_certificate_unknown = 46;
- static final byte alert_illegal_parameter = 47;
- static final byte alert_unknown_ca = 48;
- static final byte alert_access_denied = 49;
- static final byte alert_decode_error = 50;
- static final byte alert_decrypt_error = 51;
- static final byte alert_export_restriction = 60;
- static final byte alert_protocol_version = 70;
- static final byte alert_insufficient_security = 71;
- static final byte alert_internal_error = 80;
- static final byte alert_user_canceled = 90;
- static final byte alert_no_renegotiation = 100;
-
- // from RFC 3546 (TLS Extensions)
- static final byte alert_unsupported_extension = 110;
- static final byte alert_certificate_unobtainable = 111;
- static final byte alert_unrecognized_name = 112;
- static final byte alert_bad_certificate_status_response = 113;
- static final byte alert_bad_certificate_hash_value = 114;
-
- static String alertDescription(byte code) {
- switch (code) {
-
- case alert_close_notify:
- return "close_notify";
- case alert_unexpected_message:
- return "unexpected_message";
- case alert_bad_record_mac:
- return "bad_record_mac";
- case alert_decryption_failed:
- return "decryption_failed";
- case alert_record_overflow:
- return "record_overflow";
- case alert_decompression_failure:
- return "decompression_failure";
- case alert_handshake_failure:
- return "handshake_failure";
- case alert_no_certificate:
- return "no_certificate";
- case alert_bad_certificate:
- return "bad_certificate";
- case alert_unsupported_certificate:
- return "unsupported_certificate";
- case alert_certificate_revoked:
- return "certificate_revoked";
- case alert_certificate_expired:
- return "certificate_expired";
- case alert_certificate_unknown:
- return "certificate_unknown";
- case alert_illegal_parameter:
- return "illegal_parameter";
- case alert_unknown_ca:
- return "unknown_ca";
- case alert_access_denied:
- return "access_denied";
- case alert_decode_error:
- return "decode_error";
- case alert_decrypt_error:
- return "decrypt_error";
- case alert_export_restriction:
- return "export_restriction";
- case alert_protocol_version:
- return "protocol_version";
- case alert_insufficient_security:
- return "insufficient_security";
- case alert_internal_error:
- return "internal_error";
- case alert_user_canceled:
- return "user_canceled";
- case alert_no_renegotiation:
- return "no_renegotiation";
- case alert_unsupported_extension:
- return "unsupported_extension";
- case alert_certificate_unobtainable:
- return "certificate_unobtainable";
- case alert_unrecognized_name:
- return "unrecognized_name";
- case alert_bad_certificate_status_response:
- return "bad_certificate_status_response";
- case alert_bad_certificate_hash_value:
- return "bad_certificate_hash_value";
-
- default:
- return "<UNKNOWN ALERT: " + (code & 0x0ff) + ">";
- }
- }
-
- static SSLException getSSLException(byte description, String reason) {
- return getSSLException(description, null, reason);
- }
-
- /*
- * Try to be a little more specific in our choice of
- * exceptions to throw.
- */
- static SSLException getSSLException(byte description, Throwable cause,
- String reason) {
-
- SSLException e;
- // the SSLException classes do not have a no-args constructor
- // make up a message if there is none
- if (reason == null) {
- if (cause != null) {
- reason = cause.toString();
- } else {
- reason = "";
- }
- }
- switch (description) {
- case alert_handshake_failure:
- case alert_no_certificate:
- case alert_bad_certificate:
- case alert_unsupported_certificate:
- case alert_certificate_revoked:
- case alert_certificate_expired:
- case alert_certificate_unknown:
- case alert_unknown_ca:
- case alert_access_denied:
- case alert_decrypt_error:
- case alert_export_restriction:
- case alert_insufficient_security:
- case alert_unsupported_extension:
- case alert_certificate_unobtainable:
- case alert_unrecognized_name:
- case alert_bad_certificate_status_response:
- case alert_bad_certificate_hash_value:
- e = new SSLHandshakeException(reason);
- break;
-
- case alert_close_notify:
- case alert_unexpected_message:
- case alert_bad_record_mac:
- case alert_decryption_failed:
- case alert_record_overflow:
- case alert_decompression_failure:
- case alert_illegal_parameter:
- case alert_decode_error:
- case alert_protocol_version:
- case alert_internal_error:
- case alert_user_canceled:
- case alert_no_renegotiation:
- default:
- e = new SSLException(reason);
- break;
- }
-
- if (cause != null) {
- e.initCause(cause);
- }
- return e;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/AppInputStream.java b/ojluni/src/main/java/sun/security/ssl/AppInputStream.java
deleted file mode 100755
index 6c47978..0000000
--- a/ojluni/src/main/java/sun/security/ssl/AppInputStream.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-
-/**
- * InputStream for application data as returned by SSLSocket.getInputStream().
- * It uses an InputRecord as internal buffer that is refilled on demand
- * whenever it runs out of data.
- *
- * @author David Brownell
- */
-class AppInputStream extends InputStream {
-
- // static dummy array we use to implement skip()
- private final static byte[] SKIP_ARRAY = new byte[1024];
-
- private SSLSocketImpl c;
- InputRecord r;
-
- // One element array used to implement the single byte read() method
- private final byte[] oneByte = new byte[1];
-
- AppInputStream(SSLSocketImpl conn) {
- r = new InputRecord();
- c = conn;
- }
-
- /**
- * Return the minimum number of bytes that can be read without blocking.
- * Currently not synchronized.
- */
- public int available() throws IOException {
- if (c.checkEOF() || (r.isAppDataValid() == false)) {
- return 0;
- }
- return r.available();
- }
-
- /**
- * Read a single byte, returning -1 on non-fault EOF status.
- */
- public synchronized int read() throws IOException {
- int n = read(oneByte, 0, 1);
- if (n <= 0) { // EOF
- return -1;
- }
- return oneByte[0] & 0xff;
- }
-
- /**
- * Read up to "len" bytes into this buffer, starting at "off".
- * If the layer above needs more data, it asks for more, so we
- * are responsible only for blocking to fill at most one buffer,
- * and returning "-1" on non-fault EOF status.
- */
- public synchronized int read(byte b[], int off, int len)
- throws IOException {
- if (b == null) {
- throw new NullPointerException();
- } else if (off < 0 || len < 0 || len > b.length - off) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return 0;
- }
-
- if (c.checkEOF()) {
- return -1;
- }
- try {
- /*
- * Read data if needed ... notice that the connection guarantees
- * that handshake, alert, and change cipher spec data streams are
- * handled as they arrive, so we never see them here.
- */
- while (r.available() == 0) {
- c.readDataRecord(r);
- if (c.checkEOF()) {
- return -1;
- }
- }
-
- int howmany = Math.min(len, r.available());
- howmany = r.read(b, off, howmany);
- return howmany;
- } catch (Exception e) {
- // shutdown and rethrow (wrapped) exception as appropriate
- c.handleException(e);
- // dummy for compiler
- return -1;
- }
- }
-
-
- /**
- * Skip n bytes. This implementation is somewhat less efficient
- * than possible, but not badly so (redundant copy). We reuse
- * the read() code to keep things simpler. Note that SKIP_ARRAY
- * is static and may garbled by concurrent use, but we are not interested
- * in the data anyway.
- */
- public synchronized long skip(long n) throws IOException {
- long skipped = 0;
- while (n > 0) {
- int len = (int)Math.min(n, SKIP_ARRAY.length);
- int r = read(SKIP_ARRAY, 0, len);
- if (r <= 0) {
- break;
- }
- n -= r;
- skipped += r;
- }
- return skipped;
- }
-
- /*
- * Socket close is already synchronized, no need to block here.
- */
- public void close() throws IOException {
- c.close();
- }
-
- // inherit default mark/reset behavior (throw Exceptions) from InputStream
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/AppOutputStream.java b/ojluni/src/main/java/sun/security/ssl/AppOutputStream.java
deleted file mode 100755
index 5082bec..0000000
--- a/ojluni/src/main/java/sun/security/ssl/AppOutputStream.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.OutputStream;
-import java.io.IOException;
-
-/*
- * Output stream for application data. This is the kind of stream
- * that's handed out via SSLSocket.getOutputStream(). It's all the application
- * ever sees.
- *
- * Once the initial handshake has completed, application data may be
- * interleaved with handshake data. That is handled internally and remains
- * transparent to the application.
- *
- * @author David Brownell
- */
-class AppOutputStream extends OutputStream {
-
- private SSLSocketImpl c;
- OutputRecord r;
-
- // One element array used to implement the write(byte) method
- private final byte[] oneByte = new byte[1];
-
- AppOutputStream(SSLSocketImpl conn) {
- r = new OutputRecord(Record.ct_application_data);
- c = conn;
- }
-
- /**
- * Write the data out, NOW.
- */
- synchronized public void write(byte b[], int off, int len)
- throws IOException {
- if (b == null) {
- throw new NullPointerException();
- } else if (off < 0 || len < 0 || len > b.length - off) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return;
- }
-
- // check if the Socket is invalid (error or closed)
- c.checkWrite();
-
- /*
- * By default, we counter chosen plaintext issues on CBC mode
- * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
- * data in the first record of every payload, and the rest in
- * subsequent record(s). Note that the issues have been solved in
- * TLS 1.1 or later.
- *
- * It is not necessary to split the very first application record of
- * a freshly negotiated TLS session, as there is no previous
- * application data to guess. To improve compatibility, we will not
- * split such records.
- *
- * This avoids issues in the outbound direction. For a full fix,
- * the peer must have similar protections.
- */
- boolean isFirstRecordOfThePayload = true;
-
- // Always flush at the end of each application level record.
- // This lets application synchronize read and write streams
- // however they like; if we buffered here, they couldn't.
- try {
- do {
- boolean holdRecord = false;
- int howmuch;
- if (isFirstRecordOfThePayload && c.needToSplitPayload()) {
- howmuch = Math.min(0x01, r.availableDataBytes());
- /*
- * Nagle's algorithm (TCP_NODELAY) was coming into
- * play here when writing short (split) packets.
- * Signal to the OutputRecord code to internally
- * buffer this small packet until the next outbound
- * packet (of any type) is written.
- */
- if ((len != 1) && (howmuch == 1)) {
- holdRecord = true;
- }
- } else {
- howmuch = Math.min(len, r.availableDataBytes());
- }
-
- if (isFirstRecordOfThePayload && howmuch != 0) {
- isFirstRecordOfThePayload = false;
- }
-
- // NOTE: *must* call c.writeRecord() even for howmuch == 0
- if (howmuch > 0) {
- r.write(b, off, howmuch);
- off += howmuch;
- len -= howmuch;
- }
- c.writeRecord(r, holdRecord);
- c.checkWrite();
- } while (len > 0);
- } catch (Exception e) {
- // shutdown and rethrow (wrapped) exception as appropriate
- c.handleException(e);
- }
- }
-
- /**
- * Write one byte now.
- */
- synchronized public void write(int i) throws IOException {
- oneByte[0] = (byte)i;
- write(oneByte, 0, 1);
- }
-
- /*
- * Socket close is already synchronized, no need to block here.
- */
- public void close() throws IOException {
- c.close();
- }
-
- // inherit no-op flush()
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/BaseSSLSocketImpl.java b/ojluni/src/main/java/sun/security/ssl/BaseSSLSocketImpl.java
deleted file mode 100755
index ef7503b..0000000
--- a/ojluni/src/main/java/sun/security/ssl/BaseSSLSocketImpl.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.channels.SocketChannel;
-import java.net.*;
-
-import javax.net.ssl.*;
-
-/**
- * Abstract base class for SSLSocketImpl. Its purpose is to house code with
- * no SSL related logic (or no logic at all). This makes SSLSocketImpl shorter
- * and easier to read. It contains a few constants and static methods plus
- * overridden java.net.Socket methods.
- *
- * Methods are defined final to ensure that they are not accidentally
- * overridden in SSLSocketImpl.
- *
- * @see javax.net.ssl.SSLSocket
- * @see SSLSocketImpl
- *
- */
-abstract class BaseSSLSocketImpl extends SSLSocket {
-
- /*
- * Normally "self" is "this" ... but not when this connection is
- * layered over a preexisting socket. If we're using an existing
- * socket, we delegate some actions to it. Else, we delegate
- * instead to "super". This is important to ensure that we don't
- * recurse infinitely ... e.g. close() calling itself, or doing
- * I/O in terms of our own streams.
- */
- final Socket self;
-
- BaseSSLSocketImpl() {
- super();
- this.self = this;
- }
-
- BaseSSLSocketImpl(Socket socket) {
- super();
- this.self = socket;
- }
-
- //
- // CONSTANTS AND STATIC METHODS
- //
-
- /**
- * TLS requires that a close_notify warning alert is sent before the
- * connection is closed in order to avoid truncation attacks. Some
- * implementations (MS IIS and others) don't do that. The property
- * below controls whether we accept that or treat it as an error.
- *
- * The default is "false", i.e. tolerate the broken behavior.
- */
- private final static String PROP_NAME =
- "com.sun.net.ssl.requireCloseNotify";
-
- final static boolean requireCloseNotify =
- Debug.getBooleanProperty(PROP_NAME, false);
-
- //
- // MISC SOCKET METHODS
- //
-
- /**
- * Returns the unique {@link java.nio.SocketChannel SocketChannel} object
- * associated with this socket, if any.
- * @see java.net.Socket#getChannel
- */
- public final SocketChannel getChannel() {
- if (self == this) {
- return super.getChannel();
- } else {
- return self.getChannel();
- }
- }
-
- /**
- * Binds the address to the socket.
- * @see java.net.Socket#bind
- */
- public void bind(SocketAddress bindpoint) throws IOException {
- /*
- * Bind to this socket
- */
- if (self == this) {
- super.bind(bindpoint);
- } else {
- // If we're binding on a layered socket...
- throw new IOException(
- "Underlying socket should already be connected");
- }
- }
-
- /**
- * Returns the address of the endpoint this socket is connected to
- * @see java.net.Socket#getLocalSocketAddress
- */
- public SocketAddress getLocalSocketAddress() {
- if (self == this) {
- return super.getLocalSocketAddress();
- } else {
- return self.getLocalSocketAddress();
- }
- }
-
- /**
- * Returns the address of the endpoint this socket is connected to
- * @see java.net.Socket#getRemoteSocketAddress
- */
- public SocketAddress getRemoteSocketAddress() {
- if (self == this) {
- return super.getRemoteSocketAddress();
- } else {
- return self.getRemoteSocketAddress();
- }
- }
-
- /**
- * Connects this socket to the server.
- *
- * This method is either called on an unconnected SSLSocketImpl by the
- * application, or it is called in the constructor of a regular
- * SSLSocketImpl. If we are layering on top on another socket, then
- * this method should not be called, because we assume that the
- * underlying socket is already connected by the time it is passed to
- * us.
- *
- * @param endpoint the <code>SocketAddress</code>
- * @throws IOException if an error occurs during the connection
- */
- public final void connect(SocketAddress endpoint) throws IOException {
- connect(endpoint, 0);
- }
-
- /**
- * Returns the connection state of the socket.
- * @see java.net.Socket#isConnected
- */
- public final boolean isConnected() {
- if (self == this) {
- return super.isConnected();
- } else {
- return self.isConnected();
- }
- }
-
- /**
- * Returns the binding state of the socket.
- * @see java.net.Socket#isBound
- */
- public final boolean isBound() {
- if (self == this) {
- return super.isBound();
- } else {
- return self.isBound();
- }
- }
-
- //
- // CLOSE RELATED METHODS
- //
-
- /**
- * The semantics of shutdownInput is not supported in TLS 1.0
- * spec. Thus when the method is called on an SSL socket, an
- * UnsupportedOperationException will be thrown.
- *
- * @throws UnsupportedOperationException
- */
- public final void shutdownInput() throws IOException {
- throw new UnsupportedOperationException("The method shutdownInput()" +
- " is not supported in SSLSocket");
- }
-
- /**
- * The semantics of shutdownOutput is not supported in TLS 1.0
- * spec. Thus when the method is called on an SSL socket, an
- * UnsupportedOperationException will be thrown.
- *
- * @throws UnsupportedOperationException
- */
- public final void shutdownOutput() throws IOException {
- throw new UnsupportedOperationException("The method shutdownOutput()" +
- " is not supported in SSLSocket");
-
- }
-
- /**
- * Returns the input state of the socket
- * @see java.net.Socket#isInputShutdown
- */
- public final boolean isInputShutdown() {
- if (self == this) {
- return super.isInputShutdown();
- } else {
- return self.isInputShutdown();
- }
- }
-
- /**
- * Returns the output state of the socket
- * @see java.net.Socket#isOutputShutdown
- */
- public final boolean isOutputShutdown() {
- if (self == this) {
- return super.isOutputShutdown();
- } else {
- return self.isOutputShutdown();
- }
- }
-
- /**
- * Ensures that the SSL connection is closed down as cleanly
- * as possible, in case the application forgets to do so.
- * This allows SSL connections to be implicitly reclaimed,
- * rather than forcing them to be explicitly reclaimed at
- * the penalty of prematurly killing SSL sessions.
- */
- protected final void finalize() throws Throwable {
- try {
- close();
- } catch (IOException e1) {
- try {
- if (self == this) {
- super.close();
- }
- } catch (IOException e2) {
- // ignore
- }
- } finally {
- // We called close on the underlying socket above to
- // make doubly sure all resources got released. We
- // don't finalize self in the case of overlain sockets,
- // that's a different object which the GC will finalize
- // separately.
-
- super.finalize();
- }
- }
-
- //
- // GET ADDRESS METHODS
- //
-
- /**
- * Returns the address of the remote peer for this connection.
- */
- public final InetAddress getInetAddress() {
- if (self == this) {
- return super.getInetAddress();
- } else {
- return self.getInetAddress();
- }
- }
-
- /**
- * Gets the local address to which the socket is bound.
- *
- * @return the local address to which the socket is bound.
- * @since JDK1.1
- */
- public final InetAddress getLocalAddress() {
- if (self == this) {
- return super.getLocalAddress();
- } else {
- return self.getLocalAddress();
- }
- }
-
- /**
- * Returns the number of the remote port that this connection uses.
- */
- public final int getPort() {
- if (self == this) {
- return super.getPort();
- } else {
- return self.getPort();
- }
- }
-
- /**
- * Returns the number of the local port that this connection uses.
- */
- public final int getLocalPort() {
- if (self == this) {
- return super.getLocalPort();
- } else {
- return self.getLocalPort();
- }
- }
-
- //
- // SOCKET OPTION METHODS
- //
-
- /**
- * Enables or disables the Nagle optimization.
- * @see java.net.Socket#setTcpNoDelay
- */
- public final void setTcpNoDelay(boolean value) throws SocketException {
- if (self == this) {
- super.setTcpNoDelay(value);
- } else {
- self.setTcpNoDelay(value);
- }
- }
-
- /**
- * Returns true if the Nagle optimization is disabled. This
- * relates to low-level buffering of TCP traffic, delaying the
- * traffic to promote better throughput.
- *
- * @see java.net.Socket#getTcpNoDelay
- */
- public final boolean getTcpNoDelay() throws SocketException {
- if (self == this) {
- return super.getTcpNoDelay();
- } else {
- return self.getTcpNoDelay();
- }
- }
-
- /**
- * Assigns the socket's linger timeout.
- * @see java.net.Socket#setSoLinger
- */
- public final void setSoLinger(boolean flag, int linger)
- throws SocketException {
- if (self == this) {
- super.setSoLinger(flag, linger);
- } else {
- self.setSoLinger(flag, linger);
- }
- }
-
- /**
- * Returns the socket's linger timeout.
- * @see java.net.Socket#getSoLinger
- */
- public final int getSoLinger() throws SocketException {
- if (self == this) {
- return super.getSoLinger();
- } else {
- return self.getSoLinger();
- }
- }
-
- /**
- * Send one byte of urgent data on the socket.
- * @see java.net.Socket#sendUrgentData
- * At this point, there seems to be no specific requirement to support
- * this for an SSLSocket. An implementation can be provided if a need
- * arises in future.
- */
- public final void sendUrgentData(int data) throws SocketException {
- throw new SocketException("This method is not supported "
- + "by SSLSockets");
- }
-
- /**
- * Enable/disable OOBINLINE (receipt of TCP urgent data) By default, this
- * option is disabled and TCP urgent data received on a socket is silently
- * discarded.
- * @see java.net.Socket#setOOBInline
- * Setting OOBInline does not have any effect on SSLSocket,
- * since currently we don't support sending urgent data.
- */
- public final void setOOBInline(boolean on) throws SocketException {
- throw new SocketException("This method is ineffective, since"
- + " sending urgent data is not supported by SSLSockets");
- }
-
- /**
- * Tests if OOBINLINE is enabled.
- * @see java.net.Socket#getOOBInline
- */
- public final boolean getOOBInline() throws SocketException {
- throw new SocketException("This method is ineffective, since"
- + " sending urgent data is not supported by SSLSockets");
- }
-
- /**
- * Returns the socket timeout.
- * @see java.net.Socket#getSoTimeout
- */
- public final int getSoTimeout() throws SocketException {
- if (self == this) {
- return super.getSoTimeout();
- } else {
- return self.getSoTimeout();
- }
- }
-
- public final void setSendBufferSize(int size) throws SocketException {
- if (self == this) {
- super.setSendBufferSize(size);
- } else {
- self.setSendBufferSize(size);
- }
- }
-
- public final int getSendBufferSize() throws SocketException {
- if (self == this) {
- return super.getSendBufferSize();
- } else {
- return self.getSendBufferSize();
- }
- }
-
- public final void setReceiveBufferSize(int size) throws SocketException {
- if (self == this) {
- super.setReceiveBufferSize(size);
- } else {
- self.setReceiveBufferSize(size);
- }
- }
-
- public final int getReceiveBufferSize() throws SocketException {
- if (self == this) {
- return super.getReceiveBufferSize();
- } else {
- return self.getReceiveBufferSize();
- }
- }
-
- /**
- * Enable/disable SO_KEEPALIVE.
- * @see java.net.Socket#setKeepAlive
- */
- public final void setKeepAlive(boolean on) throws SocketException {
- if (self == this) {
- super.setKeepAlive(on);
- } else {
- self.setKeepAlive(on);
- }
- }
-
- /**
- * Tests if SO_KEEPALIVE is enabled.
- * @see java.net.Socket#getKeepAlive
- */
- public final boolean getKeepAlive() throws SocketException {
- if (self == this) {
- return super.getKeepAlive();
- } else {
- return self.getKeepAlive();
- }
- }
-
- /**
- * Sets traffic class or type-of-service octet in the IP header for
- * packets sent from this Socket.
- * @see java.net.Socket#setTrafficClass
- */
- public final void setTrafficClass(int tc) throws SocketException {
- if (self == this) {
- super.setTrafficClass(tc);
- } else {
- self.setTrafficClass(tc);
- }
- }
-
- /**
- * Gets traffic class or type-of-service in the IP header for packets
- * sent from this Socket.
- * @see java.net.Socket#getTrafficClass
- */
- public final int getTrafficClass() throws SocketException {
- if (self == this) {
- return super.getTrafficClass();
- } else {
- return self.getTrafficClass();
- }
- }
-
- /**
- * Enable/disable SO_REUSEADDR.
- * @see java.net.Socket#setReuseAddress
- */
- public final void setReuseAddress(boolean on) throws SocketException {
- if (self == this) {
- super.setReuseAddress(on);
- } else {
- self.setReuseAddress(on);
- }
- }
-
- /**
- * Tests if SO_REUSEADDR is enabled.
- * @see java.net.Socket#getReuseAddress
- */
- public final boolean getReuseAddress() throws SocketException {
- if (self == this) {
- return super.getReuseAddress();
- } else {
- return self.getReuseAddress();
- }
- }
-
- /**
- * Sets performance preferences for this socket.
- *
- * @see java.net.Socket#setPerformancePreferences(int, int, int)
- */
- public void setPerformancePreferences(int connectionTime,
- int latency, int bandwidth) {
- if (self == this) {
- super.setPerformancePreferences(
- connectionTime, latency, bandwidth);
- } else {
- self.setPerformancePreferences(
- connectionTime, latency, bandwidth);
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/ByteBufferInputStream.java b/ojluni/src/main/java/sun/security/ssl/ByteBufferInputStream.java
deleted file mode 100755
index 7191621..0000000
--- a/ojluni/src/main/java/sun/security/ssl/ByteBufferInputStream.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-
-/**
- * A simple InputStream which uses ByteBuffers as it's backing store.
- * <P>
- * The only IOException should come if the InputStream has been closed.
- * All other IOException should not occur because all the data is local.
- * Data reads on an exhausted ByteBuffer returns a -1.
- *
- * @author Brad Wetmore
- */
-class ByteBufferInputStream extends InputStream {
-
- ByteBuffer bb;
-
- ByteBufferInputStream(ByteBuffer bb) {
- this.bb = bb;
- }
-
- /**
- * Returns a byte from the ByteBuffer.
- *
- * Increments position().
- */
- public int read() throws IOException {
-
- if (bb == null) {
- throw new IOException("read on a closed InputStream");
- }
-
- if (bb.remaining() == 0) {
- return -1;
- }
- return bb.get();
- }
-
- /**
- * Returns a byte array from the ByteBuffer.
- *
- * Increments position().
- */
- public int read(byte b[]) throws IOException {
-
- if (bb == null) {
- throw new IOException("read on a closed InputStream");
- }
-
- return read(b, 0, b.length);
- }
-
- /**
- * Returns a byte array from the ByteBuffer.
- *
- * Increments position().
- */
- public int read(byte b[], int off, int len) throws IOException {
-
- if (bb == null) {
- throw new IOException("read on a closed InputStream");
- }
-
- if (b == null) {
- throw new NullPointerException();
- } else if (off < 0 || len < 0 || len > b.length - off) {
- throw new IndexOutOfBoundsException();
- } else if (len == 0) {
- return 0;
- }
-
- int length = Math.min(bb.remaining(), len);
- if (length == 0) {
- return -1;
- }
-
- bb.get(b, off, length);
- return length;
- }
-
- /**
- * Skips over and discards <code>n</code> bytes of data from this input
- * stream.
- */
- public long skip(long n) throws IOException {
-
- if (bb == null) {
- throw new IOException("skip on a closed InputStream");
- }
-
- if (n <= 0) {
- return 0;
- }
-
- /*
- * ByteBuffers have at most an int, so lose the upper bits.
- * The contract allows this.
- */
- int nInt = (int) n;
- int skip = Math.min(bb.remaining(), nInt);
-
- bb.position(bb.position() + skip);
-
- return nInt;
- }
-
- /**
- * Returns the number of bytes that can be read (or skipped over)
- * from this input stream without blocking by the next caller of a
- * method for this input stream.
- */
- public int available() throws IOException {
-
- if (bb == null) {
- throw new IOException("available on a closed InputStream");
- }
-
- return bb.remaining();
- }
-
- /**
- * Closes this input stream and releases any system resources associated
- * with the stream.
- *
- * @exception IOException if an I/O error occurs.
- */
- public void close() throws IOException {
- bb = null;
- }
-
- /**
- * Marks the current position in this input stream.
- */
- public synchronized void mark(int readlimit) {}
-
- /**
- * Repositions this stream to the position at the time the
- * <code>mark</code> method was last called on this input stream.
- */
- public synchronized void reset() throws IOException {
- throw new IOException("mark/reset not supported");
- }
-
- /**
- * Tests if this input stream supports the <code>mark</code> and
- * <code>reset</code> methods.
- */
- public boolean markSupported() {
- return false;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/CipherBox.java b/ojluni/src/main/java/sun/security/ssl/CipherBox.java
deleted file mode 100755
index 4dfbadd..0000000
--- a/ojluni/src/main/java/sun/security/ssl/CipherBox.java
+++ /dev/null
@@ -1,824 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.Hashtable;
-
-import java.security.*;
-import javax.crypto.*;
-import javax.crypto.spec.SecretKeySpec;
-import javax.crypto.spec.IvParameterSpec;
-
-import java.nio.*;
-
-import sun.security.ssl.CipherSuite.*;
-import static sun.security.ssl.CipherSuite.*;
-
-import sun.misc.HexDumpEncoder;
-
-
-/**
- * This class handles bulk data enciphering/deciphering for each SSLv3
- * message. This provides data confidentiality. Stream ciphers (such
- * as RC4) don't need to do padding; block ciphers (e.g. DES) need it.
- *
- * Individual instances are obtained by calling the static method
- * newCipherBox(), which should only be invoked by BulkCipher.newCipher().
- *
- * In RFC 2246, with bock ciphers in CBC mode, the Initialization
- * Vector (IV) for the first record is generated with the other keys
- * and secrets when the security parameters are set. The IV for
- * subsequent records is the last ciphertext block from the previous
- * record.
- *
- * In RFC 4346, the implicit Initialization Vector (IV) is replaced
- * with an explicit IV to protect against CBC attacks. RFC 4346
- * recommends two algorithms used to generated the per-record IV.
- * The implementation uses the algorithm (2)(b), as described at
- * section 6.2.3.2 of RFC 4346.
- *
- * The usage of IV in CBC block cipher can be illustrated in
- * the following diagrams.
- *
- * (random)
- * R P1 IV C1
- * | | | |
- * SIV---+ |-----+ |-... |----- |------
- * | | | | | | | |
- * +----+ | +----+ | +----+ | +----+ |
- * | Ek | | + Ek + | | Dk | | | Dk | |
- * +----+ | +----+ | +----+ | +----+ |
- * | | | | | | | |
- * |----| |----| SIV--+ |----| |-...
- * | | | |
- * IV C1 R P1
- * (discard)
- *
- * CBC Encryption CBC Decryption
- *
- * NOTE that any ciphering involved in key exchange (e.g. with RSA) is
- * handled separately.
- *
- * @author David Brownell
- * @author Andreas Sterbenz
- */
-final class CipherBox {
-
- // A CipherBox that implements the identity operation
- final static CipherBox NULL = new CipherBox();
-
- /* Class and subclass dynamic debugging support */
- private static final Debug debug = Debug.getInstance("ssl");
-
- // the protocol version this cipher conforms to
- private final ProtocolVersion protocolVersion;
-
- // cipher object
- private final Cipher cipher;
-
- /**
- * Cipher blocksize, 0 for stream ciphers
- */
- private int blockSize;
-
- /**
- * secure random
- */
- private SecureRandom random;
-
- /**
- * Is the cipher of CBC mode?
- */
- private final boolean isCBCMode;
-
- /**
- * Fixed masks of various block size, as the initial decryption IVs
- * for TLS 1.1 or later.
- *
- * For performance, we do not use random IVs. As the initial decryption
- * IVs will be discarded by TLS decryption processes, so the fixed masks
- * do not hurt cryptographic strength.
- */
- private static Hashtable<Integer, IvParameterSpec> masks;
-
- /**
- * NULL cipherbox. Identity operation, no encryption.
- */
- private CipherBox() {
- this.protocolVersion = ProtocolVersion.DEFAULT;
- this.cipher = null;
- this.isCBCMode = false;
- }
-
- /**
- * Construct a new CipherBox using the cipher transformation.
- *
- * @exception NoSuchAlgorithmException if no appropriate JCE Cipher
- * implementation could be found.
- */
- private CipherBox(ProtocolVersion protocolVersion, BulkCipher bulkCipher,
- SecretKey key, IvParameterSpec iv, SecureRandom random,
- boolean encrypt) throws NoSuchAlgorithmException {
- try {
- this.protocolVersion = protocolVersion;
- this.cipher = JsseJce.getCipher(bulkCipher.transformation);
- int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
-
- if (random == null) {
- random = JsseJce.getSecureRandom();
- }
- this.random = random;
- this.isCBCMode = bulkCipher.isCBCMode;
-
- /*
- * RFC 4346 recommends two algorithms used to generated the
- * per-record IV. The implementation uses the algorithm (2)(b),
- * as described at section 6.2.3.2 of RFC 4346.
- *
- * As we don't care about the initial IV value for TLS 1.1 or
- * later, so if the "iv" parameter is null, we use the default
- * value generated by Cipher.init() for encryption, and a fixed
- * mask for decryption.
- */
- if (iv == null && bulkCipher.ivSize != 0 &&
- mode == Cipher.DECRYPT_MODE &&
- protocolVersion.v >= ProtocolVersion.TLS11.v) {
- iv = getFixedMask(bulkCipher.ivSize);
- }
-
- cipher.init(mode, key, iv, random);
-
- // Do not call getBlockSize until after init()
- // otherwise we would disrupt JCE delayed provider selection
- blockSize = cipher.getBlockSize();
- // some providers implement getBlockSize() incorrectly
- if (blockSize == 1) {
- blockSize = 0;
- }
- } catch (NoSuchAlgorithmException e) {
- throw e;
- } catch (Exception e) {
- throw new NoSuchAlgorithmException
- ("Could not create cipher " + bulkCipher, e);
- } catch (ExceptionInInitializerError e) {
- throw new NoSuchAlgorithmException
- ("Could not create cipher " + bulkCipher, e);
- }
- }
-
- /*
- * Factory method to obtain a new CipherBox object.
- */
- static CipherBox newCipherBox(ProtocolVersion version, BulkCipher cipher,
- SecretKey key, IvParameterSpec iv, SecureRandom random,
- boolean encrypt) throws NoSuchAlgorithmException {
- if (cipher.allowed == false) {
- throw new NoSuchAlgorithmException("Unsupported cipher " + cipher);
- }
-
- if (cipher == B_NULL) {
- return NULL;
- } else {
- return new CipherBox(version, cipher, key, iv, random, encrypt);
- }
- }
-
- /*
- * Get a fixed mask, as the initial decryption IVs for TLS 1.1 or later.
- */
- private static IvParameterSpec getFixedMask(int ivSize) {
- if (masks == null) {
- masks = new Hashtable<Integer, IvParameterSpec>(5);
- }
-
- IvParameterSpec iv = masks.get(ivSize);
- if (iv == null) {
- iv = new IvParameterSpec(new byte[ivSize]);
- masks.put(ivSize, iv);
- }
-
- return iv;
- }
-
- /*
- * Encrypts a block of data, returning the size of the
- * resulting block.
- */
- int encrypt(byte[] buf, int offset, int len) {
- if (cipher == null) {
- return len;
- }
-
- try {
- if (blockSize != 0) {
- // TLSv1.1 needs a IV block
- if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
- // generate a random number
- byte[] prefix = new byte[blockSize];
- random.nextBytes(prefix);
-
- // move forward the plaintext
- System.arraycopy(buf, offset,
- buf, offset + prefix.length, len);
-
- // prefix the plaintext
- System.arraycopy(prefix, 0,
- buf, offset, prefix.length);
-
- len += prefix.length;
- }
-
- len = addPadding(buf, offset, len, blockSize);
- }
- if (debug != null && Debug.isOn("plaintext")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
-
- System.out.println(
- "Padded plaintext before ENCRYPTION: len = "
- + len);
- hd.encodeBuffer(
- new ByteArrayInputStream(buf, offset, len),
- System.out);
- } catch (IOException e) { }
- }
- int newLen = cipher.update(buf, offset, len, buf, offset);
- if (newLen != len) {
- // catch BouncyCastle buffering error
- throw new RuntimeException("Cipher buffering error " +
- "in JCE provider " + cipher.getProvider().getName());
- }
- return newLen;
- } catch (ShortBufferException e) {
- throw new ArrayIndexOutOfBoundsException(e.toString());
- }
- }
-
- /*
- * Encrypts a ByteBuffer block of data, returning the size of the
- * resulting block.
- *
- * The byte buffers position and limit initially define the amount
- * to encrypt. On return, the position and limit are
- * set to last position padded/encrypted. The limit may have changed
- * because of the added padding bytes.
- */
- int encrypt(ByteBuffer bb) {
-
- int len = bb.remaining();
-
- if (cipher == null) {
- bb.position(bb.limit());
- return len;
- }
-
- try {
- int pos = bb.position();
-
- if (blockSize != 0) {
- // TLSv1.1 needs a IV block
- if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
- // generate a random number
- byte[] prefix = new byte[blockSize];
- random.nextBytes(prefix);
-
- // move forward the plaintext
- byte[] buf = null;
- int limit = bb.limit();
- if (bb.hasArray()) {
- int arrayOffset = bb.arrayOffset();
- buf = bb.array();
- System.arraycopy(buf, arrayOffset + pos,
- buf, arrayOffset + pos + prefix.length,
- limit - pos);
- bb.limit(limit + prefix.length);
- } else {
- buf = new byte[limit - pos];
- bb.get(buf, 0, limit - pos);
- bb.position(pos + prefix.length);
- bb.limit(limit + prefix.length);
- bb.put(buf);
- }
- bb.position(pos);
-
- // prefix the plaintext
- bb.put(prefix);
- bb.position(pos);
- }
-
- // addPadding adjusts pos/limit
- len = addPadding(bb, blockSize);
- bb.position(pos);
- }
- if (debug != null && Debug.isOn("plaintext")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
-
- System.out.println(
- "Padded plaintext before ENCRYPTION: len = "
- + len);
- hd.encodeBuffer(bb, System.out);
-
- } catch (IOException e) { }
- /*
- * reset back to beginning
- */
- bb.position(pos);
- }
-
- /*
- * Encrypt "in-place". This does not add its own padding.
- */
- ByteBuffer dup = bb.duplicate();
- int newLen = cipher.update(dup, bb);
-
- if (bb.position() != dup.position()) {
- throw new RuntimeException("bytebuffer padding error");
- }
-
- if (newLen != len) {
- // catch BouncyCastle buffering error
- throw new RuntimeException("Cipher buffering error " +
- "in JCE provider " + cipher.getProvider().getName());
- }
- return newLen;
- } catch (ShortBufferException e) {
- RuntimeException exc = new RuntimeException(e.toString());
- exc.initCause(e);
- throw exc;
- }
- }
-
-
- /*
- * Decrypts a block of data, returning the size of the
- * resulting block if padding was required.
- *
- * For SSLv3 and TLSv1.0, with block ciphers in CBC mode the
- * Initialization Vector (IV) for the first record is generated by
- * the handshake protocol, the IV for subsequent records is the
- * last ciphertext block from the previous record.
- *
- * From TLSv1.1, the implicit IV is replaced with an explicit IV to
- * protect against CBC attacks.
- *
- * Differentiating between bad_record_mac and decryption_failed alerts
- * may permit certain attacks against CBC mode. It is preferable to
- * uniformly use the bad_record_mac alert to hide the specific type of
- * the error.
- */
- int decrypt(byte[] buf, int offset, int len,
- int tagLen) throws BadPaddingException {
- if (cipher == null) {
- return len;
- }
-
- try {
- int newLen = cipher.update(buf, offset, len, buf, offset);
- if (newLen != len) {
- // catch BouncyCastle buffering error
- throw new RuntimeException("Cipher buffering error " +
- "in JCE provider " + cipher.getProvider().getName());
- }
- if (debug != null && Debug.isOn("plaintext")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
-
- System.out.println(
- "Padded plaintext after DECRYPTION: len = "
- + newLen);
- hd.encodeBuffer(
- new ByteArrayInputStream(buf, offset, newLen),
- System.out);
- } catch (IOException e) { }
- }
-
- if (blockSize != 0) {
- newLen = removePadding(
- buf, offset, newLen, tagLen, blockSize, protocolVersion);
-
- if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
- if (newLen < blockSize) {
- throw new BadPaddingException("invalid explicit IV");
- }
-
- // discards the first cipher block, the IV component.
- System.arraycopy(buf, offset + blockSize,
- buf, offset, newLen - blockSize);
-
- newLen -= blockSize;
- }
- }
- return newLen;
- } catch (ShortBufferException e) {
- throw new ArrayIndexOutOfBoundsException(e.toString());
- }
- }
-
-
- /*
- * Decrypts a block of data, returning the size of the
- * resulting block if padding was required. position and limit
- * point to the end of the decrypted/depadded data. The initial
- * limit and new limit may be different, given we may
- * have stripped off some padding bytes.
- *
- * @see decrypt(byte[], int, int)
- */
- int decrypt(ByteBuffer bb, int tagLen) throws BadPaddingException {
-
- int len = bb.remaining();
-
- if (cipher == null) {
- bb.position(bb.limit());
- return len;
- }
-
- try {
- /*
- * Decrypt "in-place".
- */
- int pos = bb.position();
- ByteBuffer dup = bb.duplicate();
- int newLen = cipher.update(dup, bb);
- if (newLen != len) {
- // catch BouncyCastle buffering error
- throw new RuntimeException("Cipher buffering error " +
- "in JCE provider " + cipher.getProvider().getName());
- }
-
- if (debug != null && Debug.isOn("plaintext")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
-
- System.out.println(
- "Padded plaintext after DECRYPTION: len = "
- + newLen);
-
- hd.encodeBuffer(
- (ByteBuffer)bb.duplicate().position(pos), System.out);
- } catch (IOException e) { }
- }
-
- /*
- * Remove the block padding.
- */
- if (blockSize != 0) {
- bb.position(pos);
- newLen = removePadding(
- bb, tagLen, blockSize, protocolVersion);
-
- if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
- if (newLen < blockSize) {
- throw new BadPaddingException("invalid explicit IV");
- }
-
- // discards the first cipher block, the IV component.
- byte[] buf = null;
- int limit = bb.limit();
- if (bb.hasArray()) {
- int arrayOffset = bb.arrayOffset();
- buf = bb.array();
- System.arraycopy(buf, arrayOffset + pos + blockSize,
- buf, arrayOffset + pos, limit - pos - blockSize);
- bb.limit(limit - blockSize);
- } else {
- buf = new byte[limit - pos - blockSize];
- bb.position(pos + blockSize);
- bb.get(buf);
- bb.position(pos);
- bb.put(buf);
- bb.limit(limit - blockSize);
- }
-
- // reset the position to the end of the decrypted data
- limit = bb.limit();
- bb.position(limit);
- }
- }
- return newLen;
- } catch (ShortBufferException e) {
- RuntimeException exc = new RuntimeException(e.toString());
- exc.initCause(e);
- throw exc;
- }
- }
-
- private static int addPadding(byte[] buf, int offset, int len,
- int blockSize) {
- int newlen = len + 1;
- byte pad;
- int i;
-
- if ((newlen % blockSize) != 0) {
- newlen += blockSize - 1;
- newlen -= newlen % blockSize;
- }
- pad = (byte) (newlen - len);
-
- if (buf.length < (newlen + offset)) {
- throw new IllegalArgumentException("no space to pad buffer");
- }
-
- /*
- * TLS version of the padding works for both SSLv3 and TLSv1
- */
- for (i = 0, offset += len; i < pad; i++) {
- buf [offset++] = (byte) (pad - 1);
- }
- return newlen;
- }
-
- /*
- * Apply the padding to the buffer.
- *
- * Limit is advanced to the new buffer length.
- * Position is equal to limit.
- */
- private static int addPadding(ByteBuffer bb, int blockSize) {
-
- int len = bb.remaining();
- int offset = bb.position();
-
- int newlen = len + 1;
- byte pad;
- int i;
-
- if ((newlen % blockSize) != 0) {
- newlen += blockSize - 1;
- newlen -= newlen % blockSize;
- }
- pad = (byte) (newlen - len);
-
- /*
- * Update the limit to what will be padded.
- */
- bb.limit(newlen + offset);
-
- /*
- * TLS version of the padding works for both SSLv3 and TLSv1
- */
- for (i = 0, offset += len; i < pad; i++) {
- bb.put(offset++, (byte) (pad - 1));
- }
-
- bb.position(offset);
- bb.limit(offset);
-
- return newlen;
- }
-
- /*
- * A constant-time check of the padding.
- *
- * NOTE that we are checking both the padding and the padLen bytes here.
- *
- * The caller MUST ensure that the len parameter is a positive number.
- */
- private static int[] checkPadding(
- byte[] buf, int offset, int len, byte pad) {
-
- if (len <= 0) {
- throw new RuntimeException("padding len must be positive");
- }
-
- // An array of hits is used to prevent Hotspot optimization for
- // the purpose of a constant-time check.
- int[] results = {0, 0}; // {missed #, matched #}
- for (int i = 0; i <= 256;) {
- for (int j = 0; j < len && i <= 256; j++, i++) { // j <= i
- if (buf[offset + j] != pad) {
- results[0]++; // mismatched padding data
- } else {
- results[1]++; // matched padding data
- }
- }
- }
-
- return results;
- }
-
- /*
- * A constant-time check of the padding.
- *
- * NOTE that we are checking both the padding and the padLen bytes here.
- *
- * The caller MUST ensure that the bb parameter has remaining.
- */
- private static int[] checkPadding(ByteBuffer bb, byte pad) {
-
- if (!bb.hasRemaining()) {
- throw new RuntimeException("hasRemaining() must be positive");
- }
-
- // An array of hits is used to prevent Hotspot optimization for
- // the purpose of a constant-time check.
- int[] results = {0, 0}; // {missed #, matched #}
- bb.mark();
- for (int i = 0; i <= 256; bb.reset()) {
- for (; bb.hasRemaining() && i <= 256; i++) {
- if (bb.get() != pad) {
- results[0]++; // mismatched padding data
- } else {
- results[1]++; // matched padding data
- }
- }
- }
-
- return results;
- }
-
- /*
- * Typical TLS padding format for a 64 bit block cipher is as follows:
- * xx xx xx xx xx xx xx 00
- * xx xx xx xx xx xx 01 01
- * ...
- * xx 06 06 06 06 06 06 06
- * 07 07 07 07 07 07 07 07
- * TLS also allows any amount of padding from 1 and 256 bytes as long
- * as it makes the data a multiple of the block size
- */
- private static int removePadding(byte[] buf, int offset, int len,
- int tagLen, int blockSize,
- ProtocolVersion protocolVersion) throws BadPaddingException {
-
- // last byte is length byte (i.e. actual padding length - 1)
- int padOffset = offset + len - 1;
- int padLen = buf[padOffset] & 0xFF;
-
- int newLen = len - (padLen + 1);
- if ((newLen - tagLen) < 0) {
- // If the buffer is not long enough to contain the padding plus
- // a MAC tag, do a dummy constant-time padding check.
- //
- // Note that it is a dummy check, so we won't care about what is
- // the actual padding data.
- checkPadding(buf, offset, len, (byte)(padLen & 0xFF));
-
- throw new BadPaddingException("Invalid Padding length: " + padLen);
- }
-
- // The padding data should be filled with the padding length value.
- int[] results = checkPadding(buf, offset + newLen,
- padLen + 1, (byte)(padLen & 0xFF));
- if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
- if (results[0] != 0) { // padding data has invalid bytes
- throw new BadPaddingException("Invalid TLS padding data");
- }
- } else { // SSLv3
- // SSLv3 requires 0 <= length byte < block size
- // some implementations do 1 <= length byte <= block size,
- // so accept that as well
- // v3 does not require any particular value for the other bytes
- if (padLen > blockSize) {
- throw new BadPaddingException("Invalid SSLv3 padding");
- }
- }
- return newLen;
- }
-
- /*
- * Position/limit is equal the removed padding.
- */
- private static int removePadding(ByteBuffer bb,
- int tagLen, int blockSize,
- ProtocolVersion protocolVersion) throws BadPaddingException {
-
- int len = bb.remaining();
- int offset = bb.position();
-
- // last byte is length byte (i.e. actual padding length - 1)
- int padOffset = offset + len - 1;
- int padLen = bb.get(padOffset) & 0xFF;
-
- int newLen = len - (padLen + 1);
- if ((newLen - tagLen) < 0) {
- // If the buffer is not long enough to contain the padding plus
- // a MAC tag, do a dummy constant-time padding check.
- //
- // Note that it is a dummy check, so we won't care about what is
- // the actual padding data.
- checkPadding(bb.duplicate(), (byte)(padLen & 0xFF));
-
- throw new BadPaddingException("Invalid Padding length: " + padLen);
- }
-
- // The padding data should be filled with the padding length value.
- int[] results = checkPadding(
- (ByteBuffer)bb.duplicate().position(offset + newLen),
- (byte)(padLen & 0xFF));
- if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
- if (results[0] != 0) { // padding data has invalid bytes
- throw new BadPaddingException("Invalid TLS padding data");
- }
- } else { // SSLv3
- // SSLv3 requires 0 <= length byte < block size
- // some implementations do 1 <= length byte <= block size,
- // so accept that as well
- // v3 does not require any particular value for the other bytes
- if (padLen > blockSize) {
- throw new BadPaddingException("Invalid SSLv3 padding");
- }
- }
-
- /*
- * Reset buffer limit to remove padding.
- */
- bb.position(offset + newLen);
- bb.limit(offset + newLen);
-
- return newLen;
- }
-
- /*
- * Dispose of any intermediate state in the underlying cipher.
- * For PKCS11 ciphers, this will release any attached sessions, and
- * thus make finalization faster.
- */
- void dispose() {
- try {
- if (cipher != null) {
- // ignore return value.
- cipher.doFinal();
- }
- } catch (GeneralSecurityException e) {
- // swallow for now.
- }
- }
-
- /*
- * Does the cipher use CBC mode?
- *
- * @return true if the cipher use CBC mode, false otherwise.
- */
- boolean isCBCMode() {
- return isCBCMode;
- }
-
- /**
- * Is the cipher null?
- *
- * @return true if the cipher is null, false otherwise.
- */
- boolean isNullCipher() {
- return cipher == null;
- }
-
- /**
- * Sanity check the length of a fragment before decryption.
- *
- * In CBC mode, check that the fragment length is one or multiple times
- * of the block size of the cipher suite, and is at least one (one is the
- * smallest size of padding in CBC mode) bigger than the tag size of the
- * MAC algorithm except the explicit IV size for TLS 1.1 or later.
- *
- * In non-CBC mode, check that the fragment length is not less than the
- * tag size of the MAC algorithm.
- *
- * @return true if the length of a fragment matches above requirements
- */
- boolean sanityCheck(int tagLen, int fragmentLen) {
- if (!isCBCMode) {
- return fragmentLen >= tagLen;
- }
-
- if ((fragmentLen % blockSize) == 0) {
- int minimal = tagLen + 1;
- minimal = (minimal >= blockSize) ? minimal : blockSize;
- if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
- minimal += blockSize; // plus the size of the explicit IV
- }
-
- return (fragmentLen >= minimal);
- }
-
- return false;
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/CipherSuite.java b/ojluni/src/main/java/sun/security/ssl/CipherSuite.java
deleted file mode 100755
index 3bf67fa..0000000
--- a/ojluni/src/main/java/sun/security/ssl/CipherSuite.java
+++ /dev/null
@@ -1,1292 +0,0 @@
-/*
- * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.util.*;
-
-import java.security.NoSuchAlgorithmException;
-import java.security.InvalidKeyException;
-import java.security.SecureRandom;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import sun.security.ssl.CipherSuite.*;
-import static sun.security.ssl.CipherSuite.KeyExchange.*;
-import static sun.security.ssl.CipherSuite.PRF.*;
-import static sun.security.ssl.JsseJce.*;
-
-/**
- * An SSL/TLS CipherSuite. Constants for the standard key exchange, cipher,
- * and mac algorithms are also defined in this class.
- *
- * The CipherSuite class and the inner classes defined in this file roughly
- * follow the type safe enum pattern described in Effective Java. This means:
- *
- * . instances are immutable, classes are final
- *
- * . there is a unique instance of every value, i.e. there are never two
- * instances representing the same CipherSuite, etc. This means equality
- * tests can be performed using == instead of equals() (although that works
- * as well). [A minor exception are *unsupported* CipherSuites read from a
- * handshake message, but this is usually irrelevant]
- *
- * . instances are obtained using the static valueOf() factory methods.
- *
- * . properties are defined as final variables and made available as
- * package private variables without method accessors
- *
- * . if the member variable allowed is false, the given algorithm is either
- * unavailable or disabled at compile time
- *
- */
-final class CipherSuite implements Comparable {
-
- // minimum priority for supported CipherSuites
- final static int SUPPORTED_SUITES_PRIORITY = 1;
-
- // minimum priority for default enabled CipherSuites
- final static int DEFAULT_SUITES_PRIORITY = 300;
-
- // Flag indicating if CipherSuite availability can change dynamically.
- // This is the case when we rely on a JCE cipher implementation that
- // may not be available in the installed JCE providers.
- // It is true because we might not have an ECC implementation.
- final static boolean DYNAMIC_AVAILABILITY = true;
-
- private final static boolean ALLOW_ECC = Debug.getBooleanProperty
- ("com.sun.net.ssl.enableECC", true);
-
- // Map Integer(id) -> CipherSuite
- // contains all known CipherSuites
- private final static Map<Integer,CipherSuite> idMap;
-
- // Map String(name) -> CipherSuite
- // contains only supported CipherSuites (i.e. allowed == true)
- private final static Map<String,CipherSuite> nameMap;
-
- // Protocol defined CipherSuite name, e.g. SSL_RSA_WITH_RC4_128_MD5
- // we use TLS_* only for new CipherSuites, still SSL_* for old ones
- final String name;
-
- // id in 16 bit MSB format, i.e. 0x0004 for SSL_RSA_WITH_RC4_128_MD5
- final int id;
-
- // priority for the internal default preference order. the higher the
- // better. Each supported CipherSuite *must* have a unique priority.
- // Ciphersuites with priority >= DEFAULT_SUITES_PRIORITY are enabled
- // by default
- final int priority;
-
- // key exchange, bulk cipher, mac and prf algorithms. See those
- // classes below.
- final KeyExchange keyExchange;
- final BulkCipher cipher;
- final MacAlg macAlg;
- final PRF prfAlg;
-
- // whether a CipherSuite qualifies as exportable under 512/40 bit rules.
- // TLS 1.1+ (RFC 4346) must not negotiate to these suites.
- final boolean exportable;
-
- // true iff implemented and enabled at compile time
- final boolean allowed;
-
- // obsoleted since protocol version
- final int obsoleted;
-
- // supported since protocol version
- final int supported;
-
- /**
- * Constructor for implemented CipherSuites.
- */
- private CipherSuite(String name, int id, int priority,
- KeyExchange keyExchange, BulkCipher cipher,
- boolean allowed, int obsoleted, int supported, PRF prfAlg) {
- this.name = name;
- this.id = id;
- this.priority = priority;
- this.keyExchange = keyExchange;
- this.cipher = cipher;
- this.exportable = cipher.exportable;
- if (name.endsWith("_MD5")) {
- macAlg = M_MD5;
- } else if (name.endsWith("_SHA")) {
- macAlg = M_SHA;
- } else if (name.endsWith("_SHA256")) {
- macAlg = M_SHA256;
- } else if (name.endsWith("_SHA384")) {
- macAlg = M_SHA384;
- } else if (name.endsWith("_NULL")) {
- macAlg = M_NULL;
- } else if (name.endsWith("_SCSV")) {
- macAlg = M_NULL;
- } else {
- throw new IllegalArgumentException
- ("Unknown MAC algorithm for ciphersuite " + name);
- }
-
- allowed &= keyExchange.allowed;
- allowed &= cipher.allowed;
- this.allowed = allowed;
- this.obsoleted = obsoleted;
- this.supported = supported;
- this.prfAlg = prfAlg;
- }
-
- /**
- * Constructor for unimplemented CipherSuites.
- */
- private CipherSuite(String name, int id) {
- this.name = name;
- this.id = id;
- this.allowed = false;
-
- this.priority = 0;
- this.keyExchange = null;
- this.cipher = null;
- this.macAlg = null;
- this.exportable = false;
- this.obsoleted = ProtocolVersion.LIMIT_MAX_VALUE;
- this.supported = ProtocolVersion.LIMIT_MIN_VALUE;
- this.prfAlg = P_NONE;
- }
-
- /**
- * Return whether this CipherSuite is available for use. A
- * CipherSuite may be unavailable even if it is supported
- * (i.e. allowed == true) if the required JCE cipher is not installed.
- * In some configuration, this situation may change over time, call
- * CipherSuiteList.clearAvailableCache() before this method to obtain
- * the most current status.
- */
- boolean isAvailable() {
- return allowed && keyExchange.isAvailable() && cipher.isAvailable();
- }
-
- boolean isNegotiable() {
- return this != C_SCSV && isAvailable();
- }
-
- /**
- * Compares CipherSuites based on their priority. Has the effect of
- * sorting CipherSuites when put in a sorted collection, which is
- * used by CipherSuiteList. Follows standard Comparable contract.
- *
- * Note that for unsupported CipherSuites parsed from a handshake
- * message we violate the equals() contract.
- */
- public int compareTo(Object o) {
- return ((CipherSuite)o).priority - priority;
- }
-
- /**
- * Returns this.name.
- */
- public String toString() {
- return name;
- }
-
- /**
- * Return a CipherSuite for the given name. The returned CipherSuite
- * is supported by this implementation but may not actually be
- * currently useable. See isAvailable().
- *
- * @exception IllegalArgumentException if the CipherSuite is unknown or
- * unsupported.
- */
- static CipherSuite valueOf(String s) {
- if (s == null) {
- throw new IllegalArgumentException("Name must not be null");
- }
-
- CipherSuite c = nameMap.get(s);
- if ((c == null) || (c.allowed == false)) {
- throw new IllegalArgumentException("Unsupported ciphersuite " + s);
- }
-
- return c;
- }
-
- /**
- * Return a CipherSuite with the given ID. A temporary object is
- * constructed if the ID is unknown. Use isAvailable() to verify that
- * the CipherSuite can actually be used.
- */
- static CipherSuite valueOf(int id1, int id2) {
- id1 &= 0xff;
- id2 &= 0xff;
- int id = (id1 << 8) | id2;
- CipherSuite c = idMap.get(id);
- if (c == null) {
- String h1 = Integer.toString(id1, 16);
- String h2 = Integer.toString(id2, 16);
- c = new CipherSuite("Unknown 0x" + h1 + ":0x" + h2, id);
- }
- return c;
- }
-
- // for use by CipherSuiteList only
- static Collection<CipherSuite> allowedCipherSuites() {
- return nameMap.values();
- }
-
- /*
- * Use this method when all of the values need to be specified.
- * This is primarily used when defining a new ciphersuite for
- * TLS 1.2+ that doesn't use the "default" PRF.
- */
- private static void add(String name, int id, int priority,
- KeyExchange keyExchange, BulkCipher cipher,
- boolean allowed, int obsoleted, int supported, PRF prf) {
-
- CipherSuite c = new CipherSuite(name, id, priority, keyExchange,
- cipher, allowed, obsoleted, supported, prf);
- if (idMap.put(id, c) != null) {
- throw new RuntimeException("Duplicate ciphersuite definition: "
- + id + ", " + name);
- }
- if (c.allowed) {
- if (nameMap.put(name, c) != null) {
- throw new RuntimeException("Duplicate ciphersuite definition: "
- + id + ", " + name);
- }
- }
- }
-
- /*
- * Use this method when there is no lower protocol limit where this
- * suite can be used, and the PRF is P_SHA256. That is, the
- * existing ciphersuites. From RFC 5246:
- *
- * All cipher suites in this document use P_SHA256.
- */
- private static void add(String name, int id, int priority,
- KeyExchange keyExchange, BulkCipher cipher,
- boolean allowed, int obsoleted) {
- // If this is an obsoleted suite, then don't let the TLS 1.2
- // protocol have a valid PRF value.
- PRF prf = P_SHA256;
- if (obsoleted < ProtocolVersion.TLS12.v) {
- prf = P_NONE;
- }
-
- add(name, id, priority, keyExchange, cipher, allowed, obsoleted,
- ProtocolVersion.LIMIT_MIN_VALUE, prf);
- }
-
- /*
- * Use this method when there is no upper protocol limit. That is,
- * suites which have not been obsoleted.
- */
- private static void add(String name, int id, int priority,
- KeyExchange keyExchange, BulkCipher cipher, boolean allowed) {
- add(name, id, priority, keyExchange,
- cipher, allowed, ProtocolVersion.LIMIT_MAX_VALUE);
- }
-
- /*
- * Use this method to define an unimplemented suite. This provides
- * a number<->name mapping that can be used for debugging.
- */
- private static void add(String name, int id) {
- CipherSuite c = new CipherSuite(name, id);
- if (idMap.put(id, c) != null) {
- throw new RuntimeException("Duplicate ciphersuite definition: "
- + id + ", " + name);
- }
- }
-
- /**
- * An SSL/TLS key exchange algorithm.
- */
- static enum KeyExchange {
-
- // key exchange algorithms
- K_NULL ("NULL", false),
- K_RSA ("RSA", true),
- K_RSA_EXPORT ("RSA_EXPORT", true),
- K_DH_RSA ("DH_RSA", false),
- K_DH_DSS ("DH_DSS", false),
- K_DHE_DSS ("DHE_DSS", true),
- K_DHE_RSA ("DHE_RSA", true),
- K_DH_ANON ("DH_anon", true),
-
- K_ECDH_ECDSA ("ECDH_ECDSA", ALLOW_ECC),
- K_ECDH_RSA ("ECDH_RSA", ALLOW_ECC),
- K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC),
- K_ECDHE_RSA ("ECDHE_RSA", ALLOW_ECC),
- K_ECDH_ANON ("ECDH_anon", ALLOW_ECC),
-
- // Kerberos cipher suites
- K_KRB5 ("KRB5", true),
- K_KRB5_EXPORT("KRB5_EXPORT", true),
-
- // renegotiation protection request signaling cipher suite
- K_SCSV ("SCSV", true);
-
- // name of the key exchange algorithm, e.g. DHE_DSS
- final String name;
- final boolean allowed;
- private final boolean alwaysAvailable;
-
- KeyExchange(String name, boolean allowed) {
- this.name = name;
- this.allowed = allowed;
- this.alwaysAvailable = allowed &&
- (!name.startsWith("EC")) && (!name.startsWith("KRB"));
- }
-
- boolean isAvailable() {
- if (alwaysAvailable) {
- return true;
- }
-
- if (name.startsWith("EC")) {
- return (allowed && JsseJce.isEcAvailable());
- } else if (name.startsWith("KRB")) {
- return (allowed && JsseJce.isKerberosAvailable());
- } else {
- return allowed;
- }
- }
-
- public String toString() {
- return name;
- }
- }
-
- /**
- * An SSL/TLS bulk cipher algorithm. One instance per combination of
- * cipher and key length.
- *
- * Also contains a factory method to obtain in initialized CipherBox
- * for this algorithm.
- */
- final static class BulkCipher {
-
- // Map BulkCipher -> Boolean(available)
- private final static Map<BulkCipher,Boolean> availableCache =
- new HashMap<>(8);
-
- // descriptive name including key size, e.g. AES/128
- final String description;
-
- // JCE cipher transformation string, e.g. AES/CBC/NoPadding
- final String transformation;
-
- // algorithm name, e.g. AES
- final String algorithm;
-
- // supported and compile time enabled. Also see isAvailable()
- final boolean allowed;
-
- // number of bytes of entropy in the key
- final int keySize;
-
- // length of the actual cipher key in bytes.
- // for non-exportable ciphers, this is the same as keySize
- final int expandedKeySize;
-
- // size of the IV (also block size)
- final int ivSize;
-
- // exportable under 512/40 bit rules
- final boolean exportable;
-
- // Is the cipher algorithm of Cipher Block Chaining (CBC) mode?
- final boolean isCBCMode;
-
- BulkCipher(String transformation, int keySize,
- int expandedKeySize, int ivSize, boolean allowed) {
- this.transformation = transformation;
- String[] splits = transformation.split("/");
- this.algorithm = splits[0];
- this.isCBCMode =
- splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]);
- this.description = this.algorithm + "/" + (keySize << 3);
- this.keySize = keySize;
- this.ivSize = ivSize;
- this.allowed = allowed;
-
- this.expandedKeySize = expandedKeySize;
- this.exportable = true;
- }
-
- BulkCipher(String transformation, int keySize,
- int ivSize, boolean allowed) {
- this.transformation = transformation;
- String[] splits = transformation.split("/");
- this.algorithm = splits[0];
- this.isCBCMode =
- splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]);
- this.description = this.algorithm + "/" + (keySize << 3);
- this.keySize = keySize;
- this.ivSize = ivSize;
- this.allowed = allowed;
-
- this.expandedKeySize = keySize;
- this.exportable = false;
- }
-
- /**
- * Return an initialized CipherBox for this BulkCipher.
- * IV must be null for stream ciphers.
- *
- * @exception NoSuchAlgorithmException if anything goes wrong
- */
- CipherBox newCipher(ProtocolVersion version, SecretKey key,
- IvParameterSpec iv, SecureRandom random,
- boolean encrypt) throws NoSuchAlgorithmException {
- return CipherBox.newCipherBox(version, this,
- key, iv, random, encrypt);
- }
-
- /**
- * Test if this bulk cipher is available. For use by CipherSuite.
- *
- * Currently all supported ciphers except AES are always available
- * via the JSSE internal implementations. We also assume AES/128
- * is always available since it is shipped with the SunJCE provider.
- * However, AES/256 is unavailable when the default JCE policy
- * jurisdiction files are installed because of key length restrictions.
- */
- boolean isAvailable() {
- if (allowed == false) {
- return false;
- }
- if (this == B_AES_256) {
- return isAvailable(this);
- }
-
- // always available
- return true;
- }
-
- // for use by CipherSuiteList.clearAvailableCache();
- static synchronized void clearAvailableCache() {
- if (DYNAMIC_AVAILABILITY) {
- availableCache.clear();
- }
- }
-
- private static synchronized boolean isAvailable(BulkCipher cipher) {
- Boolean b = availableCache.get(cipher);
- if (b == null) {
- try {
- SecretKey key = new SecretKeySpec
- (new byte[cipher.expandedKeySize], cipher.algorithm);
- IvParameterSpec iv =
- new IvParameterSpec(new byte[cipher.ivSize]);
- cipher.newCipher(ProtocolVersion.DEFAULT,
- key, iv, null, true);
- b = Boolean.TRUE;
- } catch (NoSuchAlgorithmException e) {
- b = Boolean.FALSE;
- }
- availableCache.put(cipher, b);
- }
- return b.booleanValue();
- }
-
- public String toString() {
- return description;
- }
- }
-
- /**
- * An SSL/TLS key MAC algorithm.
- *
- * Also contains a factory method to obtain an initialized MAC
- * for this algorithm.
- */
- final static class MacAlg {
-
- // descriptive name, e.g. MD5
- final String name;
-
- // size of the MAC value (and MAC key) in bytes
- final int size;
-
- // block size of the underlying hash algorithm
- final int hashBlockSize;
-
- // minimal padding size of the underlying hash algorithm
- final int minimalPaddingSize;
-
- MacAlg(String name, int size,
- int hashBlockSize, int minimalPaddingSize) {
- this.name = name;
- this.size = size;
- this.hashBlockSize = hashBlockSize;
- this.minimalPaddingSize = minimalPaddingSize;
- }
-
- /**
- * Return an initialized MAC for this MacAlg. ProtocolVersion
- * must either be SSL30 (SSLv3 custom MAC) or TLS10 (std. HMAC).
- *
- * @exception NoSuchAlgorithmException if anything goes wrong
- */
- MAC newMac(ProtocolVersion protocolVersion, SecretKey secret)
- throws NoSuchAlgorithmException, InvalidKeyException {
- return new MAC(this, protocolVersion, secret);
- }
-
- public String toString() {
- return name;
- }
- }
-
- // export strength ciphers
- final static BulkCipher B_NULL =
- new BulkCipher("NULL", 0, 0, 0, true);
- final static BulkCipher B_RC4_40 =
- new BulkCipher(CIPHER_RC4, 5, 16, 0, true);
- final static BulkCipher B_RC2_40 =
- new BulkCipher("RC2", 5, 16, 8, false);
- final static BulkCipher B_DES_40 =
- new BulkCipher(CIPHER_DES, 5, 8, 8, true);
-
- // domestic strength ciphers
- final static BulkCipher B_RC4_128 =
- new BulkCipher(CIPHER_RC4, 16, 0, true);
- final static BulkCipher B_DES =
- new BulkCipher(CIPHER_DES, 8, 8, true);
- final static BulkCipher B_3DES =
- new BulkCipher(CIPHER_3DES, 24, 8, true);
- final static BulkCipher B_IDEA =
- new BulkCipher("IDEA", 16, 8, false);
- final static BulkCipher B_AES_128 =
- new BulkCipher(CIPHER_AES, 16, 16, true);
- final static BulkCipher B_AES_256 =
- new BulkCipher(CIPHER_AES, 32, 16, true);
-
- // MACs
- final static MacAlg M_NULL = new MacAlg("NULL", 0, 0, 0);
- final static MacAlg M_MD5 = new MacAlg("MD5", 16, 64, 9);
- final static MacAlg M_SHA = new MacAlg("SHA", 20, 64, 9);
- final static MacAlg M_SHA256 = new MacAlg("SHA256", 32, 64, 9);
- final static MacAlg M_SHA384 = new MacAlg("SHA384", 48, 128, 17);
-
- /**
- * PRFs (PseudoRandom Function) from TLS specifications.
- *
- * TLS 1.1- uses a single MD5/SHA1-based PRF algorithm for generating
- * the necessary material.
- *
- * In TLS 1.2+, all existing/known CipherSuites use SHA256, however
- * new Ciphersuites (e.g. RFC 5288) can define specific PRF hash
- * algorithms.
- */
- static enum PRF {
-
- // PRF algorithms
- P_NONE( "NONE", 0, 0),
- P_SHA256("SHA-256", 32, 64),
- P_SHA384("SHA-384", 48, 128),
- P_SHA512("SHA-512", 64, 128); // not currently used.
-
- // PRF characteristics
- private final String prfHashAlg;
- private final int prfHashLength;
- private final int prfBlockSize;
-
- PRF(String prfHashAlg, int prfHashLength, int prfBlockSize) {
- this.prfHashAlg = prfHashAlg;
- this.prfHashLength = prfHashLength;
- this.prfBlockSize = prfBlockSize;
- }
-
- String getPRFHashAlg() {
- return prfHashAlg;
- }
-
- int getPRFHashLength() {
- return prfHashLength;
- }
-
- int getPRFBlockSize() {
- return prfBlockSize;
- }
- }
-
- static {
- idMap = new HashMap<Integer,CipherSuite>();
- nameMap = new HashMap<String,CipherSuite>();
-
- final boolean F = false;
- final boolean T = true;
- // N: ciphersuites only allowed if we are not in FIPS mode
- final boolean N = (SunJSSE.isFIPS() == false);
-
- /*
- * TLS Cipher Suite Registry, as of August 2010.
- *
- * http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
- *
- * Range Registration Procedures Notes
- * 000-191 Standards Action Refers to value of first byte
- * 192-254 Specification Required Refers to value of first byte
- * 255 Reserved for Private Use Refers to value of first byte
- *
- * Value Description Reference
- * 0x00,0x00 TLS_NULL_WITH_NULL_NULL [RFC5246]
- * 0x00,0x01 TLS_RSA_WITH_NULL_MD5 [RFC5246]
- * 0x00,0x02 TLS_RSA_WITH_NULL_SHA [RFC5246]
- * 0x00,0x03 TLS_RSA_EXPORT_WITH_RC4_40_MD5 [RFC4346]
- * 0x00,0x04 TLS_RSA_WITH_RC4_128_MD5 [RFC5246]
- * 0x00,0x05 TLS_RSA_WITH_RC4_128_SHA [RFC5246]
- * 0x00,0x06 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 [RFC4346]
- * 0x00,0x07 TLS_RSA_WITH_IDEA_CBC_SHA [RFC5469]
- * 0x00,0x08 TLS_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
- * 0x00,0x09 TLS_RSA_WITH_DES_CBC_SHA [RFC5469]
- * 0x00,0x0A TLS_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246]
- * 0x00,0x0B TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
- * 0x00,0x0C TLS_DH_DSS_WITH_DES_CBC_SHA [RFC5469]
- * 0x00,0x0D TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA [RFC5246]
- * 0x00,0x0E TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
- * 0x00,0x0F TLS_DH_RSA_WITH_DES_CBC_SHA [RFC5469]
- * 0x00,0x10 TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246]
- * 0x00,0x11 TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
- * 0x00,0x12 TLS_DHE_DSS_WITH_DES_CBC_SHA [RFC5469]
- * 0x00,0x13 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [RFC5246]
- * 0x00,0x14 TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
- * 0x00,0x15 TLS_DHE_RSA_WITH_DES_CBC_SHA [RFC5469]
- * 0x00,0x16 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246]
- * 0x00,0x17 TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 [RFC4346]
- * 0x00,0x18 TLS_DH_anon_WITH_RC4_128_MD5 [RFC5246]
- * 0x00,0x19 TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA [RFC4346]
- * 0x00,0x1A TLS_DH_anon_WITH_DES_CBC_SHA [RFC5469]
- * 0x00,0x1B TLS_DH_anon_WITH_3DES_EDE_CBC_SHA [RFC5246]
- * 0x00,0x1C-1D Reserved to avoid conflicts with SSLv3 [RFC5246]
- * 0x00,0x1E TLS_KRB5_WITH_DES_CBC_SHA [RFC2712]
- * 0x00,0x1F TLS_KRB5_WITH_3DES_EDE_CBC_SHA [RFC2712]
- * 0x00,0x20 TLS_KRB5_WITH_RC4_128_SHA [RFC2712]
- * 0x00,0x21 TLS_KRB5_WITH_IDEA_CBC_SHA [RFC2712]
- * 0x00,0x22 TLS_KRB5_WITH_DES_CBC_MD5 [RFC2712]
- * 0x00,0x23 TLS_KRB5_WITH_3DES_EDE_CBC_MD5 [RFC2712]
- * 0x00,0x24 TLS_KRB5_WITH_RC4_128_MD5 [RFC2712]
- * 0x00,0x25 TLS_KRB5_WITH_IDEA_CBC_MD5 [RFC2712]
- * 0x00,0x26 TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA [RFC2712]
- * 0x00,0x27 TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA [RFC2712]
- * 0x00,0x28 TLS_KRB5_EXPORT_WITH_RC4_40_SHA [RFC2712]
- * 0x00,0x29 TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 [RFC2712]
- * 0x00,0x2A TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 [RFC2712]
- * 0x00,0x2B TLS_KRB5_EXPORT_WITH_RC4_40_MD5 [RFC2712]
- * 0x00,0x2C TLS_PSK_WITH_NULL_SHA [RFC4785]
- * 0x00,0x2D TLS_DHE_PSK_WITH_NULL_SHA [RFC4785]
- * 0x00,0x2E TLS_RSA_PSK_WITH_NULL_SHA [RFC4785]
- * 0x00,0x2F TLS_RSA_WITH_AES_128_CBC_SHA [RFC5246]
- * 0x00,0x30 TLS_DH_DSS_WITH_AES_128_CBC_SHA [RFC5246]
- * 0x00,0x31 TLS_DH_RSA_WITH_AES_128_CBC_SHA [RFC5246]
- * 0x00,0x32 TLS_DHE_DSS_WITH_AES_128_CBC_SHA [RFC5246]
- * 0x00,0x33 TLS_DHE_RSA_WITH_AES_128_CBC_SHA [RFC5246]
- * 0x00,0x34 TLS_DH_anon_WITH_AES_128_CBC_SHA [RFC5246]
- * 0x00,0x35 TLS_RSA_WITH_AES_256_CBC_SHA [RFC5246]
- * 0x00,0x36 TLS_DH_DSS_WITH_AES_256_CBC_SHA [RFC5246]
- * 0x00,0x37 TLS_DH_RSA_WITH_AES_256_CBC_SHA [RFC5246]
- * 0x00,0x38 TLS_DHE_DSS_WITH_AES_256_CBC_SHA [RFC5246]
- * 0x00,0x39 TLS_DHE_RSA_WITH_AES_256_CBC_SHA [RFC5246]
- * 0x00,0x3A TLS_DH_anon_WITH_AES_256_CBC_SHA [RFC5246]
- * 0x00,0x3B TLS_RSA_WITH_NULL_SHA256 [RFC5246]
- * 0x00,0x3C TLS_RSA_WITH_AES_128_CBC_SHA256 [RFC5246]
- * 0x00,0x3D TLS_RSA_WITH_AES_256_CBC_SHA256 [RFC5246]
- * 0x00,0x3E TLS_DH_DSS_WITH_AES_128_CBC_SHA256 [RFC5246]
- * 0x00,0x3F TLS_DH_RSA_WITH_AES_128_CBC_SHA256 [RFC5246]
- * 0x00,0x40 TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 [RFC5246]
- * 0x00,0x41 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
- * 0x00,0x42 TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
- * 0x00,0x43 TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
- * 0x00,0x44 TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
- * 0x00,0x45 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
- * 0x00,0x46 TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA [RFC5932]
- * 0x00,0x47-4F Reserved to avoid conflicts with
- * deployed implementations [Pasi_Eronen]
- * 0x00,0x50-58 Reserved to avoid conflicts [Pasi Eronen]
- * 0x00,0x59-5C Reserved to avoid conflicts with
- * deployed implementations [Pasi_Eronen]
- * 0x00,0x5D-5F Unassigned
- * 0x00,0x60-66 Reserved to avoid conflicts with widely
- * deployed implementations [Pasi_Eronen]
- * 0x00,0x67 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 [RFC5246]
- * 0x00,0x68 TLS_DH_DSS_WITH_AES_256_CBC_SHA256 [RFC5246]
- * 0x00,0x69 TLS_DH_RSA_WITH_AES_256_CBC_SHA256 [RFC5246]
- * 0x00,0x6A TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 [RFC5246]
- * 0x00,0x6B TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 [RFC5246]
- * 0x00,0x6C TLS_DH_anon_WITH_AES_128_CBC_SHA256 [RFC5246]
- * 0x00,0x6D TLS_DH_anon_WITH_AES_256_CBC_SHA256 [RFC5246]
- * 0x00,0x6E-83 Unassigned
- * 0x00,0x84 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
- * 0x00,0x85 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
- * 0x00,0x86 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
- * 0x00,0x87 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
- * 0x00,0x88 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
- * 0x00,0x89 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA [RFC5932]
- * 0x00,0x8A TLS_PSK_WITH_RC4_128_SHA [RFC4279]
- * 0x00,0x8B TLS_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279]
- * 0x00,0x8C TLS_PSK_WITH_AES_128_CBC_SHA [RFC4279]
- * 0x00,0x8D TLS_PSK_WITH_AES_256_CBC_SHA [RFC4279]
- * 0x00,0x8E TLS_DHE_PSK_WITH_RC4_128_SHA [RFC4279]
- * 0x00,0x8F TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279]
- * 0x00,0x90 TLS_DHE_PSK_WITH_AES_128_CBC_SHA [RFC4279]
- * 0x00,0x91 TLS_DHE_PSK_WITH_AES_256_CBC_SHA [RFC4279]
- * 0x00,0x92 TLS_RSA_PSK_WITH_RC4_128_SHA [RFC4279]
- * 0x00,0x93 TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279]
- * 0x00,0x94 TLS_RSA_PSK_WITH_AES_128_CBC_SHA [RFC4279]
- * 0x00,0x95 TLS_RSA_PSK_WITH_AES_256_CBC_SHA [RFC4279]
- * 0x00,0x96 TLS_RSA_WITH_SEED_CBC_SHA [RFC4162]
- * 0x00,0x97 TLS_DH_DSS_WITH_SEED_CBC_SHA [RFC4162]
- * 0x00,0x98 TLS_DH_RSA_WITH_SEED_CBC_SHA [RFC4162]
- * 0x00,0x99 TLS_DHE_DSS_WITH_SEED_CBC_SHA [RFC4162]
- * 0x00,0x9A TLS_DHE_RSA_WITH_SEED_CBC_SHA [RFC4162]
- * 0x00,0x9B TLS_DH_anon_WITH_SEED_CBC_SHA [RFC4162]
- * 0x00,0x9C TLS_RSA_WITH_AES_128_GCM_SHA256 [RFC5288]
- * 0x00,0x9D TLS_RSA_WITH_AES_256_GCM_SHA384 [RFC5288]
- * 0x00,0x9E TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 [RFC5288]
- * 0x00,0x9F TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 [RFC5288]
- * 0x00,0xA0 TLS_DH_RSA_WITH_AES_128_GCM_SHA256 [RFC5288]
- * 0x00,0xA1 TLS_DH_RSA_WITH_AES_256_GCM_SHA384 [RFC5288]
- * 0x00,0xA2 TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 [RFC5288]
- * 0x00,0xA3 TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 [RFC5288]
- * 0x00,0xA4 TLS_DH_DSS_WITH_AES_128_GCM_SHA256 [RFC5288]
- * 0x00,0xA5 TLS_DH_DSS_WITH_AES_256_GCM_SHA384 [RFC5288]
- * 0x00,0xA6 TLS_DH_anon_WITH_AES_128_GCM_SHA256 [RFC5288]
- * 0x00,0xA7 TLS_DH_anon_WITH_AES_256_GCM_SHA384 [RFC5288]
- * 0x00,0xA8 TLS_PSK_WITH_AES_128_GCM_SHA256 [RFC5487]
- * 0x00,0xA9 TLS_PSK_WITH_AES_256_GCM_SHA384 [RFC5487]
- * 0x00,0xAA TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 [RFC5487]
- * 0x00,0xAB TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 [RFC5487]
- * 0x00,0xAC TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 [RFC5487]
- * 0x00,0xAD TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 [RFC5487]
- * 0x00,0xAE TLS_PSK_WITH_AES_128_CBC_SHA256 [RFC5487]
- * 0x00,0xAF TLS_PSK_WITH_AES_256_CBC_SHA384 [RFC5487]
- * 0x00,0xB0 TLS_PSK_WITH_NULL_SHA256 [RFC5487]
- * 0x00,0xB1 TLS_PSK_WITH_NULL_SHA384 [RFC5487]
- * 0x00,0xB2 TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 [RFC5487]
- * 0x00,0xB3 TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 [RFC5487]
- * 0x00,0xB4 TLS_DHE_PSK_WITH_NULL_SHA256 [RFC5487]
- * 0x00,0xB5 TLS_DHE_PSK_WITH_NULL_SHA384 [RFC5487]
- * 0x00,0xB6 TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 [RFC5487]
- * 0x00,0xB7 TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 [RFC5487]
- * 0x00,0xB8 TLS_RSA_PSK_WITH_NULL_SHA256 [RFC5487]
- * 0x00,0xB9 TLS_RSA_PSK_WITH_NULL_SHA384 [RFC5487]
- * 0x00,0xBA TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
- * 0x00,0xBB TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
- * 0x00,0xBC TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
- * 0x00,0xBD TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
- * 0x00,0xBE TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
- * 0x00,0xBF TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932]
- * 0x00,0xC0 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
- * 0x00,0xC1 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
- * 0x00,0xC2 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
- * 0x00,0xC3 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
- * 0x00,0xC4 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
- * 0x00,0xC5 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932]
- * 0x00,0xC6-FE Unassigned
- * 0x00,0xFF TLS_EMPTY_RENEGOTIATION_INFO_SCSV [RFC5746]
- * 0x01-BF,* Unassigned
- * 0xC0,0x01 TLS_ECDH_ECDSA_WITH_NULL_SHA [RFC4492]
- * 0xC0,0x02 TLS_ECDH_ECDSA_WITH_RC4_128_SHA [RFC4492]
- * 0xC0,0x03 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
- * 0xC0,0x04 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA [RFC4492]
- * 0xC0,0x05 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA [RFC4492]
- * 0xC0,0x06 TLS_ECDHE_ECDSA_WITH_NULL_SHA [RFC4492]
- * 0xC0,0x07 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA [RFC4492]
- * 0xC0,0x08 TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
- * 0xC0,0x09 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA [RFC4492]
- * 0xC0,0x0A TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA [RFC4492]
- * 0xC0,0x0B TLS_ECDH_RSA_WITH_NULL_SHA [RFC4492]
- * 0xC0,0x0C TLS_ECDH_RSA_WITH_RC4_128_SHA [RFC4492]
- * 0xC0,0x0D TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
- * 0xC0,0x0E TLS_ECDH_RSA_WITH_AES_128_CBC_SHA [RFC4492]
- * 0xC0,0x0F TLS_ECDH_RSA_WITH_AES_256_CBC_SHA [RFC4492]
- * 0xC0,0x10 TLS_ECDHE_RSA_WITH_NULL_SHA [RFC4492]
- * 0xC0,0x11 TLS_ECDHE_RSA_WITH_RC4_128_SHA [RFC4492]
- * 0xC0,0x12 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA [RFC4492]
- * 0xC0,0x13 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA [RFC4492]
- * 0xC0,0x14 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA [RFC4492]
- * 0xC0,0x15 TLS_ECDH_anon_WITH_NULL_SHA [RFC4492]
- * 0xC0,0x16 TLS_ECDH_anon_WITH_RC4_128_SHA [RFC4492]
- * 0xC0,0x17 TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA [RFC4492]
- * 0xC0,0x18 TLS_ECDH_anon_WITH_AES_128_CBC_SHA [RFC4492]
- * 0xC0,0x19 TLS_ECDH_anon_WITH_AES_256_CBC_SHA [RFC4492]
- * 0xC0,0x1A TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA [RFC5054]
- * 0xC0,0x1B TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA [RFC5054]
- * 0xC0,0x1C TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA [RFC5054]
- * 0xC0,0x1D TLS_SRP_SHA_WITH_AES_128_CBC_SHA [RFC5054]
- * 0xC0,0x1E TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA [RFC5054]
- * 0xC0,0x1F TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA [RFC5054]
- * 0xC0,0x20 TLS_SRP_SHA_WITH_AES_256_CBC_SHA [RFC5054]
- * 0xC0,0x21 TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA [RFC5054]
- * 0xC0,0x22 TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA [RFC5054]
- * 0xC0,0x23 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 [RFC5289]
- * 0xC0,0x24 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 [RFC5289]
- * 0xC0,0x25 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 [RFC5289]
- * 0xC0,0x26 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 [RFC5289]
- * 0xC0,0x27 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 [RFC5289]
- * 0xC0,0x28 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 [RFC5289]
- * 0xC0,0x29 TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 [RFC5289]
- * 0xC0,0x2A TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 [RFC5289]
- * 0xC0,0x2B TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 [RFC5289]
- * 0xC0,0x2C TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 [RFC5289]
- * 0xC0,0x2D TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 [RFC5289]
- * 0xC0,0x2E TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 [RFC5289]
- * 0xC0,0x2F TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [RFC5289]
- * 0xC0,0x30 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 [RFC5289]
- * 0xC0,0x31 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 [RFC5289]
- * 0xC0,0x32 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 [RFC5289]
- * 0xC0,0x33 TLS_ECDHE_PSK_WITH_RC4_128_SHA [RFC5489]
- * 0xC0,0x34 TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA [RFC5489]
- * 0xC0,0x35 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA [RFC5489]
- * 0xC0,0x36 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA [RFC5489]
- * 0xC0,0x37 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 [RFC5489]
- * 0xC0,0x38 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 [RFC5489]
- * 0xC0,0x39 TLS_ECDHE_PSK_WITH_NULL_SHA [RFC5489]
- * 0xC0,0x3A TLS_ECDHE_PSK_WITH_NULL_SHA256 [RFC5489]
- * 0xC0,0x3B TLS_ECDHE_PSK_WITH_NULL_SHA384 [RFC5489]
- * 0xC0,0x3C-FF Unassigned
- * 0xC1-FD,* Unassigned
- * 0xFE,0x00-FD Unassigned
- * 0xFE,0xFE-FF Reserved to avoid conflicts with widely
- * deployed implementations [Pasi_Eronen]
- * 0xFF,0x00-FF Reserved for Private Use [RFC5246]
- */
-
- add("SSL_NULL_WITH_NULL_NULL",
- 0x0000, 1, K_NULL, B_NULL, F);
-
- /*
- * Definition of the CipherSuites that are enabled by default.
- * They are listed in preference order, most preferred first, using
- * the following criteria:
- * 1. Prefer the stronger buld cipher, in the order of AES_256,
- * AES_128, RC-4, 3DES-EDE.
- * 2. Prefer the stronger MAC algorithm, in the order of SHA384,
- * SHA256, SHA, MD5.
- * 3. Prefer the better performance of key exchange and digital
- * signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA,
- * RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS.
- */
- int p = DEFAULT_SUITES_PRIORITY * 2;
-
- // shorten names to fit the following table cleanly.
- int max = ProtocolVersion.LIMIT_MAX_VALUE;
- int tls11 = ProtocolVersion.TLS11.v;
- int tls12 = ProtocolVersion.TLS12.v;
-
- // ID Key Exchange Cipher A obs suprt PRF
- // ====== ============ ========= = === ===== ========
- add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
- 0xc024, --p, K_ECDHE_ECDSA, B_AES_256, T, max, tls12, P_SHA384);
- add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
- 0xc028, --p, K_ECDHE_RSA, B_AES_256, T, max, tls12, P_SHA384);
- add("TLS_RSA_WITH_AES_256_CBC_SHA256",
- 0x003d, --p, K_RSA, B_AES_256, T, max, tls12, P_SHA256);
- add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
- 0xc026, --p, K_ECDH_ECDSA, B_AES_256, T, max, tls12, P_SHA384);
- add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
- 0xc02a, --p, K_ECDH_RSA, B_AES_256, T, max, tls12, P_SHA384);
- add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
- 0x006b, --p, K_DHE_RSA, B_AES_256, T, max, tls12, P_SHA256);
- add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
- 0x006a, --p, K_DHE_DSS, B_AES_256, T, max, tls12, P_SHA256);
-
- add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
- 0xC00A, --p, K_ECDHE_ECDSA, B_AES_256, T);
- add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
- 0xC014, --p, K_ECDHE_RSA, B_AES_256, T);
- add("TLS_RSA_WITH_AES_256_CBC_SHA",
- 0x0035, --p, K_RSA, B_AES_256, T);
- add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
- 0xC005, --p, K_ECDH_ECDSA, B_AES_256, T);
- add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
- 0xC00F, --p, K_ECDH_RSA, B_AES_256, T);
- add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
- 0x0039, --p, K_DHE_RSA, B_AES_256, T);
- add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
- 0x0038, --p, K_DHE_DSS, B_AES_256, T);
-
- add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
- 0xc023, --p, K_ECDHE_ECDSA, B_AES_128, T, max, tls12, P_SHA256);
- add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
- 0xc027, --p, K_ECDHE_RSA, B_AES_128, T, max, tls12, P_SHA256);
- add("TLS_RSA_WITH_AES_128_CBC_SHA256",
- 0x003c, --p, K_RSA, B_AES_128, T, max, tls12, P_SHA256);
- add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
- 0xc025, --p, K_ECDH_ECDSA, B_AES_128, T, max, tls12, P_SHA256);
- add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
- 0xc029, --p, K_ECDH_RSA, B_AES_128, T, max, tls12, P_SHA256);
- add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
- 0x0067, --p, K_DHE_RSA, B_AES_128, T, max, tls12, P_SHA256);
- add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
- 0x0040, --p, K_DHE_DSS, B_AES_128, T, max, tls12, P_SHA256);
-
- add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
- 0xC009, --p, K_ECDHE_ECDSA, B_AES_128, T);
- add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
- 0xC013, --p, K_ECDHE_RSA, B_AES_128, T);
- add("TLS_RSA_WITH_AES_128_CBC_SHA",
- 0x002f, --p, K_RSA, B_AES_128, T);
- add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
- 0xC004, --p, K_ECDH_ECDSA, B_AES_128, T);
- add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
- 0xC00E, --p, K_ECDH_RSA, B_AES_128, T);
- add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
- 0x0033, --p, K_DHE_RSA, B_AES_128, T);
- add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
- 0x0032, --p, K_DHE_DSS, B_AES_128, T);
-
- add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
- 0xC007, --p, K_ECDHE_ECDSA, B_RC4_128, N);
- add("TLS_ECDHE_RSA_WITH_RC4_128_SHA",
- 0xC011, --p, K_ECDHE_RSA, B_RC4_128, N);
- add("SSL_RSA_WITH_RC4_128_SHA",
- 0x0005, --p, K_RSA, B_RC4_128, N);
- add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
- 0xC002, --p, K_ECDH_ECDSA, B_RC4_128, N);
- add("TLS_ECDH_RSA_WITH_RC4_128_SHA",
- 0xC00C, --p, K_ECDH_RSA, B_RC4_128, N);
-
- add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
- 0xC008, --p, K_ECDHE_ECDSA, B_3DES, T);
- add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
- 0xC012, --p, K_ECDHE_RSA, B_3DES, T);
- add("SSL_RSA_WITH_3DES_EDE_CBC_SHA",
- 0x000a, --p, K_RSA, B_3DES, T);
- add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
- 0xC003, --p, K_ECDH_ECDSA, B_3DES, T);
- add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
- 0xC00D, --p, K_ECDH_RSA, B_3DES, T);
- add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
- 0x0016, --p, K_DHE_RSA, B_3DES, T);
- add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
- 0x0013, --p, K_DHE_DSS, B_3DES, N);
-
- add("SSL_RSA_WITH_RC4_128_MD5",
- 0x0004, --p, K_RSA, B_RC4_128, N);
-
- // Renegotiation protection request Signalling Cipher Suite Value (SCSV)
- add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
- 0x00ff, --p, K_SCSV, B_NULL, T);
-
- /*
- * Definition of the CipherSuites that are supported but not enabled
- * by default.
- * They are listed in preference order, preferred first, using the
- * following criteria:
- * 1. CipherSuites for KRB5 need additional KRB5 service
- * configuration, and these suites are not common in practice,
- * so we put KRB5 based cipher suites at the end of the supported
- * list.
- * 2. If a cipher suite has been obsoleted, we put it at the end of
- * the list.
- * 3. Prefer the stronger bulk cipher, in the order of AES_256,
- * AES_128, RC-4, 3DES-EDE, DES, RC4_40, DES40, NULL.
- * 4. Prefer the stronger MAC algorithm, in the order of SHA384,
- * SHA256, SHA, MD5.
- * 5. Prefer the better performance of key exchange and digital
- * signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA,
- * RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS, anonymous.
- */
- p = DEFAULT_SUITES_PRIORITY;
-
- add("TLS_DH_anon_WITH_AES_256_CBC_SHA256",
- 0x006d, --p, K_DH_ANON, B_AES_256, N, max, tls12, P_SHA256);
- add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
- 0xC019, --p, K_ECDH_ANON, B_AES_256, T);
- add("TLS_DH_anon_WITH_AES_256_CBC_SHA",
- 0x003a, --p, K_DH_ANON, B_AES_256, N);
-
- add("TLS_DH_anon_WITH_AES_128_CBC_SHA256",
- 0x006c, --p, K_DH_ANON, B_AES_128, N, max, tls12, P_SHA256);
- add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
- 0xC018, --p, K_ECDH_ANON, B_AES_128, T);
- add("TLS_DH_anon_WITH_AES_128_CBC_SHA",
- 0x0034, --p, K_DH_ANON, B_AES_128, N);
-
- add("TLS_ECDH_anon_WITH_RC4_128_SHA",
- 0xC016, --p, K_ECDH_ANON, B_RC4_128, N);
- add("SSL_DH_anon_WITH_RC4_128_MD5",
- 0x0018, --p, K_DH_ANON, B_RC4_128, N);
-
- add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
- 0xC017, --p, K_ECDH_ANON, B_3DES, T);
- add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
- 0x001b, --p, K_DH_ANON, B_3DES, N);
-
- add("TLS_RSA_WITH_NULL_SHA256",
- 0x003b, --p, K_RSA, B_NULL, N, max, tls12, P_SHA256);
- add("TLS_ECDHE_ECDSA_WITH_NULL_SHA",
- 0xC006, --p, K_ECDHE_ECDSA, B_NULL, N);
- add("TLS_ECDHE_RSA_WITH_NULL_SHA",
- 0xC010, --p, K_ECDHE_RSA, B_NULL, N);
- add("SSL_RSA_WITH_NULL_SHA",
- 0x0002, --p, K_RSA, B_NULL, N);
- add("TLS_ECDH_ECDSA_WITH_NULL_SHA",
- 0xC001, --p, K_ECDH_ECDSA, B_NULL, N);
- add("TLS_ECDH_RSA_WITH_NULL_SHA",
- 0xC00B, --p, K_ECDH_RSA, B_NULL, N);
- add("TLS_ECDH_anon_WITH_NULL_SHA",
- 0xC015, --p, K_ECDH_ANON, B_NULL, N);
- add("SSL_RSA_WITH_NULL_MD5",
- 0x0001, --p, K_RSA, B_NULL, N);
-
- // weak cipher suites obsoleted in TLS 1.2
- add("SSL_RSA_WITH_DES_CBC_SHA",
- 0x0009, --p, K_RSA, B_DES, N, tls12);
- add("SSL_DHE_RSA_WITH_DES_CBC_SHA",
- 0x0015, --p, K_DHE_RSA, B_DES, N, tls12);
- add("SSL_DHE_DSS_WITH_DES_CBC_SHA",
- 0x0012, --p, K_DHE_DSS, B_DES, N, tls12);
- add("SSL_DH_anon_WITH_DES_CBC_SHA",
- 0x001a, --p, K_DH_ANON, B_DES, N, tls12);
-
- // weak cipher suites obsoleted in TLS 1.1
- add("SSL_RSA_EXPORT_WITH_RC4_40_MD5",
- 0x0003, --p, K_RSA_EXPORT, B_RC4_40, N, tls11);
- add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
- 0x0017, --p, K_DH_ANON, B_RC4_40, N, tls11);
-
- add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
- 0x0008, --p, K_RSA_EXPORT, B_DES_40, N, tls11);
- add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
- 0x0014, --p, K_DHE_RSA, B_DES_40, N, tls11);
- add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
- 0x0011, --p, K_DHE_DSS, B_DES_40, N, tls11);
- add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
- 0x0019, --p, K_DH_ANON, B_DES_40, N, tls11);
-
- // Supported Kerberos ciphersuites from RFC2712
- add("TLS_KRB5_WITH_RC4_128_SHA",
- 0x0020, --p, K_KRB5, B_RC4_128, N);
- add("TLS_KRB5_WITH_RC4_128_MD5",
- 0x0024, --p, K_KRB5, B_RC4_128, N);
- add("TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
- 0x001f, --p, K_KRB5, B_3DES, N);
- add("TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
- 0x0023, --p, K_KRB5, B_3DES, N);
- add("TLS_KRB5_WITH_DES_CBC_SHA",
- 0x001e, --p, K_KRB5, B_DES, N, tls12);
- add("TLS_KRB5_WITH_DES_CBC_MD5",
- 0x0022, --p, K_KRB5, B_DES, N, tls12);
- add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
- 0x0028, --p, K_KRB5_EXPORT, B_RC4_40, N, tls11);
- add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
- 0x002b, --p, K_KRB5_EXPORT, B_RC4_40, N, tls11);
- add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
- 0x0026, --p, K_KRB5_EXPORT, B_DES_40, N, tls11);
- add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
- 0x0029, --p, K_KRB5_EXPORT, B_DES_40, N, tls11);
-
- /*
- * Other values from the TLS Cipher Suite Registry, as of August 2010.
- *
- * http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
- *
- * Range Registration Procedures Notes
- * 000-191 Standards Action Refers to value of first byte
- * 192-254 Specification Required Refers to value of first byte
- * 255 Reserved for Private Use Refers to value of first byte
- */
-
- // Register the names of a few additional CipherSuites.
- // Makes them show up as names instead of numbers in
- // the debug output.
-
- // remaining unsupported ciphersuites defined in RFC2246.
- add("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x0006);
- add("SSL_RSA_WITH_IDEA_CBC_SHA", 0x0007);
- add("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x000b);
- add("SSL_DH_DSS_WITH_DES_CBC_SHA", 0x000c);
- add("SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x000d);
- add("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x000e);
- add("SSL_DH_RSA_WITH_DES_CBC_SHA", 0x000f);
- add("SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x0010);
-
- // SSL 3.0 Fortezza ciphersuites
- add("SSL_FORTEZZA_DMS_WITH_NULL_SHA", 0x001c);
- add("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", 0x001d);
-
- // 1024/56 bit exportable ciphersuites from expired internet draft
- add("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA", 0x0062);
- add("SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA", 0x0063);
- add("SSL_RSA_EXPORT1024_WITH_RC4_56_SHA", 0x0064);
- add("SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA", 0x0065);
- add("SSL_DHE_DSS_WITH_RC4_128_SHA", 0x0066);
-
- // Netscape old and new SSL 3.0 FIPS ciphersuites
- // see http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html
- add("NETSCAPE_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", 0xffe0);
- add("NETSCAPE_RSA_FIPS_WITH_DES_CBC_SHA", 0xffe1);
- add("SSL_RSA_FIPS_WITH_DES_CBC_SHA", 0xfefe);
- add("SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", 0xfeff);
-
- // Unsupported Kerberos cipher suites from RFC 2712
- add("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x0021);
- add("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x0025);
- add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027);
- add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a);
-
- // Unsupported cipher suites from RFC 4162
- add("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096);
- add("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097);
- add("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098);
- add("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099);
- add("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a);
- add("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b);
-
- // Unsupported cipher suites from RFC 4279
- add("TLS_PSK_WITH_RC4_128_SHA", 0x008a);
- add("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b);
- add("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c);
- add("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d);
- add("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e);
- add("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f);
- add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090);
- add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x0091);
- add("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x0092);
- add("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x0093);
- add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094);
- add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095);
-
- // Unsupported cipher suites from RFC 4785
- add("TLS_PSK_WITH_NULL_SHA", 0x002c);
- add("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d);
- add("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e);
-
- // Unsupported cipher suites from RFC 5246
- add("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030);
- add("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031);
- add("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036);
- add("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037);
- add("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e);
- add("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f);
- add("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068);
- add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069);
-
- // Unsupported cipher suites from RFC 5288
- add("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c);
- add("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d);
- add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e);
- add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f);
- add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0);
- add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1);
- add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2);
- add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3);
- add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4);
- add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5);
- add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6);
- add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7);
-
- // Unsupported cipher suites from RFC 5487
- add("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8);
- add("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9);
- add("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa);
- add("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0x00ab);
- add("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0x00ac);
- add("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0x00ad);
- add("TLS_PSK_WITH_AES_128_CBC_SHA256", 0x00ae);
- add("TLS_PSK_WITH_AES_256_CBC_SHA384", 0x00af);
- add("TLS_PSK_WITH_NULL_SHA256", 0x00b0);
- add("TLS_PSK_WITH_NULL_SHA384", 0x00b1);
- add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0x00b2);
- add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0x00b3);
- add("TLS_DHE_PSK_WITH_NULL_SHA256", 0x00b4);
- add("TLS_DHE_PSK_WITH_NULL_SHA384", 0x00b5);
- add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0x00b6);
- add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0x00b7);
- add("TLS_RSA_PSK_WITH_NULL_SHA256", 0x00b8);
- add("TLS_RSA_PSK_WITH_NULL_SHA384", 0x00b9);
-
- // Unsupported cipher suites from RFC 5932
- add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041);
- add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042);
- add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043);
- add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044);
- add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045);
- add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046);
- add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084);
- add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085);
- add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086);
- add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087);
- add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088);
- add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089);
- add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00ba);
- add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bb);
- add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00bc);
- add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bd);
- add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00be);
- add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 0x00bf);
- add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c0);
- add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c1);
- add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c2);
- add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c3);
- add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4);
- add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5);
-
- // Unsupported cipher suites from RFC 5054
- add("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a);
- add("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b);
- add("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c);
- add("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xc01d);
- add("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xc01e);
- add("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xc01f);
- add("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xc020);
- add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021);
- add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022);
-
- // Unsupported cipher suites from RFC 5289
- add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b);
- add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c);
- add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d);
- add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e);
- add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f);
- add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030);
- add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031);
- add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032);
-
- // Unsupported cipher suites from RFC 5489
- add("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033);
- add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034);
- add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035);
- add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036);
- add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037);
- add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038);
- add("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039);
- add("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xc03a);
- add("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xc03b);
- }
-
- // ciphersuite SSL_NULL_WITH_NULL_NULL
- final static CipherSuite C_NULL = CipherSuite.valueOf(0, 0);
-
- // ciphersuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV
- final static CipherSuite C_SCSV = CipherSuite.valueOf(0x00, 0xff);
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/CipherSuiteList.java b/ojluni/src/main/java/sun/security/ssl/CipherSuiteList.java
deleted file mode 100755
index bf69b35..0000000
--- a/ojluni/src/main/java/sun/security/ssl/CipherSuiteList.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.util.*;
-
-import javax.net.ssl.SSLException;
-
-/**
- * A list of CipherSuites. Also maintains the lists of supported and
- * default ciphersuites and supports I/O from handshake streams.
- *
- * Instances of this class are immutable.
- *
- */
-final class CipherSuiteList {
-
- private final Collection<CipherSuite> cipherSuites;
- private String[] suiteNames;
-
- // flag indicating whether this list contains any ECC ciphersuites.
- // null if not yet checked.
- private volatile Boolean containsEC;
-
- // for use by buildAvailableCache() and
- // Handshaker.getKickstartMessage() only
- CipherSuiteList(Collection<CipherSuite> cipherSuites) {
- this.cipherSuites = cipherSuites;
- }
-
- /**
- * Create a CipherSuiteList with a single element.
- */
- CipherSuiteList(CipherSuite suite) {
- cipherSuites = new ArrayList<CipherSuite>(1);
- cipherSuites.add(suite);
- }
-
- /**
- * Construct a CipherSuiteList from a array of names. We don't bother
- * to eliminate duplicates.
- *
- * @exception IllegalArgumentException if the array or any of its elements
- * is null or if the ciphersuite name is unrecognized or unsupported
- * using currently installed providers.
- */
- CipherSuiteList(String[] names) {
- if (names == null) {
- throw new IllegalArgumentException("CipherSuites may not be null");
- }
- cipherSuites = new ArrayList<CipherSuite>(names.length);
- // refresh available cache once if a CipherSuite is not available
- // (maybe new JCE providers have been installed)
- boolean refreshed = false;
- for (int i = 0; i < names.length; i++) {
- String suiteName = names[i];
- CipherSuite suite = CipherSuite.valueOf(suiteName);
- if (suite.isAvailable() == false) {
- if (refreshed == false) {
- // clear the cache so that the isAvailable() call below
- // does a full check
- clearAvailableCache();
- refreshed = true;
- }
- // still missing?
- if (suite.isAvailable() == false) {
- throw new IllegalArgumentException("Cannot support "
- + suiteName + " with currently installed providers");
- }
- }
- cipherSuites.add(suite);
- }
- }
-
- /**
- * Read a CipherSuiteList from a HandshakeInStream in V3 ClientHello
- * format. Does not check if the listed ciphersuites are known or
- * supported.
- */
- CipherSuiteList(HandshakeInStream in) throws IOException {
- byte[] bytes = in.getBytes16();
- if ((bytes.length & 1) != 0) {
- throw new SSLException("Invalid ClientHello message");
- }
- cipherSuites = new ArrayList<CipherSuite>(bytes.length >> 1);
- for (int i = 0; i < bytes.length; i += 2) {
- cipherSuites.add(CipherSuite.valueOf(bytes[i], bytes[i+1]));
- }
- }
-
- /**
- * Return whether this list contains the given CipherSuite.
- */
- boolean contains(CipherSuite suite) {
- return cipherSuites.contains(suite);
- }
-
- // Return whether this list contains any ECC ciphersuites
- boolean containsEC() {
- if (containsEC == null) {
- for (CipherSuite c : cipherSuites) {
- switch (c.keyExchange) {
- case K_ECDH_ECDSA:
- case K_ECDH_RSA:
- case K_ECDHE_ECDSA:
- case K_ECDHE_RSA:
- case K_ECDH_ANON:
- containsEC = true;
- return true;
- default:
- break;
- }
- }
- containsEC = false;
- }
- return containsEC;
- }
-
- /**
- * Return an Iterator for the CipherSuites in this list.
- */
- Iterator<CipherSuite> iterator() {
- return cipherSuites.iterator();
- }
-
- /**
- * Return a reference to the internal Collection of CipherSuites.
- * The Collection MUST NOT be modified.
- */
- Collection<CipherSuite> collection() {
- return cipherSuites;
- }
-
- /**
- * Return the number of CipherSuites in this list.
- */
- int size() {
- return cipherSuites.size();
- }
-
- /**
- * Return an array with the names of the CipherSuites in this list.
- */
- synchronized String[] toStringArray() {
- if (suiteNames == null) {
- suiteNames = new String[cipherSuites.size()];
- int i = 0;
- for (CipherSuite c : cipherSuites) {
- suiteNames[i++] = c.name;
- }
- }
- return suiteNames.clone();
- }
-
- public String toString() {
- return cipherSuites.toString();
- }
-
- /**
- * Write this list to an HandshakeOutStream in V3 ClientHello format.
- */
- void send(HandshakeOutStream s) throws IOException {
- byte[] suiteBytes = new byte[cipherSuites.size() * 2];
- int i = 0;
- for (CipherSuite c : cipherSuites) {
- suiteBytes[i] = (byte)(c.id >> 8);
- suiteBytes[i+1] = (byte)c.id;
- i += 2;
- }
- s.putBytes16(suiteBytes);
- }
-
- /**
- * Clear cache of available ciphersuites. If we support all ciphers
- * internally, there is no need to clear the cache and calling this
- * method has no effect.
- */
- static synchronized void clearAvailableCache() {
- if (CipherSuite.DYNAMIC_AVAILABILITY) {
- CipherSuite.BulkCipher.clearAvailableCache();
- JsseJce.clearEcAvailable();
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/ClientHandshaker.java b/ojluni/src/main/java/sun/security/ssl/ClientHandshaker.java
deleted file mode 100755
index 0c1022b..0000000
--- a/ojluni/src/main/java/sun/security/ssl/ClientHandshaker.java
+++ /dev/null
@@ -1,1345 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.math.BigInteger;
-import java.security.*;
-import java.util.*;
-
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.ECParameterSpec;
-
-import java.security.cert.X509Certificate;
-import java.security.cert.CertificateException;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import javax.net.ssl.*;
-
-import javax.security.auth.Subject;
-
-import sun.security.ssl.HandshakeMessage.*;
-import sun.security.ssl.CipherSuite.*;
-import static sun.security.ssl.CipherSuite.KeyExchange.*;
-
-import sun.net.util.IPAddressUtil;
-
-/**
- * ClientHandshaker does the protocol handshaking from the point
- * of view of a client. It is driven asychronously by handshake messages
- * as delivered by the parent Handshaker class, and also uses
- * common functionality (e.g. key generation) that is provided there.
- *
- * @author David Brownell
- */
-final class ClientHandshaker extends Handshaker {
-
- // the server's public key from its certificate.
- private PublicKey serverKey;
-
- // the server's ephemeral public key from the server key exchange message
- // for ECDHE/ECDH_anon and RSA_EXPORT.
- private PublicKey ephemeralServerKey;
-
- // server's ephemeral public value for DHE/DH_anon key exchanges
- private BigInteger serverDH;
-
- private DHCrypt dh;
-
- private ECDHCrypt ecdh;
-
- private CertificateRequest certRequest;
-
- private boolean serverKeyExchangeReceived;
-
- /*
- * The RSA PreMasterSecret needs to know the version of
- * ClientHello that was used on this handshake. This represents
- * the "max version" this client is supporting. In the
- * case of an initial handshake, it's the max version enabled,
- * but in the case of a resumption attempt, it's the version
- * of the session we're trying to resume.
- */
- private ProtocolVersion maxProtocolVersion;
-
- // To switch off the SNI extension.
- private final static boolean enableSNIExtension =
- Debug.getBooleanProperty("jsse.enableSNIExtension", true);
-
- /*
- * Constructors
- */
- ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context,
- ProtocolList enabledProtocols,
- ProtocolVersion activeProtocolVersion,
- boolean isInitialHandshake, boolean secureRenegotiation,
- byte[] clientVerifyData, byte[] serverVerifyData) {
-
- super(socket, context, enabledProtocols, true, true,
- activeProtocolVersion, isInitialHandshake, secureRenegotiation,
- clientVerifyData, serverVerifyData);
- }
-
- ClientHandshaker(SSLEngineImpl engine, SSLContextImpl context,
- ProtocolList enabledProtocols,
- ProtocolVersion activeProtocolVersion,
- boolean isInitialHandshake, boolean secureRenegotiation,
- byte[] clientVerifyData, byte[] serverVerifyData) {
-
- super(engine, context, enabledProtocols, true, true,
- activeProtocolVersion, isInitialHandshake, secureRenegotiation,
- clientVerifyData, serverVerifyData);
- }
-
- /*
- * This routine handles all the client side handshake messages, one at
- * a time. Given the message type (and in some cases the pending cipher
- * spec) it parses the type-specific message. Then it calls a function
- * that handles that specific message.
- *
- * It updates the state machine (need to verify it) as each message
- * is processed, and writes responses as needed using the connection
- * in the constructor.
- */
- void processMessage(byte type, int messageLen) throws IOException {
- if (state >= type
- && (type != HandshakeMessage.ht_hello_request)) {
- throw new SSLProtocolException(
- "Handshake message sequence violation, " + type);
- }
-
- switch (type) {
- case HandshakeMessage.ht_hello_request:
- this.serverHelloRequest(new HelloRequest(input));
- break;
-
- case HandshakeMessage.ht_server_hello:
- this.serverHello(new ServerHello(input, messageLen));
- break;
-
- case HandshakeMessage.ht_certificate:
- if (keyExchange == K_DH_ANON || keyExchange == K_ECDH_ANON
- || keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
- fatalSE(Alerts.alert_unexpected_message,
- "unexpected server cert chain");
- // NOTREACHED
- }
- this.serverCertificate(new CertificateMsg(input));
- serverKey =
- session.getPeerCertificates()[0].getPublicKey();
- break;
-
- case HandshakeMessage.ht_server_key_exchange:
- serverKeyExchangeReceived = true;
- switch (keyExchange) {
- case K_RSA_EXPORT:
- /**
- * The server key exchange message is sent by the server only
- * when the server certificate message does not contain the
- * proper amount of data to allow the client to exchange a
- * premaster secret, such as when RSA_EXPORT is used and the
- * public key in the server certificate is longer than 512 bits.
- */
- if (serverKey == null) {
- throw new SSLProtocolException
- ("Server did not send certificate message");
- }
-
- if (!(serverKey instanceof RSAPublicKey)) {
- throw new SSLProtocolException("Protocol violation:" +
- " the certificate type must be appropriate for the" +
- " selected cipher suite's key exchange algorithm");
- }
-
- if (JsseJce.getRSAKeyLength(serverKey) <= 512) {
- throw new SSLProtocolException("Protocol violation:" +
- " server sent a server key exchange message for" +
- " key exchange " + keyExchange +
- " when the public key in the server certificate" +
- " is less than or equal to 512 bits in length");
- }
-
- try {
- this.serverKeyExchange(new RSA_ServerKeyExchange(input));
- } catch (GeneralSecurityException e) {
- throwSSLException("Server key", e);
- }
- break;
- case K_DH_ANON:
- try {
- this.serverKeyExchange(new DH_ServerKeyExchange(
- input, protocolVersion));
- } catch (GeneralSecurityException e) {
- throwSSLException("Server key", e);
- }
- break;
- case K_DHE_DSS:
- case K_DHE_RSA:
- try {
- this.serverKeyExchange(new DH_ServerKeyExchange(
- input, serverKey,
- clnt_random.random_bytes, svr_random.random_bytes,
- messageLen,
- localSupportedSignAlgs, protocolVersion));
- } catch (GeneralSecurityException e) {
- throwSSLException("Server key", e);
- }
- break;
- case K_ECDHE_ECDSA:
- case K_ECDHE_RSA:
- case K_ECDH_ANON:
- try {
- this.serverKeyExchange(new ECDH_ServerKeyExchange
- (input, serverKey, clnt_random.random_bytes,
- svr_random.random_bytes,
- localSupportedSignAlgs, protocolVersion));
- } catch (GeneralSecurityException e) {
- throwSSLException("Server key", e);
- }
- break;
- case K_RSA:
- case K_DH_RSA:
- case K_DH_DSS:
- case K_ECDH_ECDSA:
- case K_ECDH_RSA:
- throw new SSLProtocolException(
- "Protocol violation: server sent a server key exchange"
- + "message for key exchange " + keyExchange);
- case K_KRB5:
- case K_KRB5_EXPORT:
- throw new SSLProtocolException(
- "unexpected receipt of server key exchange algorithm");
- default:
- throw new SSLProtocolException(
- "unsupported key exchange algorithm = "
- + keyExchange);
- }
- break;
-
- case HandshakeMessage.ht_certificate_request:
- // save for later, it's handled by serverHelloDone
- if ((keyExchange == K_DH_ANON) || (keyExchange == K_ECDH_ANON)) {
- throw new SSLHandshakeException(
- "Client authentication requested for "+
- "anonymous cipher suite.");
- } else if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
- throw new SSLHandshakeException(
- "Client certificate requested for "+
- "kerberos cipher suite.");
- }
- certRequest = new CertificateRequest(input, protocolVersion);
- if (debug != null && Debug.isOn("handshake")) {
- certRequest.print(System.out);
- }
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- Collection<SignatureAndHashAlgorithm> peerSignAlgs =
- certRequest.getSignAlgorithms();
- if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
- throw new SSLHandshakeException(
- "No peer supported signature algorithms");
- }
-
- Collection<SignatureAndHashAlgorithm> supportedPeerSignAlgs =
- SignatureAndHashAlgorithm.getSupportedAlgorithms(
- peerSignAlgs);
- if (supportedPeerSignAlgs.isEmpty()) {
- throw new SSLHandshakeException(
- "No supported signature and hash algorithm in common");
- }
-
- setPeerSupportedSignAlgs(supportedPeerSignAlgs);
- session.setPeerSupportedSignatureAlgorithms(
- supportedPeerSignAlgs);
- }
-
- break;
-
- case HandshakeMessage.ht_server_hello_done:
- this.serverHelloDone(new ServerHelloDone(input));
- break;
-
- case HandshakeMessage.ht_finished:
- this.serverFinished(
- new Finished(protocolVersion, input, cipherSuite));
- break;
-
- default:
- throw new SSLProtocolException(
- "Illegal client handshake msg, " + type);
- }
-
- //
- // Move state machine forward if the message handling
- // code didn't already do so
- //
- if (state < type) {
- state = type;
- }
- }
-
- /*
- * Used by the server to kickstart negotiations -- this requests a
- * "client hello" to renegotiate current cipher specs (e.g. maybe lots
- * of data has been encrypted with the same keys, or the server needs
- * the client to present a certificate).
- */
- private void serverHelloRequest(HelloRequest mesg) throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- //
- // Could be (e.g. at connection setup) that we already
- // sent the "client hello" but the server's not seen it.
- //
- if (state < HandshakeMessage.ht_client_hello) {
- if (!secureRenegotiation && !allowUnsafeRenegotiation) {
- // renegotiation is not allowed.
- if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
- // response with a no_renegotiation warning,
- warningSE(Alerts.alert_no_renegotiation);
-
- // invalidate the handshake so that the caller can
- // dispose this object.
- invalidated = true;
-
- // If there is still unread block in the handshake
- // input stream, it would be truncated with the disposal
- // and the next handshake message will become incomplete.
- //
- // However, according to SSL/TLS specifications, no more
- // handshake message should immediately follow ClientHello
- // or HelloRequest. So just let it be.
- } else {
- // For SSLv3, send the handshake_failure fatal error.
- // Note that SSLv3 does not define a no_renegotiation
- // alert like TLSv1. However we cannot ignore the message
- // simply, otherwise the other side was waiting for a
- // response that would never come.
- fatalSE(Alerts.alert_handshake_failure,
- "Renegotiation is not allowed");
- }
- } else {
- if (!secureRenegotiation) {
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "Warning: continue with insecure renegotiation");
- }
- }
- kickstart();
- }
- }
- }
-
-
- /*
- * Server chooses session parameters given options created by the
- * client -- basically, cipher options, session id, and someday a
- * set of compression options.
- *
- * There are two branches of the state machine, decided by the
- * details of this message. One is the "fast" handshake, where we
- * can resume the pre-existing session we asked resume. The other
- * is a more expensive "full" handshake, with key exchange and
- * probably authentication getting done.
- */
- private void serverHello(ServerHello mesg) throws IOException {
- serverKeyExchangeReceived = false;
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- // check if the server selected protocol version is OK for us
- ProtocolVersion mesgVersion = mesg.protocolVersion;
- if (!isNegotiable(mesgVersion)) {
- throw new SSLHandshakeException(
- "Server chose " + mesgVersion +
- ", but that protocol version is not enabled or not supported " +
- "by the client.");
- }
-
- handshakeHash.protocolDetermined(mesgVersion);
-
- // Set protocolVersion and propagate to SSLSocket and the
- // Handshake streams
- setVersion(mesgVersion);
-
- // check the "renegotiation_info" extension
- RenegotiationInfoExtension serverHelloRI = (RenegotiationInfoExtension)
- mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO);
- if (serverHelloRI != null) {
- if (isInitialHandshake) {
- // verify the length of the "renegotiated_connection" field
- if (!serverHelloRI.isEmpty()) {
- // abort the handshake with a fatal handshake_failure alert
- fatalSE(Alerts.alert_handshake_failure,
- "The renegotiation_info field is not empty");
- }
-
- secureRenegotiation = true;
- } else {
- // For a legacy renegotiation, the client MUST verify that
- // it does not contain the "renegotiation_info" extension.
- if (!secureRenegotiation) {
- fatalSE(Alerts.alert_handshake_failure,
- "Unexpected renegotiation indication extension");
- }
-
- // verify the client_verify_data and server_verify_data values
- byte[] verifyData =
- new byte[clientVerifyData.length + serverVerifyData.length];
- System.arraycopy(clientVerifyData, 0, verifyData,
- 0, clientVerifyData.length);
- System.arraycopy(serverVerifyData, 0, verifyData,
- clientVerifyData.length, serverVerifyData.length);
- if (!Arrays.equals(verifyData,
- serverHelloRI.getRenegotiatedConnection())) {
- fatalSE(Alerts.alert_handshake_failure,
- "Incorrect verify data in ServerHello " +
- "renegotiation_info message");
- }
- }
- } else {
- // no renegotiation indication extension
- if (isInitialHandshake) {
- if (!allowLegacyHelloMessages) {
- // abort the handshake with a fatal handshake_failure alert
- fatalSE(Alerts.alert_handshake_failure,
- "Failed to negotiate the use of secure renegotiation");
- }
-
- secureRenegotiation = false;
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("Warning: No renegotiation " +
- "indication extension in ServerHello");
- }
- } else {
- // For a secure renegotiation, the client must abort the
- // handshake if no "renegotiation_info" extension is present.
- if (secureRenegotiation) {
- fatalSE(Alerts.alert_handshake_failure,
- "No renegotiation indication extension");
- }
-
- // we have already allowed unsafe renegotation before request
- // the renegotiation.
- }
- }
-
- //
- // Save server nonce, we always use it to compute connection
- // keys and it's also used to create the master secret if we're
- // creating a new session (i.e. in the full handshake).
- //
- svr_random = mesg.svr_random;
-
- if (isNegotiable(mesg.cipherSuite) == false) {
- fatalSE(Alerts.alert_illegal_parameter,
- "Server selected improper ciphersuite " + mesg.cipherSuite);
- }
-
- setCipherSuite(mesg.cipherSuite);
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
- }
-
- if (mesg.compression_method != 0) {
- fatalSE(Alerts.alert_illegal_parameter,
- "compression type not supported, "
- + mesg.compression_method);
- // NOTREACHED
- }
-
- // so far so good, let's look at the session
- if (session != null) {
- // we tried to resume, let's see what the server decided
- if (session.getSessionId().equals(mesg.sessionId)) {
- // server resumed the session, let's make sure everything
- // checks out
-
- // Verify that the session ciphers are unchanged.
- CipherSuite sessionSuite = session.getSuite();
- if (cipherSuite != sessionSuite) {
- throw new SSLProtocolException
- ("Server returned wrong cipher suite for session");
- }
-
- // verify protocol version match
- ProtocolVersion sessionVersion = session.getProtocolVersion();
- if (protocolVersion != sessionVersion) {
- throw new SSLProtocolException
- ("Server resumed session with wrong protocol version");
- }
-
- // validate subject identity
- if (sessionSuite.keyExchange == K_KRB5 ||
- sessionSuite.keyExchange == K_KRB5_EXPORT) {
- Principal localPrincipal = session.getLocalPrincipal();
-
- Subject subject = null;
- try {
- subject = AccessController.doPrivileged(
- new PrivilegedExceptionAction<Subject>() {
- public Subject run() throws Exception {
- return Krb5Helper.getClientSubject(getAccSE());
- }});
- } catch (PrivilegedActionException e) {
- subject = null;
- if (debug != null && Debug.isOn("session")) {
- System.out.println("Attempt to obtain" +
- " subject failed!");
- }
- }
-
- if (subject != null) {
- // Eliminate dependency on KerberosPrincipal
- Set<Principal> principals =
- subject.getPrincipals(Principal.class);
- if (!principals.contains(localPrincipal)) {
- throw new SSLProtocolException("Server resumed" +
- " session with wrong subject identity");
- } else {
- if (debug != null && Debug.isOn("session"))
- System.out.println("Subject identity is same");
- }
- } else {
- if (debug != null && Debug.isOn("session"))
- System.out.println("Kerberos credentials are not" +
- " present in the current Subject; check if " +
- " javax.security.auth.useSubjectAsCreds" +
- " system property has been set to false");
- throw new SSLProtocolException
- ("Server resumed session with no subject");
- }
- }
-
- // looks fine; resume it, and update the state machine.
- resumingSession = true;
- state = HandshakeMessage.ht_finished - 1;
- calculateConnectionKeys(session.getMasterSecret());
- if (debug != null && Debug.isOn("session")) {
- System.out.println("%% Server resumed " + session);
- }
- } else {
- // we wanted to resume, but the server refused
- session = null;
- if (!enableNewSession) {
- throw new SSLException
- ("New session creation is disabled");
- }
- }
- }
-
- if (resumingSession && session != null) {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- handshakeHash.setCertificateVerifyAlg(null);
- }
-
- setHandshakeSessionSE(session);
- return;
- }
-
- // check extensions
- for (HelloExtension ext : mesg.extensions.list()) {
- ExtensionType type = ext.type;
- if ((type != ExtensionType.EXT_ELLIPTIC_CURVES)
- && (type != ExtensionType.EXT_EC_POINT_FORMATS)
- && (type != ExtensionType.EXT_SERVER_NAME)
- && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) {
- fatalSE(Alerts.alert_unsupported_extension,
- "Server sent an unsupported extension: " + type);
- }
- }
-
- // Create a new session, we need to do the full handshake
- session = new SSLSessionImpl(protocolVersion, cipherSuite,
- getLocalSupportedSignAlgs(),
- mesg.sessionId, getHostSE(), getPortSE());
- setHandshakeSessionSE(session);
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("** " + cipherSuite);
- }
- }
-
- /*
- * Server's own key was either a signing-only key, or was too
- * large for export rules ... this message holds an ephemeral
- * RSA key to use for key exchange.
- */
- private void serverKeyExchange(RSA_ServerKeyExchange mesg)
- throws IOException, GeneralSecurityException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- if (!mesg.verify(serverKey, clnt_random, svr_random)) {
- fatalSE(Alerts.alert_handshake_failure,
- "server key exchange invalid");
- // NOTREACHED
- }
- ephemeralServerKey = mesg.getPublicKey();
- }
-
-
- /*
- * Diffie-Hellman key exchange. We save the server public key and
- * our own D-H algorithm object so we can defer key calculations
- * until after we've sent the client key exchange message (which
- * gives client and server some useful parallelism).
- */
- private void serverKeyExchange(DH_ServerKeyExchange mesg)
- throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- dh = new DHCrypt(mesg.getModulus(), mesg.getBase(),
- sslContext.getSecureRandom());
- serverDH = mesg.getServerPublicKey();
- }
-
- private void serverKeyExchange(ECDH_ServerKeyExchange mesg)
- throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- ECPublicKey key = mesg.getPublicKey();
- ecdh = new ECDHCrypt(key.getParams(), sslContext.getSecureRandom());
- ephemeralServerKey = key;
- }
-
- /*
- * The server's "Hello Done" message is the client's sign that
- * it's time to do all the hard work.
- */
- private void serverHelloDone(ServerHelloDone mesg) throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- /*
- * Always make sure the input has been digested before we
- * start emitting data, to ensure the hashes are correctly
- * computed for the Finished and CertificateVerify messages
- * which we send (here).
- */
- input.digestNow();
-
- /*
- * FIRST ... if requested, send an appropriate Certificate chain
- * to authenticate the client, and remember the associated private
- * key to sign the CertificateVerify message.
- */
- PrivateKey signingKey = null;
-
- if (certRequest != null) {
- X509ExtendedKeyManager km = sslContext.getX509KeyManager();
-
- ArrayList<String> keytypesTmp = new ArrayList<>(4);
-
- for (int i = 0; i < certRequest.types.length; i++) {
- String typeName;
-
- switch (certRequest.types[i]) {
- case CertificateRequest.cct_rsa_sign:
- typeName = "RSA";
- break;
-
- case CertificateRequest.cct_dss_sign:
- typeName = "DSA";
- break;
-
- case CertificateRequest.cct_ecdsa_sign:
- // ignore if we do not have EC crypto available
- typeName = JsseJce.isEcAvailable() ? "EC" : null;
- break;
-
- // Fixed DH/ECDH client authentication not supported
- case CertificateRequest.cct_rsa_fixed_dh:
- case CertificateRequest.cct_dss_fixed_dh:
- case CertificateRequest.cct_rsa_fixed_ecdh:
- case CertificateRequest.cct_ecdsa_fixed_ecdh:
- // Any other values (currently not used in TLS)
- case CertificateRequest.cct_rsa_ephemeral_dh:
- case CertificateRequest.cct_dss_ephemeral_dh:
- default:
- typeName = null;
- break;
- }
-
- if ((typeName != null) && (!keytypesTmp.contains(typeName))) {
- keytypesTmp.add(typeName);
- }
- }
-
- String alias = null;
- int keytypesTmpSize = keytypesTmp.size();
- if (keytypesTmpSize != 0) {
- String keytypes[] =
- keytypesTmp.toArray(new String[keytypesTmpSize]);
-
- if (conn != null) {
- alias = km.chooseClientAlias(keytypes,
- certRequest.getAuthorities(), conn);
- } else {
- alias = km.chooseEngineClientAlias(keytypes,
- certRequest.getAuthorities(), engine);
- }
- }
-
- CertificateMsg m1 = null;
- if (alias != null) {
- X509Certificate[] certs = km.getCertificateChain(alias);
- if ((certs != null) && (certs.length != 0)) {
- PublicKey publicKey = certs[0].getPublicKey();
- // for EC, make sure we use a supported named curve
- if (publicKey instanceof ECPublicKey) {
- ECParameterSpec params =
- ((ECPublicKey)publicKey).getParams();
- int index =
- SupportedEllipticCurvesExtension.getCurveIndex(
- params);
- if (!SupportedEllipticCurvesExtension.isSupported(
- index)) {
- publicKey = null;
- }
- }
- if (publicKey != null) {
- m1 = new CertificateMsg(certs);
- signingKey = km.getPrivateKey(alias);
- session.setLocalPrivateKey(signingKey);
- session.setLocalCertificates(certs);
- }
- }
- }
- if (m1 == null) {
- //
- // No appropriate cert was found ... report this to the
- // server. For SSLv3, send the no_certificate alert;
- // TLS uses an empty cert chain instead.
- //
- if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
- m1 = new CertificateMsg(new X509Certificate [0]);
- } else {
- warningSE(Alerts.alert_no_certificate);
- }
- }
-
- //
- // At last ... send any client certificate chain.
- //
- if (m1 != null) {
- if (debug != null && Debug.isOn("handshake")) {
- m1.print(System.out);
- }
- m1.write(output);
- }
- }
-
- /*
- * SECOND ... send the client key exchange message. The
- * procedure used is a function of the cipher suite selected;
- * one is always needed.
- */
- HandshakeMessage m2;
-
- switch (keyExchange) {
-
- case K_RSA:
- case K_RSA_EXPORT:
- if (serverKey == null) {
- throw new SSLProtocolException
- ("Server did not send certificate message");
- }
-
- if (!(serverKey instanceof RSAPublicKey)) {
- throw new SSLProtocolException
- ("Server certificate does not include an RSA key");
- }
-
- /*
- * For RSA key exchange, we randomly generate a new
- * pre-master secret and encrypt it with the server's
- * public key. Then we save that pre-master secret
- * so that we can calculate the keying data later;
- * it's a performance speedup not to do that until
- * the client's waiting for the server response, but
- * more of a speedup for the D-H case.
- *
- * If the RSA_EXPORT scheme is active, when the public
- * key in the server certificate is less than or equal
- * to 512 bits in length, use the cert's public key,
- * otherwise, the ephemeral one.
- */
- PublicKey key;
- if (keyExchange == K_RSA) {
- key = serverKey;
- } else { // K_RSA_EXPORT
- if (JsseJce.getRSAKeyLength(serverKey) <= 512) {
- // extraneous ephemeralServerKey check done
- // above in processMessage()
- key = serverKey;
- } else {
- if (ephemeralServerKey == null) {
- throw new SSLProtocolException("Server did not send" +
- " a RSA_EXPORT Server Key Exchange message");
- }
- key = ephemeralServerKey;
- }
- }
-
- m2 = new RSAClientKeyExchange(protocolVersion, maxProtocolVersion,
- sslContext.getSecureRandom(), key);
- break;
- case K_DH_RSA:
- case K_DH_DSS:
- /*
- * For DH Key exchange, we only need to make sure the server
- * knows our public key, so we calculate the same pre-master
- * secret.
- *
- * For certs that had DH keys in them, we send an empty
- * handshake message (no key) ... we flag this case by
- * passing a null "dhPublic" value.
- *
- * Otherwise we send ephemeral DH keys, unsigned.
- */
- // if (useDH_RSA || useDH_DSS)
- m2 = new DHClientKeyExchange();
- break;
- case K_DHE_RSA:
- case K_DHE_DSS:
- case K_DH_ANON:
- if (dh == null) {
- throw new SSLProtocolException
- ("Server did not send a DH Server Key Exchange message");
- }
- m2 = new DHClientKeyExchange(dh.getPublicKey());
- break;
- case K_ECDHE_RSA:
- case K_ECDHE_ECDSA:
- case K_ECDH_ANON:
- if (ecdh == null) {
- throw new SSLProtocolException
- ("Server did not send a ECDH Server Key Exchange message");
- }
- m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());
- break;
- case K_ECDH_RSA:
- case K_ECDH_ECDSA:
- if (serverKey == null) {
- throw new SSLProtocolException
- ("Server did not send certificate message");
- }
- if (serverKey instanceof ECPublicKey == false) {
- throw new SSLProtocolException
- ("Server certificate does not include an EC key");
- }
- ECParameterSpec params = ((ECPublicKey)serverKey).getParams();
- ecdh = new ECDHCrypt(params, sslContext.getSecureRandom());
- m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());
- break;
- case K_KRB5:
- case K_KRB5_EXPORT:
- String hostname = getHostSE();
- if (hostname == null) {
- throw new IOException("Hostname is required" +
- " to use Kerberos cipher suites");
- }
- KerberosClientKeyExchange kerberosMsg =
- new KerberosClientKeyExchange(
- hostname, isLoopbackSE(), getAccSE(), protocolVersion,
- sslContext.getSecureRandom());
- // Record the principals involved in exchange
- session.setPeerPrincipal(kerberosMsg.getPeerPrincipal());
- session.setLocalPrincipal(kerberosMsg.getLocalPrincipal());
- m2 = kerberosMsg;
- break;
- default:
- // somethings very wrong
- throw new RuntimeException
- ("Unsupported key exchange: " + keyExchange);
- }
- if (debug != null && Debug.isOn("handshake")) {
- m2.print(System.out);
- }
- m2.write(output);
-
-
- /*
- * THIRD, send a "change_cipher_spec" record followed by the
- * "Finished" message. We flush the messages we've queued up, to
- * get concurrency between client and server. The concurrency is
- * useful as we calculate the master secret, which is needed both
- * to compute the "Finished" message, and to compute the keys used
- * to protect all records following the change_cipher_spec.
- */
-
- output.doHashes();
- output.flush();
-
- /*
- * We deferred calculating the master secret and this connection's
- * keying data; we do it now. Deferring this calculation is good
- * from a performance point of view, since it lets us do it during
- * some time that network delays and the server's own calculations
- * would otherwise cause to be "dead" in the critical path.
- */
- SecretKey preMasterSecret;
- switch (keyExchange) {
- case K_RSA:
- case K_RSA_EXPORT:
- preMasterSecret = ((RSAClientKeyExchange)m2).preMaster;
- break;
- case K_KRB5:
- case K_KRB5_EXPORT:
- byte[] secretBytes =
- ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret();
- preMasterSecret = new SecretKeySpec(secretBytes,
- "TlsPremasterSecret");
- break;
- case K_DHE_RSA:
- case K_DHE_DSS:
- case K_DH_ANON:
- preMasterSecret = dh.getAgreedSecret(serverDH, true);
- break;
- case K_ECDHE_RSA:
- case K_ECDHE_ECDSA:
- case K_ECDH_ANON:
- preMasterSecret = ecdh.getAgreedSecret(ephemeralServerKey);
- break;
- case K_ECDH_RSA:
- case K_ECDH_ECDSA:
- preMasterSecret = ecdh.getAgreedSecret(serverKey);
- break;
- default:
- throw new IOException("Internal error: unknown key exchange "
- + keyExchange);
- }
-
- calculateKeys(preMasterSecret, null);
-
- /*
- * FOURTH, if we sent a Certificate, we need to send a signed
- * CertificateVerify (unless the key in the client's certificate
- * was a Diffie-Hellman key).).
- *
- * This uses a hash of the previous handshake messages ... either
- * a nonfinal one (if the particular implementation supports it)
- * or else using the third element in the arrays of hashes being
- * computed.
- */
- if (signingKey != null) {
- CertificateVerify m3;
- try {
- SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.getPreferableAlgorithm(
- peerSupportedSignAlgs, signingKey.getAlgorithm(),
- signingKey);
-
- if (preferableSignatureAlgorithm == null) {
- throw new SSLHandshakeException(
- "No supported signature algorithm");
- }
-
- String hashAlg =
- SignatureAndHashAlgorithm.getHashAlgorithmName(
- preferableSignatureAlgorithm);
- if (hashAlg == null || hashAlg.length() == 0) {
- throw new SSLHandshakeException(
- "No supported hash algorithm");
- }
-
- handshakeHash.setCertificateVerifyAlg(hashAlg);
- }
-
- m3 = new CertificateVerify(protocolVersion, handshakeHash,
- signingKey, session.getMasterSecret(),
- sslContext.getSecureRandom(),
- preferableSignatureAlgorithm);
- } catch (GeneralSecurityException e) {
- fatalSE(Alerts.alert_handshake_failure,
- "Error signing certificate verify", e);
- // NOTREACHED, make compiler happy
- m3 = null;
- }
- if (debug != null && Debug.isOn("handshake")) {
- m3.print(System.out);
- }
- m3.write(output);
- output.doHashes();
- } else {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- handshakeHash.setCertificateVerifyAlg(null);
- }
- }
-
- /*
- * OK, that's that!
- */
- sendChangeCipherAndFinish(false);
- }
-
-
- /*
- * "Finished" is the last handshake message sent. If we got this
- * far, the MAC has been validated post-decryption. We validate
- * the two hashes here as an additional sanity check, protecting
- * the handshake against various active attacks.
- */
- private void serverFinished(Finished mesg) throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- boolean verified = mesg.verify(handshakeHash, Finished.SERVER,
- session.getMasterSecret());
-
- if (!verified) {
- fatalSE(Alerts.alert_illegal_parameter,
- "server 'finished' message doesn't verify");
- // NOTREACHED
- }
-
- /*
- * save server verify data for secure renegotiation
- */
- if (secureRenegotiation) {
- serverVerifyData = mesg.getVerifyData();
- }
-
- /*
- * OK, it verified. If we're doing the fast handshake, add that
- * "Finished" message to the hash of handshake messages, then send
- * our own change_cipher_spec and Finished message for the server
- * to verify in turn. These are the last handshake messages.
- *
- * In any case, update the session cache. We're done handshaking,
- * so there are no threats any more associated with partially
- * completed handshakes.
- */
- if (resumingSession) {
- input.digestNow();
- sendChangeCipherAndFinish(true);
- }
- session.setLastAccessedTime(System.currentTimeMillis());
-
- if (!resumingSession) {
- if (session.isRejoinable()) {
- ((SSLSessionContextImpl) sslContext
- .engineGetClientSessionContext())
- .put(session);
- if (debug != null && Debug.isOn("session")) {
- System.out.println("%% Cached client session: " + session);
- }
- } else if (debug != null && Debug.isOn("session")) {
- System.out.println(
- "%% Didn't cache non-resumable client session: "
- + session);
- }
- }
- }
-
-
- /*
- * Send my change-cipher-spec and Finished message ... done as the
- * last handshake act in either the short or long sequences. In
- * the short one, we've already seen the server's Finished; in the
- * long one, we wait for it now.
- */
- private void sendChangeCipherAndFinish(boolean finishedTag)
- throws IOException {
- Finished mesg = new Finished(protocolVersion, handshakeHash,
- Finished.CLIENT, session.getMasterSecret(), cipherSuite);
-
- /*
- * Send the change_cipher_spec message, then the Finished message
- * which we just calculated (and protected using the keys we just
- * calculated). Server responds with its Finished message, except
- * in the "fast handshake" (resume session) case.
- */
- sendChangeCipherSpec(mesg, finishedTag);
-
- /*
- * save client verify data for secure renegotiation
- */
- if (secureRenegotiation) {
- clientVerifyData = mesg.getVerifyData();
- }
-
- /*
- * Update state machine so server MUST send 'finished' next.
- * (In "long" handshake case; in short case, we're responding
- * to its message.)
- */
- state = HandshakeMessage.ht_finished - 1;
- }
-
-
- /*
- * Returns a ClientHello message to kickstart renegotiations
- */
- HandshakeMessage getKickstartMessage() throws SSLException {
- // session ID of the ClientHello message
- SessionId sessionId = SSLSessionImpl.nullSession.getSessionId();
-
- // a list of cipher suites sent by the client
- CipherSuiteList cipherSuites = getActiveCipherSuites();
-
- // set the max protocol version this client is supporting.
- maxProtocolVersion = protocolVersion;
-
- //
- // Try to resume an existing session. This might be mandatory,
- // given certain API options.
- //
- session = ((SSLSessionContextImpl)sslContext
- .engineGetClientSessionContext())
- .get(getHostSE(), getPortSE());
- if (debug != null && Debug.isOn("session")) {
- if (session != null) {
- System.out.println("%% Client cached "
- + session
- + (session.isRejoinable() ? "" : " (not rejoinable)"));
- } else {
- System.out.println("%% No cached client session");
- }
- }
- if ((session != null) && (session.isRejoinable() == false)) {
- session = null;
- }
-
- if (session != null) {
- CipherSuite sessionSuite = session.getSuite();
- ProtocolVersion sessionVersion = session.getProtocolVersion();
- if (isNegotiable(sessionSuite) == false) {
- if (debug != null && Debug.isOn("session")) {
- System.out.println("%% can't resume, unavailable cipher");
- }
- session = null;
- }
-
- if ((session != null) && !isNegotiable(sessionVersion)) {
- if (debug != null && Debug.isOn("session")) {
- System.out.println("%% can't resume, protocol disabled");
- }
- session = null;
- }
-
- if (session != null) {
- if (debug != null) {
- if (Debug.isOn("handshake") || Debug.isOn("session")) {
- System.out.println("%% Try resuming " + session
- + " from port " + getLocalPortSE());
- }
- }
-
- sessionId = session.getSessionId();
- maxProtocolVersion = sessionVersion;
-
- // Update SSL version number in underlying SSL socket and
- // handshake output stream, so that the output records (at the
- // record layer) have the correct version
- setVersion(sessionVersion);
- }
-
- /*
- * Force use of the previous session ciphersuite, and
- * add the SCSV if enabled.
- */
- if (!enableNewSession) {
- if (session == null) {
- throw new SSLHandshakeException(
- "Can't reuse existing SSL client session");
- }
-
- Collection<CipherSuite> cipherList = new ArrayList<>(2);
- cipherList.add(sessionSuite);
- if (!secureRenegotiation &&
- cipherSuites.contains(CipherSuite.C_SCSV)) {
- cipherList.add(CipherSuite.C_SCSV);
- } // otherwise, renegotiation_info extension will be used
-
- cipherSuites = new CipherSuiteList(cipherList);
- }
- }
-
- if (session == null && !enableNewSession) {
- throw new SSLHandshakeException("No existing session to resume");
- }
-
- // exclude SCSV for secure renegotiation
- if (secureRenegotiation && cipherSuites.contains(CipherSuite.C_SCSV)) {
- Collection<CipherSuite> cipherList =
- new ArrayList<>(cipherSuites.size() - 1);
- for (CipherSuite suite : cipherSuites.collection()) {
- if (suite != CipherSuite.C_SCSV) {
- cipherList.add(suite);
- }
- }
-
- cipherSuites = new CipherSuiteList(cipherList);
- }
-
- // make sure there is a negotiable cipher suite.
- boolean negotiable = false;
- for (CipherSuite suite : cipherSuites.collection()) {
- if (isNegotiable(suite)) {
- negotiable = true;
- break;
- }
- }
-
- if (!negotiable) {
- throw new SSLHandshakeException("No negotiable cipher suite");
- }
-
- // Not a TLS1.2+ handshake
- // For SSLv2Hello, HandshakeHash.reset() will be called, so we
- // cannot call HandshakeHash.protocolDetermined() here. As it does
- // not follow the spec that HandshakeHash.reset() can be only be
- // called before protocolDetermined.
- // if (maxProtocolVersion.v < ProtocolVersion.TLS12.v) {
- // handshakeHash.protocolDetermined(maxProtocolVersion);
- // }
-
- // create the ClientHello message
- ClientHello clientHelloMessage = new ClientHello(
- sslContext.getSecureRandom(), maxProtocolVersion,
- sessionId, cipherSuites);
-
- // add signature_algorithm extension
- if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) {
- // we will always send the signature_algorithm extension
- Collection<SignatureAndHashAlgorithm> localSignAlgs =
- getLocalSupportedSignAlgs();
- if (localSignAlgs.isEmpty()) {
- throw new SSLHandshakeException(
- "No supported signature algorithm");
- }
-
- clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs);
- }
-
- // add server_name extension
- if (enableSNIExtension) {
- // We cannot use the hostname resolved from name services. For
- // virtual hosting, multiple hostnames may be bound to the same IP
- // address, so the hostname resolved from name services is not
- // reliable.
- String hostname = getRawHostnameSE();
-
- // we only allow FQDN
- if (hostname != null && hostname.indexOf('.') > 0 &&
- !IPAddressUtil.isIPv4LiteralAddress(hostname) &&
- !IPAddressUtil.isIPv6LiteralAddress(hostname)) {
- clientHelloMessage.addServerNameIndicationExtension(hostname);
- }
- }
-
- // reset the client random cookie
- clnt_random = clientHelloMessage.clnt_random;
-
- /*
- * need to set the renegotiation_info extension for:
- * 1: secure renegotiation
- * 2: initial handshake and no SCSV in the ClientHello
- * 3: insecure renegotiation and no SCSV in the ClientHello
- */
- if (secureRenegotiation ||
- !cipherSuites.contains(CipherSuite.C_SCSV)) {
- clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData);
- }
-
- return clientHelloMessage;
- }
-
- /*
- * Fault detected during handshake.
- */
- void handshakeAlert(byte description) throws SSLProtocolException {
- String message = Alerts.alertDescription(description);
-
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("SSL - handshake alert: " + message);
- }
- throw new SSLProtocolException("handshake alert: " + message);
- }
-
- /*
- * Unless we are using an anonymous ciphersuite, the server always
- * sends a certificate message (for the CipherSuites we currently
- * support). The trust manager verifies the chain for us.
- */
- private void serverCertificate(CertificateMsg mesg) throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- X509Certificate[] peerCerts = mesg.getCertificateChain();
- if (peerCerts.length == 0) {
- fatalSE(Alerts.alert_bad_certificate,
- "empty certificate chain");
- }
- // ask the trust manager to verify the chain
- X509TrustManager tm = sslContext.getX509TrustManager();
- try {
- // find out the key exchange algorithm used
- // use "RSA" for non-ephemeral "RSA_EXPORT"
- String keyExchangeString;
- if (keyExchange == K_RSA_EXPORT && !serverKeyExchangeReceived) {
- keyExchangeString = K_RSA.name;
- } else {
- keyExchangeString = keyExchange.name;
- }
-
- if (tm instanceof X509ExtendedTrustManager) {
- if (conn != null) {
- ((X509ExtendedTrustManager)tm).checkServerTrusted(
- peerCerts.clone(),
- keyExchangeString,
- conn);
- } else {
- ((X509ExtendedTrustManager)tm).checkServerTrusted(
- peerCerts.clone(),
- keyExchangeString,
- engine);
- }
- } else {
- // Unlikely to happen, because we have wrapped the old
- // X509TrustManager with the new X509ExtendedTrustManager.
- throw new CertificateException(
- "Improper X509TrustManager implementation");
- }
- } catch (CertificateException e) {
- // This will throw an exception, so include the original error.
- fatalSE(Alerts.alert_certificate_unknown, e);
- }
- session.setPeerCertificates(peerCerts);
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/DHClientKeyExchange.java b/ojluni/src/main/java/sun/security/ssl/DHClientKeyExchange.java
deleted file mode 100755
index b450098..0000000
--- a/ojluni/src/main/java/sun/security/ssl/DHClientKeyExchange.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.math.BigInteger;
-import javax.net.ssl.SSLHandshakeException;
-
-/*
- * Message used by clients to send their Diffie-Hellman public
- * keys to servers.
- *
- * @author David Brownell
- */
-final class DHClientKeyExchange extends HandshakeMessage {
-
- int messageType() {
- return ht_client_key_exchange;
- }
-
- /*
- * This value may be empty if it was included in the
- * client's certificate ...
- */
- private byte dh_Yc[]; // 1 to 2^16 -1 bytes
-
- BigInteger getClientPublicKey() {
- return dh_Yc == null ? null : new BigInteger(1, dh_Yc);
- }
-
- /*
- * Either pass the client's public key explicitly (because it's
- * using DHE or DH_anon), or implicitly (the public key was in the
- * certificate).
- */
- DHClientKeyExchange(BigInteger publicKey) {
- dh_Yc = toByteArray(publicKey);
- }
-
- DHClientKeyExchange() {
- dh_Yc = null;
- }
-
- /*
- * Get the client's public key either explicitly or implicitly.
- * (It's ugly to have an empty record be sent in the latter case,
- * but that's what the protocol spec requires.)
- */
- DHClientKeyExchange(HandshakeInStream input) throws IOException {
- if (input.available() >= 2) {
- dh_Yc = input.getBytes16();
- } else {
- // currently, we don't support cipher suites that requires
- // implicit public key of client.
- throw new SSLHandshakeException(
- "Unsupported implicit client DiffieHellman public key");
- }
- }
-
- int messageLength() {
- if (dh_Yc == null) {
- return 0;
- } else {
- return dh_Yc.length + 2;
- }
- }
-
- void send(HandshakeOutStream s) throws IOException {
- if (dh_Yc != null && dh_Yc.length != 0) {
- s.putBytes16(dh_Yc);
- }
- }
-
- void print(PrintStream s) throws IOException {
- s.println("*** ClientKeyExchange, DH");
-
- if (debug != null && Debug.isOn("verbose")) {
- Debug.println(s, "DH Public key", dh_Yc);
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/DHCrypt.java b/ojluni/src/main/java/sun/security/ssl/DHCrypt.java
deleted file mode 100755
index ae9118f..0000000
--- a/ojluni/src/main/java/sun/security/ssl/DHCrypt.java
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.math.BigInteger;
-import java.security.*;
-import java.io.IOException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.crypto.SecretKey;
-import javax.crypto.KeyAgreement;
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.*;
-
-import sun.security.util.KeyUtil;
-
-/**
- * This class implements the Diffie-Hellman key exchange algorithm.
- * D-H means combining your private key with your partners public key to
- * generate a number. The peer does the same with its private key and our
- * public key. Through the magic of Diffie-Hellman we both come up with the
- * same number. This number is secret (discounting MITM attacks) and hence
- * called the shared secret. It has the same length as the modulus, e.g. 512
- * or 1024 bit. Man-in-the-middle attacks are typically countered by an
- * independent authentication step using certificates (RSA, DSA, etc.).
- *
- * The thing to note is that the shared secret is constant for two partners
- * with constant private keys. This is often not what we want, which is why
- * it is generally a good idea to create a new private key for each session.
- * Generating a private key involves one modular exponentiation assuming
- * suitable D-H parameters are available.
- *
- * General usage of this class (TLS DHE case):
- * . if we are server, call DHCrypt(keyLength,random). This generates
- * an ephemeral keypair of the request length.
- * . if we are client, call DHCrypt(modulus, base, random). This
- * generates an ephemeral keypair using the parameters specified by
- * the server.
- * . send parameters and public value to remote peer
- * . receive peers ephemeral public key
- * . call getAgreedSecret() to calculate the shared secret
- *
- * In TLS the server chooses the parameter values itself, the client must use
- * those sent to it by the server.
- *
- * The use of ephemeral keys as described above also achieves what is called
- * "forward secrecy". This means that even if the authentication keys are
- * broken at a later date, the shared secret remains secure. The session is
- * compromised only if the authentication keys are already broken at the
- * time the key exchange takes place and an active MITM attack is used.
- * This is in contrast to straightforward encrypting RSA key exchanges.
- *
- * @author David Brownell
- */
-final class DHCrypt {
-
- // group parameters (prime modulus and generator)
- private BigInteger modulus; // P (aka N)
- private BigInteger base; // G (aka alpha)
-
- // our private key (including private component x)
- private PrivateKey privateKey;
-
- // public component of our key, X = (g ^ x) mod p
- private BigInteger publicValue; // X (aka y)
-
- // the times to recove from failure if public key validation
- private static int MAX_FAILOVER_TIMES = 2;
-
- /**
- * Generate a Diffie-Hellman keypair of the specified size.
- */
- DHCrypt(int keyLength, SecureRandom random) {
- try {
- KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
- kpg.initialize(keyLength, random);
-
- DHPublicKeySpec spec = generateDHPublicKeySpec(kpg);
- if (spec == null) {
- throw new RuntimeException("Could not generate DH keypair");
- }
-
- publicValue = spec.getY();
- modulus = spec.getP();
- base = spec.getG();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate DH keypair", e);
- }
- }
-
-
- /**
- * Generate a Diffie-Hellman keypair using the specified parameters.
- *
- * @param modulus the Diffie-Hellman modulus P
- * @param base the Diffie-Hellman base G
- */
- DHCrypt(BigInteger modulus, BigInteger base, SecureRandom random) {
- this.modulus = modulus;
- this.base = base;
- try {
- KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
- DHParameterSpec params = new DHParameterSpec(modulus, base);
- kpg.initialize(params, random);
-
- DHPublicKeySpec spec = generateDHPublicKeySpec(kpg);
- if (spec == null) {
- throw new RuntimeException("Could not generate DH keypair");
- }
-
- publicValue = spec.getY();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate DH keypair", e);
- }
- }
-
-
- static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) {
- if (key instanceof DHPublicKey) {
- DHPublicKey dhKey = (DHPublicKey)key;
- DHParameterSpec params = dhKey.getParams();
- return new DHPublicKeySpec(dhKey.getY(),
- params.getP(), params.getG());
- }
- try {
- KeyFactory factory = JsseJce.getKeyFactory("DH");
- return factory.getKeySpec(key, DHPublicKeySpec.class);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
-
- /** Returns the Diffie-Hellman modulus. */
- BigInteger getModulus() {
- return modulus;
- }
-
- /** Returns the Diffie-Hellman base (generator). */
- BigInteger getBase() {
- return base;
- }
-
- /**
- * Gets the public key of this end of the key exchange.
- */
- BigInteger getPublicKey() {
- return publicValue;
- }
-
- /**
- * Get the secret data that has been agreed on through Diffie-Hellman
- * key agreement protocol. Note that in the two party protocol, if
- * the peer keys are already known, no other data needs to be sent in
- * order to agree on a secret. That is, a secured message may be
- * sent without any mandatory round-trip overheads.
- *
- * <P>It is illegal to call this member function if the private key
- * has not been set (or generated).
- *
- * @param peerPublicKey the peer's public key.
- * @param keyIsValidated whether the {@code peerPublicKey} has beed
- * validated
- * @return the secret, which is an unsigned big-endian integer
- * the same size as the Diffie-Hellman modulus.
- */
- SecretKey getAgreedSecret(BigInteger peerPublicValue,
- boolean keyIsValidated) throws IOException {
- try {
- KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman");
- DHPublicKeySpec spec =
- new DHPublicKeySpec(peerPublicValue, modulus, base);
- PublicKey publicKey = kf.generatePublic(spec);
- KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
-
- // validate the Diffie-Hellman public key
- if (!keyIsValidated &&
- !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) {
- try {
- KeyUtil.validate(spec);
- } catch (InvalidKeyException ike) {
- // prefer handshake_failure alert to internal_error alert
- throw new SSLHandshakeException(ike.getMessage());
- }
- }
-
- ka.init(privateKey);
- ka.doPhase(publicKey, true);
- return ka.generateSecret("TlsPremasterSecret");
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate secret", e);
- }
- }
-
- // Generate and validate DHPublicKeySpec
- private DHPublicKeySpec generateDHPublicKeySpec(KeyPairGenerator kpg)
- throws GeneralSecurityException {
-
- boolean doExtraValiadtion =
- (!KeyUtil.isOracleJCEProvider(kpg.getProvider().getName()));
- for (int i = 0; i <= MAX_FAILOVER_TIMES; i++) {
- KeyPair kp = kpg.generateKeyPair();
- privateKey = kp.getPrivate();
- DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
-
- // validate the Diffie-Hellman public key
- if (doExtraValiadtion) {
- try {
- KeyUtil.validate(spec);
- } catch (InvalidKeyException ivke) {
- if (i == MAX_FAILOVER_TIMES) {
- throw ivke;
- }
- // otherwise, ignore the exception and try the next one
- continue;
- }
- }
-
- return spec;
- }
-
- return null;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/Debug.java b/ojluni/src/main/java/sun/security/ssl/Debug.java
deleted file mode 100755
index a270816..0000000
--- a/ojluni/src/main/java/sun/security/ssl/Debug.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.PrintStream;
-import java.security.AccessController;
-import java.util.Locale;
-
-import sun.security.action.GetPropertyAction;
-
-/**
- * This class has be shamefully lifted from sun.security.util.Debug
- *
- * @author Gary Ellison
- */
-public class Debug {
-
- private String prefix;
-
- private static String args;
-
- static {
- args = java.security.AccessController.doPrivileged(
- new GetPropertyAction("javax.net.debug", ""));
- args = args.toLowerCase(Locale.ENGLISH);
- if (args.equals("help")) {
- Help();
- }
- }
-
- public static void Help()
- {
- System.err.println();
- System.err.println("all turn on all debugging");
- System.err.println("ssl turn on ssl debugging");
- System.err.println();
- System.err.println("The following can be used with ssl:");
- System.err.println("\trecord enable per-record tracing");
- System.err.println("\thandshake print each handshake message");
- System.err.println("\tkeygen print key generation data");
- System.err.println("\tsession print session activity");
- System.err.println("\tdefaultctx print default SSL initialization");
- System.err.println("\tsslctx print SSLContext tracing");
- System.err.println("\tsessioncache print session cache tracing");
- System.err.println("\tkeymanager print key manager tracing");
- System.err.println("\ttrustmanager print trust manager tracing");
- System.err.println("\tpluggability print pluggability tracing");
- System.err.println();
- System.err.println("\thandshake debugging can be widened with:");
- System.err.println("\tdata hex dump of each handshake message");
- System.err.println("\tverbose verbose handshake message printing");
- System.err.println();
- System.err.println("\trecord debugging can be widened with:");
- System.err.println("\tplaintext hex dump of record plaintext");
- System.err.println("\tpacket print raw SSL/TLS packets");
- System.err.println();
- System.exit(0);
- }
-
- /**
- * Get a Debug object corresponding to whether or not the given
- * option is set. Set the prefix to be the same as option.
- */
-
- public static Debug getInstance(String option)
- {
- return getInstance(option, option);
- }
-
- /**
- * Get a Debug object corresponding to whether or not the given
- * option is set. Set the prefix to be prefix.
- */
- public static Debug getInstance(String option, String prefix)
- {
- if (isOn(option)) {
- Debug d = new Debug();
- d.prefix = prefix;
- return d;
- } else {
- return null;
- }
- }
-
- /**
- * True if the property "javax.net.debug" contains the
- * string "option".
- */
- public static boolean isOn(String option)
- {
- if (args == null) {
- return false;
- } else {
- int n = 0;
- option = option.toLowerCase(Locale.ENGLISH);
-
- if (args.indexOf("all") != -1) {
- return true;
- } else if ((n = args.indexOf("ssl")) != -1) {
- if (args.indexOf("sslctx", n) == -1) {
- // don't enable data and plaintext options by default
- if (!(option.equals("data")
- || option.equals("packet")
- || option.equals("plaintext"))) {
- return true;
- }
- }
- }
- return (args.indexOf(option) != -1);
- }
- }
-
- /**
- * print a message to stderr that is prefixed with the prefix
- * created from the call to getInstance.
- */
-
- public void println(String message)
- {
- System.err.println(prefix + ": "+message);
- }
-
- /**
- * print a blank line to stderr that is prefixed with the prefix.
- */
-
- public void println()
- {
- System.err.println(prefix + ":");
- }
-
- /**
- * print a message to stderr that is prefixed with the prefix.
- */
-
- public static void println(String prefix, String message)
- {
- System.err.println(prefix + ": "+message);
- }
-
- public static void println(PrintStream s, String name, byte[] data) {
- s.print(name + ": { ");
- if (data == null) {
- s.print("null");
- } else {
- for (int i = 0; i < data.length; i++) {
- if (i != 0) s.print(", ");
- s.print(data[i] & 0x0ff);
- }
- }
- s.println(" }");
- }
-
- /**
- * Return the value of the boolean System property propName.
- *
- * Note use of doPrivileged(). Do make accessible to applications.
- */
- static boolean getBooleanProperty(String propName, boolean defaultValue) {
- // if set, require value of either true or false
- String b = AccessController.doPrivileged(
- new GetPropertyAction(propName));
- if (b == null) {
- return defaultValue;
- } else if (b.equalsIgnoreCase("false")) {
- return false;
- } else if (b.equalsIgnoreCase("true")) {
- return true;
- } else {
- throw new RuntimeException("Value of " + propName
- + " must either be 'true' or 'false'");
- }
- }
-
- static String toString(byte[] b) {
- return sun.security.util.Debug.toString(b);
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/ECDHClientKeyExchange.java b/ojluni/src/main/java/sun/security/ssl/ECDHClientKeyExchange.java
deleted file mode 100755
index d89945c..0000000
--- a/ojluni/src/main/java/sun/security/ssl/ECDHClientKeyExchange.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.io.PrintStream;
-
-import java.security.PublicKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.*;
-
-/**
- * ClientKeyExchange message for all ECDH based key exchange methods. It
- * contains the client's ephemeral public value.
- *
- * @since 1.6
- * @author Andreas Sterbenz
- */
-final class ECDHClientKeyExchange extends HandshakeMessage {
-
- int messageType() {
- return ht_client_key_exchange;
- }
-
- private byte[] encodedPoint;
-
- byte[] getEncodedPoint() {
- return encodedPoint;
- }
-
- // Called by the client with its ephemeral public key.
- ECDHClientKeyExchange(PublicKey publicKey) {
- ECPublicKey ecKey = (ECPublicKey)publicKey;
- ECPoint point = ecKey.getW();
- ECParameterSpec params = ecKey.getParams();
- encodedPoint = JsseJce.encodePoint(point, params.getCurve());
- }
-
- ECDHClientKeyExchange(HandshakeInStream input) throws IOException {
- encodedPoint = input.getBytes8();
- }
-
- int messageLength() {
- return encodedPoint.length + 1;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putBytes8(encodedPoint);
- }
-
- void print(PrintStream s) throws IOException {
- s.println("*** ECDHClientKeyExchange");
-
- if (debug != null && Debug.isOn("verbose")) {
- Debug.println(s, "ECDH Public value", encodedPoint);
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/ECDHCrypt.java b/ojluni/src/main/java/sun/security/ssl/ECDHCrypt.java
deleted file mode 100755
index 84dc467..0000000
--- a/ojluni/src/main/java/sun/security/ssl/ECDHCrypt.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.*;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.*;
-
-import javax.crypto.SecretKey;
-import javax.crypto.KeyAgreement;
-import javax.crypto.spec.*;
-
-/**
- * Helper class for the ECDH key exchange. It generates the appropriate
- * ephemeral keys as necessary and performs the actual shared secret derivation.
- *
- * @since 1.6
- * @author Andreas Sterbenz
- */
-final class ECDHCrypt {
-
- // our private key
- private PrivateKey privateKey;
-
- // our public key
- private ECPublicKey publicKey;
-
- // Called by ServerHandshaker for static ECDH
- ECDHCrypt(PrivateKey privateKey, PublicKey publicKey) {
- this.privateKey = privateKey;
- this.publicKey = (ECPublicKey)publicKey;
- }
-
- // Called by ServerHandshaker for ephemeral ECDH
- ECDHCrypt(String curveName, SecureRandom random) {
- try {
- KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
- ECGenParameterSpec params = new ECGenParameterSpec(curveName);
- kpg.initialize(params, random);
- KeyPair kp = kpg.generateKeyPair();
- privateKey = kp.getPrivate();
- publicKey = (ECPublicKey)kp.getPublic();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate DH keypair", e);
- }
- }
-
- // Called by ClientHandshaker with params it received from the server
- ECDHCrypt(ECParameterSpec params, SecureRandom random) {
- try {
- KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
- kpg.initialize(params, random);
- KeyPair kp = kpg.generateKeyPair();
- privateKey = kp.getPrivate();
- publicKey = (ECPublicKey)kp.getPublic();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate DH keypair", e);
- }
- }
-
- /**
- * Gets the public key of this end of the key exchange.
- */
- PublicKey getPublicKey() {
- return publicKey;
- }
-
- // called by ClientHandshaker with either the server's static or ephemeral public key
- SecretKey getAgreedSecret(PublicKey peerPublicKey) {
- try {
- KeyAgreement ka = JsseJce.getKeyAgreement("ECDH");
- ka.init(privateKey);
- ka.doPhase(peerPublicKey, true);
- return ka.generateSecret("TlsPremasterSecret");
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate secret", e);
- }
- }
-
- // called by ServerHandshaker
- SecretKey getAgreedSecret(byte[] encodedPoint) {
- try {
- ECParameterSpec params = publicKey.getParams();
- ECPoint point = JsseJce.decodePoint(encodedPoint, params.getCurve());
- KeyFactory kf = JsseJce.getKeyFactory("EC");
- ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
- PublicKey peerPublicKey = kf.generatePublic(spec);
- return getAgreedSecret(peerPublicKey);
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate secret", e);
- } catch (java.io.IOException e) {
- throw new RuntimeException("Could not generate secret", e);
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/EngineArgs.java b/ojluni/src/main/java/sun/security/ssl/EngineArgs.java
deleted file mode 100755
index 5f89d0c..0000000
--- a/ojluni/src/main/java/sun/security/ssl/EngineArgs.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.nio.*;
-
-/*
- * A multi-purpose class which handles all of the SSLEngine arguments.
- * It validates arguments, checks for RO conditions, does space
- * calculations, performs scatter/gather, etc.
- *
- * @author Brad R. Wetmore
- */
-class EngineArgs {
-
- /*
- * Keep track of the input parameters.
- */
- ByteBuffer netData;
- ByteBuffer [] appData;
-
- private int offset; // offset/len for the appData array.
- private int len;
-
- /*
- * The initial pos/limit conditions. This is useful because we can
- * quickly calculate the amount consumed/produced in successful
- * operations, or easily return the buffers to their pre-error
- * conditions.
- */
- private int netPos;
- private int netLim;
-
- private int [] appPoss;
- private int [] appLims;
-
- /*
- * Sum total of the space remaining in all of the appData buffers
- */
- private int appRemaining = 0;
-
- private boolean wrapMethod;
-
- /*
- * Called by the SSLEngine.wrap() method.
- */
- EngineArgs(ByteBuffer [] appData, int offset, int len,
- ByteBuffer netData) {
- this.wrapMethod = true;
- init(netData, appData, offset, len);
- }
-
- /*
- * Called by the SSLEngine.unwrap() method.
- */
- EngineArgs(ByteBuffer netData, ByteBuffer [] appData, int offset,
- int len) {
- this.wrapMethod = false;
- init(netData, appData, offset, len);
- }
-
- /*
- * The main initialization method for the arguments. Most
- * of them are pretty obvious as to what they do.
- *
- * Since we're already iterating over appData array for validity
- * checking, we also keep track of how much remainging space is
- * available. Info is used in both unwrap (to see if there is
- * enough space available in the destination), and in wrap (to
- * determine how much more we can copy into the outgoing data
- * buffer.
- */
- private void init(ByteBuffer netData, ByteBuffer [] appData,
- int offset, int len) {
-
- if ((netData == null) || (appData == null)) {
- throw new IllegalArgumentException("src/dst is null");
- }
-
- if ((offset < 0) || (len < 0) || (offset > appData.length - len)) {
- throw new IndexOutOfBoundsException();
- }
-
- if (wrapMethod && netData.isReadOnly()) {
- throw new ReadOnlyBufferException();
- }
-
- netPos = netData.position();
- netLim = netData.limit();
-
- appPoss = new int [appData.length];
- appLims = new int [appData.length];
-
- for (int i = offset; i < offset + len; i++) {
- if (appData[i] == null) {
- throw new IllegalArgumentException(
- "appData[" + i + "] == null");
- }
-
- /*
- * If we're unwrapping, then check to make sure our
- * destination bufffers are writable.
- */
- if (!wrapMethod && appData[i].isReadOnly()) {
- throw new ReadOnlyBufferException();
- }
-
- appRemaining += appData[i].remaining();
-
- appPoss[i] = appData[i].position();
- appLims[i] = appData[i].limit();
- }
-
- /*
- * Ok, looks like we have a good set of args, let's
- * store the rest of this stuff.
- */
- this.netData = netData;
- this.appData = appData;
- this.offset = offset;
- this.len = len;
- }
-
- /*
- * Given spaceLeft bytes to transfer, gather up that much data
- * from the appData buffers (starting at offset in the array),
- * and transfer it into the netData buffer.
- *
- * The user has already ensured there is enough room.
- */
- void gather(int spaceLeft) {
- for (int i = offset; (i < (offset + len)) && (spaceLeft > 0); i++) {
- int amount = Math.min(appData[i].remaining(), spaceLeft);
- appData[i].limit(appData[i].position() + amount);
- netData.put(appData[i]);
- appRemaining -= amount;
- spaceLeft -= amount;
- }
- }
-
- /*
- * Using the supplied buffer, scatter the data into the appData buffers
- * (starting at offset in the array).
- *
- * The user has already ensured there is enough room.
- */
- void scatter(ByteBuffer readyData) {
- int amountLeft = readyData.remaining();
-
- for (int i = offset; (i < (offset + len)) && (amountLeft > 0);
- i++) {
- int amount = Math.min(appData[i].remaining(), amountLeft);
- readyData.limit(readyData.position() + amount);
- appData[i].put(readyData);
- amountLeft -= amount;
- }
- assert(readyData.remaining() == 0);
- }
-
- int getAppRemaining() {
- return appRemaining;
- }
-
- /*
- * Calculate the bytesConsumed/byteProduced. Aren't you glad
- * we saved this off earlier?
- */
- int deltaNet() {
- return (netData.position() - netPos);
- }
-
- /*
- * Calculate the bytesConsumed/byteProduced. Aren't you glad
- * we saved this off earlier?
- */
- int deltaApp() {
- int sum = 0; // Only calculating 2^14 here, don't need a long.
-
- for (int i = offset; i < offset + len; i++) {
- sum += appData[i].position() - appPoss[i];
- }
-
- return sum;
- }
-
- /*
- * In the case of Exception, we want to reset the positions
- * to appear as though no data has been consumed or produced.
- *
- * Currently, this method is only called as we are preparing to
- * fail out, and thus we don't need to actually recalculate
- * appRemaining. If that assumption changes, that variable should
- * be updated here.
- */
- void resetPos() {
- netData.position(netPos);
- for (int i = offset; i < offset + len; i++) {
- // See comment above about recalculating appRemaining.
- appData[i].position(appPoss[i]);
- }
- }
-
- /*
- * We are doing lots of ByteBuffer manipulations, in which case
- * we need to make sure that the limits get set back correctly.
- * This is one of the last things to get done before returning to
- * the user.
- */
- void resetLim() {
- netData.limit(netLim);
- for (int i = offset; i < offset + len; i++) {
- appData[i].limit(appLims[i]);
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/EngineInputRecord.java b/ojluni/src/main/java/sun/security/ssl/EngineInputRecord.java
deleted file mode 100755
index fb7b133..0000000
--- a/ojluni/src/main/java/sun/security/ssl/EngineInputRecord.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-import javax.net.ssl.*;
-import javax.crypto.BadPaddingException;
-import sun.misc.HexDumpEncoder;
-
-
-/**
- * Wrapper class around InputRecord.
- *
- * Application data is kept external to the InputRecord,
- * but handshake data (alert/change_cipher_spec/handshake) will
- * be kept internally in the ByteArrayInputStream.
- *
- * @author Brad Wetmore
- */
-final class EngineInputRecord extends InputRecord {
-
- private SSLEngineImpl engine;
-
- /*
- * A dummy ByteBuffer we'll pass back even when the data
- * is stored internally. It'll never actually be used.
- */
- static private ByteBuffer tmpBB = ByteBuffer.allocate(0);
-
- /*
- * Flag to tell whether the last read/parsed data resides
- * internal in the ByteArrayInputStream, or in the external
- * buffers.
- */
- private boolean internalData;
-
- EngineInputRecord(SSLEngineImpl engine) {
- super();
- this.engine = engine;
- }
-
- byte contentType() {
- if (internalData) {
- return super.contentType();
- } else {
- return ct_application_data;
- }
- }
-
- /*
- * Check if there is enough inbound data in the ByteBuffer
- * to make a inbound packet. Look for both SSLv2 and SSLv3.
- *
- * @return -1 if there are not enough bytes to tell (small header),
- */
- int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
-
- /*
- * SSLv2 length field is in bytes 0/1
- * SSLv3/TLS length field is in bytes 3/4
- */
- if (buf.remaining() < 5) {
- return -1;
- }
-
- int pos = buf.position();
- byte byteZero = buf.get(pos);
-
- int len = 0;
-
- /*
- * If we have already verified previous packets, we can
- * ignore the verifications steps, and jump right to the
- * determination. Otherwise, try one last hueristic to
- * see if it's SSL/TLS.
- */
- if (formatVerified ||
- (byteZero == ct_handshake) ||
- (byteZero == ct_alert)) {
- /*
- * Last sanity check that it's not a wild record
- */
- ProtocolVersion recordVersion =
- ProtocolVersion.valueOf(buf.get(pos + 1), buf.get(pos + 2));
-
- // Check if too old (currently not possible)
- // or if the major version does not match.
- // The actual version negotiation is in the handshaker classes
- if ((recordVersion.v < ProtocolVersion.MIN.v)
- || (recordVersion.major > ProtocolVersion.MAX.major)) {
- throw new SSLException(
- "Unsupported record version " + recordVersion);
- }
-
- /*
- * Reasonably sure this is a V3, disable further checks.
- * We can't do the same in the v2 check below, because
- * read still needs to parse/handle the v2 clientHello.
- */
- formatVerified = true;
-
- /*
- * One of the SSLv3/TLS message types.
- */
- len = ((buf.get(pos + 3) & 0xff) << 8) +
- (buf.get(pos + 4) & 0xff) + headerSize;
-
- } else {
- /*
- * Must be SSLv2 or something unknown.
- * Check if it's short (2 bytes) or
- * long (3) header.
- *
- * Internals can warn about unsupported SSLv2
- */
- boolean isShort = ((byteZero & 0x80) != 0);
-
- if (isShort &&
- ((buf.get(pos + 2) == 1) || buf.get(pos + 2) == 4)) {
-
- ProtocolVersion recordVersion =
- ProtocolVersion.valueOf(buf.get(pos + 3), buf.get(pos + 4));
-
- // Check if too old (currently not possible)
- // or if the major version does not match.
- // The actual version negotiation is in the handshaker classes
- if ((recordVersion.v < ProtocolVersion.MIN.v)
- || (recordVersion.major > ProtocolVersion.MAX.major)) {
-
- // if it's not SSLv2, we're out of here.
- if (recordVersion.v != ProtocolVersion.SSL20Hello.v) {
- throw new SSLException(
- "Unsupported record version " + recordVersion);
- }
- }
-
- /*
- * Client or Server Hello
- */
- int mask = (isShort ? 0x7f : 0x3f);
- len = ((byteZero & mask) << 8) + (buf.get(pos + 1) & 0xff) +
- (isShort ? 2 : 3);
-
- } else {
- // Gobblygook!
- throw new SSLException(
- "Unrecognized SSL message, plaintext connection?");
- }
- }
-
- return len;
- }
-
- /*
- * Pass the data down if it's internally cached, otherwise
- * do it here.
- *
- * If internal data, data is decrypted internally.
- *
- * If external data(app), return a new ByteBuffer with data to
- * process.
- */
- ByteBuffer decrypt(MAC signer,
- CipherBox box, ByteBuffer bb) throws BadPaddingException {
-
- if (internalData) {
- decrypt(signer, box); // MAC is checked during decryption
- return tmpBB;
- }
-
- BadPaddingException reservedBPE = null;
- int tagLen = signer.MAClen();
- int cipheredLength = bb.remaining();
-
- if (!box.isNullCipher()) {
- // sanity check length of the ciphertext
- if (!box.sanityCheck(tagLen, cipheredLength)) {
- throw new BadPaddingException(
- "ciphertext sanity check failed");
- }
-
- try {
- // Note that the CipherBox.decrypt() does not change
- // the capacity of the buffer.
- box.decrypt(bb, tagLen);
- } catch (BadPaddingException bpe) {
- // RFC 2246 states that decryption_failed should be used
- // for this purpose. However, that allows certain attacks,
- // so we just send bad record MAC. We also need to make
- // sure to always check the MAC to avoid a timing attack
- // for the same issue. See paper by Vaudenay et al and the
- // update in RFC 4346/5246.
- //
- // Failover to message authentication code checking.
- reservedBPE = bpe;
- } finally {
- bb.rewind();
- }
- }
-
- if (tagLen != 0) {
- int macOffset = bb.limit() - tagLen;
-
- // Note that although it is not necessary, we run the same MAC
- // computation and comparison on the payload for both stream
- // cipher and CBC block cipher.
- if (bb.remaining() < tagLen) {
- // negative data length, something is wrong
- if (reservedBPE == null) {
- reservedBPE = new BadPaddingException("bad record");
- }
-
- // set offset of the dummy MAC
- macOffset = cipheredLength - tagLen;
- bb.limit(cipheredLength);
- }
-
- // Run MAC computation and comparison on the payload.
- if (checkMacTags(contentType(), bb, signer, false)) {
- if (reservedBPE == null) {
- reservedBPE = new BadPaddingException("bad record MAC");
- }
- }
-
- // Run MAC computation and comparison on the remainder.
- //
- // It is only necessary for CBC block cipher. It is used to get a
- // constant time of MAC computation and comparison on each record.
- if (box.isCBCMode()) {
- int remainingLen = calculateRemainingLen(
- signer, cipheredLength, macOffset);
-
- // NOTE: here we use the InputRecord.buf because I did not find
- // an effective way to work on ByteBuffer when its capacity is
- // less than remainingLen.
-
- // NOTE: remainingLen may be bigger (less than 1 block of the
- // hash algorithm of the MAC) than the cipheredLength. However,
- // We won't need to worry about it because we always use a
- // maximum buffer for every record. We need a change here if
- // we use small buffer size in the future.
- if (remainingLen > buf.length) {
- // unlikely to happen, just a placehold
- throw new RuntimeException(
- "Internal buffer capacity error");
- }
-
- // Won't need to worry about the result on the remainder. And
- // then we won't need to worry about what's actual data to
- // check MAC tag on. We start the check from the header of the
- // buffer so that we don't need to construct a new byte buffer.
- checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
- }
-
- bb.limit(macOffset);
- }
-
- // Is it a failover?
- if (reservedBPE != null) {
- throw reservedBPE;
- }
-
- return bb.slice();
- }
-
- /*
- * Run MAC computation and comparison
- *
- * Please DON'T change the content of the ByteBuffer parameter!
- */
- private static boolean checkMacTags(byte contentType, ByteBuffer bb,
- MAC signer, boolean isSimulated) {
-
- int tagLen = signer.MAClen();
- int lim = bb.limit();
- int macData = lim - tagLen;
-
- bb.limit(macData);
- byte[] hash = signer.compute(contentType, bb, isSimulated);
- if (hash == null || tagLen != hash.length) {
- // Something is wrong with MAC implementation.
- throw new RuntimeException("Internal MAC error");
- }
-
- bb.position(macData);
- bb.limit(lim);
- try {
- int[] results = compareMacTags(bb, hash);
- return (results[0] != 0);
- } finally {
- bb.rewind();
- bb.limit(macData);
- }
- }
-
- /*
- * A constant-time comparison of the MAC tags.
- *
- * Please DON'T change the content of the ByteBuffer parameter!
- */
- private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
-
- // An array of hits is used to prevent Hotspot optimization for
- // the purpose of a constant-time check.
- int[] results = {0, 0}; // {missed #, matched #}
-
- // The caller ensures there are enough bytes available in the buffer.
- // So we won't need to check the remaining of the buffer.
- for (int i = 0; i < tag.length; i++) {
- if (bb.get() != tag[i]) {
- results[0]++; // mismatched bytes
- } else {
- results[1]++; // matched bytes
- }
- }
-
- return results;
- }
-
- /*
- * Override the actual write below. We do things this way to be
- * consistent with InputRecord. InputRecord may try to write out
- * data to the peer, and *then* throw an Exception. This forces
- * data to be generated/output before the exception is ever
- * generated.
- */
- void writeBuffer(OutputStream s, byte [] buf, int off, int len)
- throws IOException {
- /*
- * Copy data out of buffer, it's ready to go.
- */
- ByteBuffer netBB = (ByteBuffer)
- (ByteBuffer.allocate(len).put(buf, 0, len).flip());
- engine.writer.putOutboundDataSync(netBB);
- }
-
- /*
- * Delineate or read a complete packet from src.
- *
- * If internal data (hs, alert, ccs), the data is read and
- * stored internally.
- *
- * If external data (app), return a new ByteBuffer which points
- * to the data to process.
- */
- ByteBuffer read(ByteBuffer srcBB) throws IOException {
- /*
- * Could have a src == null/dst == null check here,
- * but that was already checked by SSLEngine.unwrap before
- * ever attempting to read.
- */
-
- /*
- * If we have anything besides application data,
- * or if we haven't even done the initial v2 verification,
- * we send this down to be processed by the underlying
- * internal cache.
- */
- if (!formatVerified ||
- (srcBB.get(srcBB.position()) != ct_application_data)) {
- internalData = true;
- read(new ByteBufferInputStream(srcBB), (OutputStream) null);
- return tmpBB;
- }
-
- internalData = false;
-
- int srcPos = srcBB.position();
- int srcLim = srcBB.limit();
-
- ProtocolVersion recordVersion = ProtocolVersion.valueOf(
- srcBB.get(srcPos + 1), srcBB.get(srcPos + 2));
- // Check if too old (currently not possible)
- // or if the major version does not match.
- // The actual version negotiation is in the handshaker classes
- if ((recordVersion.v < ProtocolVersion.MIN.v)
- || (recordVersion.major > ProtocolVersion.MAX.major)) {
- throw new SSLException(
- "Unsupported record version " + recordVersion);
- }
-
- /*
- * It's really application data. How much to consume?
- * Jump over the header.
- */
- int len = bytesInCompletePacket(srcBB);
- assert(len > 0);
-
- if (debug != null && Debug.isOn("packet")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
- srcBB.limit(srcPos + len);
- ByteBuffer bb = srcBB.duplicate(); // Use copy of BB
-
- System.out.println("[Raw read (bb)]: length = " + len);
- hd.encodeBuffer(bb, System.out);
- } catch (IOException e) { }
- }
-
- // Demarcate past header to end of packet.
- srcBB.position(srcPos + headerSize);
- srcBB.limit(srcPos + len);
-
- // Protect remainder of buffer, create slice to actually
- // operate on.
- ByteBuffer bb = srcBB.slice();
-
- srcBB.position(srcBB.limit());
- srcBB.limit(srcLim);
-
- return bb;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/EngineOutputRecord.java b/ojluni/src/main/java/sun/security/ssl/EngineOutputRecord.java
deleted file mode 100755
index c7605fd..0000000
--- a/ojluni/src/main/java/sun/security/ssl/EngineOutputRecord.java
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-
-import javax.net.ssl.SSLException;
-import sun.misc.HexDumpEncoder;
-
-
-/**
- * A OutputRecord class extension which uses external ByteBuffers
- * or the internal ByteArrayOutputStream for data manipulations.
- * <P>
- * Instead of rewriting this entire class
- * to use ByteBuffers, we leave things intact, so handshake, CCS,
- * and alerts will continue to use the internal buffers, but application
- * data will use external buffers.
- *
- * @author Brad Wetmore
- */
-final class EngineOutputRecord extends OutputRecord {
-
- private SSLEngineImpl engine;
- private EngineWriter writer;
-
- private boolean finishedMsg = false;
-
- /*
- * All handshake hashing is done by the superclass
- */
-
- /*
- * Default constructor makes a record supporting the maximum
- * SSL record size. It allocates the header bytes directly.
- *
- * @param type the content type for the record
- */
- EngineOutputRecord(byte type, SSLEngineImpl engine) {
- super(type, recordSize(type));
- this.engine = engine;
- writer = engine.writer;
- }
-
- /**
- * Get the size of the buffer we need for records of the specified
- * type.
- * <P>
- * Application data buffers will provide their own byte buffers,
- * and will not use the internal byte caching.
- */
- private static int recordSize(byte type) {
- switch (type) {
-
- case ct_change_cipher_spec:
- case ct_alert:
- return maxAlertRecordSize;
-
- case ct_handshake:
- return maxRecordSize;
-
- case ct_application_data:
- return 0;
- }
-
- throw new RuntimeException("Unknown record type: " + type);
- }
-
- void setFinishedMsg() {
- finishedMsg = true;
- }
-
- public void flush() throws IOException {
- finishedMsg = false;
- }
-
- boolean isFinishedMsg() {
- return finishedMsg;
- }
-
-
- /**
- * Calculate the MAC value, storing the result either in
- * the internal buffer, or at the end of the destination
- * ByteBuffer.
- * <P>
- * We assume that the higher levels have assured us enough
- * room, otherwise we'll indirectly throw a
- * BufferOverFlowException runtime exception.
- *
- * position should equal limit, and points to the next
- * free spot.
- */
- private void addMAC(MAC signer, ByteBuffer bb)
- throws IOException {
-
- if (signer.MAClen() != 0) {
- byte[] hash = signer.compute(contentType(), bb, false);
-
- /*
- * position was advanced to limit in compute above.
- *
- * Mark next area as writable (above layers should have
- * established that we have plenty of room), then write
- * out the hash.
- */
- bb.limit(bb.limit() + hash.length);
- bb.put(hash);
- }
- }
-
- /*
- * Encrypt a ByteBuffer.
- *
- * We assume that the higher levels have assured us enough
- * room for the encryption (plus padding), otherwise we'll
- * indirectly throw a BufferOverFlowException runtime exception.
- *
- * position and limit will be the same, and points to the
- * next free spot.
- */
- void encrypt(CipherBox box, ByteBuffer bb) {
- box.encrypt(bb);
- }
-
- /*
- * Override the actual write below. We do things this way to be
- * consistent with InputRecord. InputRecord may try to write out
- * data to the peer, and *then* throw an Exception. This forces
- * data to be generated/output before the exception is ever
- * generated.
- */
- @Override
- void writeBuffer(OutputStream s, byte [] buf, int off, int len,
- int debugOffset) throws IOException {
- /*
- * Copy data out of buffer, it's ready to go.
- */
- ByteBuffer netBB = (ByteBuffer)
- ByteBuffer.allocate(len).put(buf, 0, len).flip();
- writer.putOutboundData(netBB);
- }
-
- /*
- * Main method for writing non-application data.
- * We MAC/encrypt, then send down for processing.
- */
- void write(MAC writeMAC, CipherBox writeCipher) throws IOException {
- /*
- * Sanity check.
- */
- switch (contentType()) {
- case ct_change_cipher_spec:
- case ct_alert:
- case ct_handshake:
- break;
- default:
- throw new RuntimeException("unexpected byte buffers");
- }
-
- /*
- * Don't bother to really write empty records. We went this
- * far to drive the handshake machinery, for correctness; not
- * writing empty records improves performance by cutting CPU
- * time and network resource usage. Also, some protocol
- * implementations are fragile and don't like to see empty
- * records, so this increases robustness.
- *
- * (Even change cipher spec messages have a byte of data!)
- */
- if (!isEmpty()) {
- // compress(); // eventually
- addMAC(writeMAC);
- encrypt(writeCipher);
- write((OutputStream)null, false, // send down for processing
- (ByteArrayOutputStream)null);
- }
- return;
- }
-
- /**
- * Main wrap/write driver.
- */
- void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher)
- throws IOException {
- /*
- * sanity check to make sure someone didn't inadvertantly
- * send us an impossible combination we don't know how
- * to process.
- */
- assert(contentType() == ct_application_data);
-
- /*
- * Have we set the MAC's yet? If not, we're not ready
- * to process application data yet.
- */
- if (writeMAC == MAC.NULL) {
- return;
- }
-
- /*
- * Don't bother to really write empty records. We went this
- * far to drive the handshake machinery, for correctness; not
- * writing empty records improves performance by cutting CPU
- * time and network resource usage. Also, some protocol
- * implementations are fragile and don't like to see empty
- * records, so this increases robustness.
- */
- if (ea.getAppRemaining() == 0) {
- return;
- }
-
- /*
- * By default, we counter chosen plaintext issues on CBC mode
- * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
- * data in the first record of every payload, and the rest in
- * subsequent record(s). Note that the issues have been solved in
- * TLS 1.1 or later.
- *
- * It is not necessary to split the very first application record of
- * a freshly negotiated TLS session, as there is no previous
- * application data to guess. To improve compatibility, we will not
- * split such records.
- *
- * Because of the compatibility, we'd better produce no more than
- * SSLSession.getPacketBufferSize() net data for each wrap. As we
- * need a one-byte record at first, the 2nd record size should be
- * equal to or less than Record.maxDataSizeMinusOneByteRecord.
- *
- * This avoids issues in the outbound direction. For a full fix,
- * the peer must have similar protections.
- */
- int length;
- if (engine.needToSplitPayload(writeCipher, protocolVersion)) {
- write(ea, writeMAC, writeCipher, 0x01);
- ea.resetLim(); // reset application data buffer limit
- length = Math.min(ea.getAppRemaining(),
- maxDataSizeMinusOneByteRecord);
- } else {
- length = Math.min(ea.getAppRemaining(), maxDataSize);
- }
-
- // Don't bother to really write empty records.
- if (length > 0) {
- write(ea, writeMAC, writeCipher, length);
- }
-
- return;
- }
-
- void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher,
- int length) throws IOException {
- /*
- * Copy out existing buffer values.
- */
- ByteBuffer dstBB = ea.netData;
- int dstPos = dstBB.position();
- int dstLim = dstBB.limit();
-
- /*
- * Where to put the data. Jump over the header.
- *
- * Don't need to worry about SSLv2 rewrites, if we're here,
- * that's long since done.
- */
- int dstData = dstPos + headerSize;
- dstBB.position(dstData);
-
- ea.gather(length);
-
- /*
- * "flip" but skip over header again, add MAC & encrypt
- * addMAC will expand the limit to reflect the new
- * data.
- */
- dstBB.limit(dstBB.position());
- dstBB.position(dstData);
- addMAC(writeMAC, dstBB);
-
- /*
- * Encrypt may pad, so again the limit may have changed.
- */
- dstBB.limit(dstBB.position());
- dstBB.position(dstData);
- encrypt(writeCipher, dstBB);
-
- if (debug != null
- && (Debug.isOn("record") || Debug.isOn("handshake"))) {
- if ((debug != null && Debug.isOn("record"))
- || contentType() == ct_change_cipher_spec)
- System.out.println(Thread.currentThread().getName()
- // v3.0/v3.1 ...
- + ", WRITE: " + protocolVersion
- + " " + InputRecord.contentName(contentType())
- + ", length = " + length);
- }
-
- int packetLength = dstBB.limit() - dstData;
-
- /*
- * Finish out the record header.
- */
- dstBB.put(dstPos, contentType());
- dstBB.put(dstPos + 1, protocolVersion.major);
- dstBB.put(dstPos + 2, protocolVersion.minor);
- dstBB.put(dstPos + 3, (byte)(packetLength >> 8));
- dstBB.put(dstPos + 4, (byte)packetLength);
-
- /*
- * Position was already set by encrypt() above.
- */
- dstBB.limit(dstLim);
-
- return;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/EngineWriter.java b/ojluni/src/main/java/sun/security/ssl/EngineWriter.java
deleted file mode 100755
index c930af7..0000000
--- a/ojluni/src/main/java/sun/security/ssl/EngineWriter.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import javax.net.ssl.*;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import javax.net.ssl.SSLEngineResult.HandshakeStatus;
-import sun.misc.HexDumpEncoder;
-
-/**
- * A class to help abstract away SSLEngine writing synchronization.
- */
-final class EngineWriter {
-
- /*
- * Outgoing handshake Data waiting for a ride is stored here.
- * Normal application data is written directly into the outbound
- * buffer, but handshake data can be written out at any time,
- * so we have buffer it somewhere.
- *
- * When wrap is called, we first check to see if there is
- * any data waiting, then if we're in a data transfer state,
- * we try to write app data.
- *
- * This will contain either ByteBuffers, or the marker
- * HandshakeStatus.FINISHED to signify that a handshake just completed.
- */
- private LinkedList<Object> outboundList;
-
- private boolean outboundClosed = false;
-
- /* Class and subclass dynamic debugging support */
- private static final Debug debug = Debug.getInstance("ssl");
-
- EngineWriter() {
- outboundList = new LinkedList<Object>();
- }
-
- /*
- * Upper levels assured us we had room for at least one packet of data.
- * As per the SSLEngine spec, we only return one SSL packets worth of
- * data.
- */
- private HandshakeStatus getOutboundData(ByteBuffer dstBB) {
-
- Object msg = outboundList.removeFirst();
- assert(msg instanceof ByteBuffer);
-
- ByteBuffer bbIn = (ByteBuffer) msg;
- assert(dstBB.remaining() >= bbIn.remaining());
-
- dstBB.put(bbIn);
-
- /*
- * If we have more data in the queue, it's either
- * a finished message, or an indication that we need
- * to call wrap again.
- */
- if (hasOutboundDataInternal()) {
- msg = outboundList.getFirst();
- if (msg == HandshakeStatus.FINISHED) {
- outboundList.removeFirst(); // consume the message
- return HandshakeStatus.FINISHED;
- } else {
- return HandshakeStatus.NEED_WRAP;
- }
- } else {
- return null;
- }
- }
-
- /*
- * Properly orders the output of the data written to the wrap call.
- * This is only handshake data, application data goes through the
- * other writeRecord.
- */
- synchronized void writeRecord(EngineOutputRecord outputRecord,
- MAC writeMAC, CipherBox writeCipher) throws IOException {
-
- /*
- * Only output if we're still open.
- */
- if (outboundClosed) {
- throw new IOException("writer side was already closed.");
- }
-
- outputRecord.write(writeMAC, writeCipher);
-
- /*
- * Did our handshakers notify that we just sent the
- * Finished message?
- *
- * Add an "I'm finished" message to the queue.
- */
- if (outputRecord.isFinishedMsg()) {
- outboundList.addLast(HandshakeStatus.FINISHED);
- }
- }
-
- /*
- * Output the packet info.
- */
- private void dumpPacket(EngineArgs ea, boolean hsData) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
-
- ByteBuffer bb = ea.netData.duplicate();
-
- int pos = bb.position();
- bb.position(pos - ea.deltaNet());
- bb.limit(pos);
-
- System.out.println("[Raw write" +
- (hsData ? "" : " (bb)") + "]: length = " +
- bb.remaining());
- hd.encodeBuffer(bb, System.out);
- } catch (IOException e) { }
- }
-
- /*
- * Properly orders the output of the data written to the wrap call.
- * Only app data goes through here, handshake data goes through
- * the other writeRecord.
- *
- * Shouldn't expect to have an IOException here.
- *
- * Return any determined status.
- */
- synchronized HandshakeStatus writeRecord(
- EngineOutputRecord outputRecord, EngineArgs ea, MAC writeMAC,
- CipherBox writeCipher) throws IOException {
-
- /*
- * If we have data ready to go, output this first before
- * trying to consume app data.
- */
- if (hasOutboundDataInternal()) {
- HandshakeStatus hss = getOutboundData(ea.netData);
-
- if (debug != null && Debug.isOn("packet")) {
- /*
- * We could have put the dump in
- * OutputRecord.write(OutputStream), but let's actually
- * output when it's actually output by the SSLEngine.
- */
- dumpPacket(ea, true);
- }
-
- return hss;
- }
-
- /*
- * If we are closed, no more app data can be output.
- * Only existing handshake data (above) can be obtained.
- */
- if (outboundClosed) {
- throw new IOException("The write side was already closed");
- }
-
- outputRecord.write(ea, writeMAC, writeCipher);
-
- if (debug != null && Debug.isOn("packet")) {
- dumpPacket(ea, false);
- }
-
- /*
- * No way new outbound handshake data got here if we're
- * locked properly.
- *
- * We don't have any status we can return.
- */
- return null;
- }
-
- /*
- * We already hold "this" lock, this is the callback from the
- * outputRecord.write() above. We already know this
- * writer can accept more data (outboundClosed == false),
- * and the closure is sync'd.
- */
- void putOutboundData(ByteBuffer bytes) {
- outboundList.addLast(bytes);
- }
-
- /*
- * This is for the really rare case that someone is writing from
- * the *InputRecord* before we know what to do with it.
- */
- synchronized void putOutboundDataSync(ByteBuffer bytes)
- throws IOException {
-
- if (outboundClosed) {
- throw new IOException("Write side already closed");
- }
-
- outboundList.addLast(bytes);
- }
-
- /*
- * Non-synch'd version of this method, called by internals
- */
- private boolean hasOutboundDataInternal() {
- return (outboundList.size() != 0);
- }
-
- synchronized boolean hasOutboundData() {
- return hasOutboundDataInternal();
- }
-
- synchronized boolean isOutboundDone() {
- return outboundClosed && !hasOutboundDataInternal();
- }
-
- synchronized void closeOutbound() {
- outboundClosed = true;
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/EphemeralKeyManager.java b/ojluni/src/main/java/sun/security/ssl/EphemeralKeyManager.java
deleted file mode 100755
index 47dba95..0000000
--- a/ojluni/src/main/java/sun/security/ssl/EphemeralKeyManager.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.*;
-
-/**
- * The "KeyManager" for ephemeral RSA keys. Ephemeral DH and ECDH keys
- * are handled by the DHCrypt and ECDHCrypt classes, respectively.
- *
- * @author Andreas Sterbenz
- */
-final class EphemeralKeyManager {
-
- // indices for the keys array below
- private final static int INDEX_RSA512 = 0;
- private final static int INDEX_RSA1024 = 1;
-
- /*
- * Current cached RSA KeyPairs. Elements are never null.
- * Indexed via the the constants above.
- */
- private final EphemeralKeyPair[] keys = new EphemeralKeyPair[] {
- new EphemeralKeyPair(null),
- new EphemeralKeyPair(null),
- };
-
- EphemeralKeyManager() {
- // empty
- }
-
- /*
- * Get a temporary RSA KeyPair.
- */
- KeyPair getRSAKeyPair(boolean export, SecureRandom random) {
- int length, index;
- if (export) {
- length = 512;
- index = INDEX_RSA512;
- } else {
- length = 1024;
- index = INDEX_RSA1024;
- }
-
- synchronized (keys) {
- KeyPair kp = keys[index].getKeyPair();
- if (kp == null) {
- try {
- KeyPairGenerator kgen = JsseJce.getKeyPairGenerator("RSA");
- kgen.initialize(length, random);
- keys[index] = new EphemeralKeyPair(kgen.genKeyPair());
- kp = keys[index].getKeyPair();
- } catch (Exception e) {
- // ignore
- }
- }
- return kp;
- }
- }
-
- /**
- * Inner class to handle storage of ephemeral KeyPairs.
- */
- private static class EphemeralKeyPair {
-
- // maximum number of times a KeyPair is used
- private final static int MAX_USE = 200;
-
- // maximum time interval in which the keypair is used (1 hour in ms)
- private final static long USE_INTERVAL = 3600*1000;
-
- private KeyPair keyPair;
- private int uses;
- private long expirationTime;
-
- private EphemeralKeyPair(KeyPair keyPair) {
- this.keyPair = keyPair;
- expirationTime = System.currentTimeMillis() + USE_INTERVAL;
- }
-
- /*
- * Check if the KeyPair can still be used.
- */
- private boolean isValid() {
- return (keyPair != null) && (uses < MAX_USE)
- && (System.currentTimeMillis() < expirationTime);
- }
-
- /*
- * Return the KeyPair or null if it is invalid.
- */
- private KeyPair getKeyPair() {
- if (isValid() == false) {
- keyPair = null;
- return null;
- }
- uses++;
- return keyPair;
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/HandshakeHash.java b/ojluni/src/main/java/sun/security/ssl/HandshakeHash.java
deleted file mode 100755
index ffb8f32..0000000
--- a/ojluni/src/main/java/sun/security/ssl/HandshakeHash.java
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.ByteArrayOutputStream;
-import java.security.*;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Abstraction for the SSL/TLS hash of all handshake messages that is
- * maintained to verify the integrity of the negotiation. Internally,
- * it consists of an MD5 and an SHA1 digest. They are used in the client
- * and server finished messages and in certificate verify messages (if sent).
- *
- * This class transparently deals with cloneable and non-cloneable digests.
- *
- * This class now supports TLS 1.2 also. The key difference for TLS 1.2
- * is that you cannot determine the hash algorithms for CertificateVerify
- * at a early stage. On the other hand, it's simpler than TLS 1.1 (and earlier)
- * that there is no messy MD5+SHA1 digests.
- *
- * You need to obey these conventions when using this class:
- *
- * 1. protocolDetermined(version) should be called when the negotiated
- * protocol version is determined.
- *
- * 2. Before protocolDetermined() is called, only update(), reset(),
- * restrictCertificateVerifyAlgs(), setFinishedAlg(), and
- * setCertificateVerifyAlg() can be called.
- *
- * 3. After protocolDetermined() is called, reset() cannot be called.
- *
- * 4. After protocolDetermined() is called, if the version is pre-TLS 1.2,
- * getFinishedHash() and getCertificateVerifyHash() cannot be called. Otherwise,
- * getMD5Clone() and getSHAClone() cannot be called.
- *
- * 5. getMD5Clone() and getSHAClone() can only be called after
- * protocolDetermined() is called and version is pre-TLS 1.2.
- *
- * 6. getFinishedHash() and getCertificateVerifyHash() can only be called after
- * all protocolDetermined(), setCertificateVerifyAlg() and setFinishedAlg()
- * have been called and the version is TLS 1.2. If a CertificateVerify message
- * is to be used, call setCertificateVerifyAlg() with the hash algorithm as the
- * argument. Otherwise, you still must call setCertificateVerifyAlg(null) before
- * calculating any hash value.
- *
- * Suggestions: Call protocolDetermined(), restrictCertificateVerifyAlgs(),
- * setFinishedAlg(), and setCertificateVerifyAlg() as early as possible.
- *
- * Example:
- * <pre>
- * HandshakeHash hh = new HandshakeHash(...)
- * hh.protocolDetermined(ProtocolVersion.TLS12);
- * hh.update(clientHelloBytes);
- * hh.setFinishedAlg("SHA-256");
- * hh.update(serverHelloBytes);
- * ...
- * hh.setCertificateVerifyAlg("SHA-384");
- * hh.update(CertificateVerifyBytes);
- * byte[] cvDigest = hh.getCertificateVerifyHash();
- * ...
- * hh.update(finished1);
- * byte[] finDigest1 = hh.getFinishedHash();
- * hh.update(finished2);
- * byte[] finDigest2 = hh.getFinishedHash();
- * </pre>
- * If no CertificateVerify message is to be used, call
- * <pre>
- * hh.setCertificateVerifyAlg(null);
- * </pre>
- * This call can be made once you are certain that this message
- * will never be used.
- */
-final class HandshakeHash {
-
- // Common
-
- // -1: unknown
- // 1: <=TLS 1.1
- // 2: TLS 1.2
- private int version = -1;
- private ByteArrayOutputStream data = new ByteArrayOutputStream();
- private final boolean isServer;
-
- // For TLS 1.1
- private MessageDigest md5, sha;
- private final int clonesNeeded; // needs to be saved for later use
-
- // For TLS 1.2
- // cvAlgDetermined == true means setCertificateVerifyAlg() is called
- private boolean cvAlgDetermined = false;
- private String cvAlg;
- private MessageDigest finMD;
-
- /**
- * Create a new HandshakeHash. needCertificateVerify indicates whether
- * a hash for the certificate verify message is required. The argument
- * algs is a set of all possible hash algorithms that might be used in
- * TLS 1.2. If the caller is sure that TLS 1.2 won't be used or no
- * CertificateVerify message will be used, leave it null or empty.
- */
- HandshakeHash(boolean isServer, boolean needCertificateVerify,
- Set<String> algs) {
- this.isServer = isServer;
- clonesNeeded = needCertificateVerify ? 3 : 2;
- }
-
- void update(byte[] b, int offset, int len) {
- switch (version) {
- case 1:
- md5.update(b, offset, len);
- sha.update(b, offset, len);
- break;
- default:
- if (finMD != null) {
- finMD.update(b, offset, len);
- }
- data.write(b, offset, len);
- break;
- }
- }
-
- /**
- * Reset the remaining digests. Note this does *not* reset the number of
- * digest clones that can be obtained. Digests that have already been
- * cloned and are gone remain gone.
- */
- void reset() {
- if (version != -1) {
- throw new RuntimeException(
- "reset() can be only be called before protocolDetermined");
- }
- data.reset();
- }
-
-
- void protocolDetermined(ProtocolVersion pv) {
-
- // Do not set again, will ignore
- if (version != -1) return;
-
- version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
- switch (version) {
- case 1:
- // initiate md5, sha and call update on saved array
- try {
- md5 = CloneableDigest.getDigest("MD5", clonesNeeded);
- sha = CloneableDigest.getDigest("SHA", clonesNeeded);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException
- ("Algorithm MD5 or SHA not available", e);
- }
- byte[] bytes = data.toByteArray();
- update(bytes, 0, bytes.length);
- break;
- case 2:
- break;
- }
- }
-
- /////////////////////////////////////////////////////////////
- // Below are old methods for pre-TLS 1.1
- /////////////////////////////////////////////////////////////
-
- /**
- * Return a new MD5 digest updated with all data hashed so far.
- */
- MessageDigest getMD5Clone() {
- if (version != 1) {
- throw new RuntimeException(
- "getMD5Clone() can be only be called for TLS 1.1");
- }
- return cloneDigest(md5);
- }
-
- /**
- * Return a new SHA digest updated with all data hashed so far.
- */
- MessageDigest getSHAClone() {
- if (version != 1) {
- throw new RuntimeException(
- "getSHAClone() can be only be called for TLS 1.1");
- }
- return cloneDigest(sha);
- }
-
- private static MessageDigest cloneDigest(MessageDigest digest) {
- try {
- return (MessageDigest)digest.clone();
- } catch (CloneNotSupportedException e) {
- // cannot occur for digests generated via CloneableDigest
- throw new RuntimeException("Could not clone digest", e);
- }
- }
-
- /////////////////////////////////////////////////////////////
- // Below are new methods for TLS 1.2
- /////////////////////////////////////////////////////////////
-
- private static String normalizeAlgName(String alg) {
- alg = alg.toUpperCase(Locale.US);
- if (alg.startsWith("SHA")) {
- if (alg.length() == 3) {
- return "SHA-1";
- }
- if (alg.charAt(3) != '-') {
- return "SHA-" + alg.substring(3);
- }
- }
- return alg;
- }
- /**
- * Specifies the hash algorithm used in Finished. This should be called
- * based in info in ServerHello.
- * Can be called multiple times.
- */
- void setFinishedAlg(String s) {
- if (s == null) {
- throw new RuntimeException(
- "setFinishedAlg's argument cannot be null");
- }
-
- // Can be called multiple times, but only set once
- if (finMD != null) return;
-
- try {
- finMD = CloneableDigest.getDigest(normalizeAlgName(s), 2);
- } catch (NoSuchAlgorithmException e) {
- throw new Error(e);
- }
- finMD.update(data.toByteArray());
- }
-
- /**
- * Restricts the possible algorithms for the CertificateVerify. Called by
- * the server based on info in CertRequest. The argument must be a subset
- * of the argument with the same name in the constructor. The method can be
- * called multiple times. If the caller is sure that no CertificateVerify
- * message will be used, leave this argument null or empty.
- */
- void restrictCertificateVerifyAlgs(Set<String> algs) {
- if (version == 1) {
- throw new RuntimeException(
- "setCertificateVerifyAlg() cannot be called for TLS 1.1");
- }
- // Not used yet
- }
-
- /**
- * Specifies the hash algorithm used in CertificateVerify.
- * Can be called multiple times.
- */
- void setCertificateVerifyAlg(String s) {
-
- // Can be called multiple times, but only set once
- if (cvAlgDetermined) return;
-
- cvAlg = s == null ? null : normalizeAlgName(s);
- cvAlgDetermined = true;
- }
-
- byte[] getAllHandshakeMessages() {
- return data.toByteArray();
- }
-
- /**
- * Calculates the hash in the CertificateVerify. Must be called right
- * after setCertificateVerifyAlg()
- */
- /*byte[] getCertificateVerifyHash() {
- throw new Error("Do not call getCertificateVerifyHash()");
- }*/
-
- /**
- * Calculates the hash in Finished. Must be called after setFinishedAlg().
- * This method can be called twice, for Finished messages of the server
- * side and client side respectively.
- */
- byte[] getFinishedHash() {
- try {
- return cloneDigest(finMD).digest();
- } catch (Exception e) {
- throw new Error("BAD");
- }
- }
-}
-
-/**
- * A wrapper for MessageDigests that simulates cloning of non-cloneable
- * digests. It uses the standard MessageDigest API and therefore can be used
- * transparently in place of a regular digest.
- *
- * Note that we extend the MessageDigest class directly rather than
- * MessageDigestSpi. This works because MessageDigest was originally designed
- * this way in the JDK 1.1 days which allows us to avoid creating an internal
- * provider.
- *
- * It can be "cloned" a limited number of times, which is specified at
- * construction time. This is achieved by internally maintaining n digests
- * in parallel. Consequently, it is only 1/n-th times as fast as the original
- * digest.
- *
- * Example:
- * MessageDigest md = CloneableDigest.getDigest("SHA", 2);
- * md.update(data1);
- * MessageDigest md2 = (MessageDigest)md.clone();
- * md2.update(data2);
- * byte[] d1 = md2.digest(); // digest of data1 || data2
- * md.update(data3);
- * byte[] d2 = md.digest(); // digest of data1 || data3
- *
- * This class is not thread safe.
- *
- */
-final class CloneableDigest extends MessageDigest implements Cloneable {
-
- /**
- * The individual MessageDigests. Initially, all elements are non-null.
- * When clone() is called, the non-null element with the maximum index is
- * returned and the array element set to null.
- *
- * All non-null element are always in the same state.
- */
- private final MessageDigest[] digests;
-
- private CloneableDigest(MessageDigest digest, int n, String algorithm)
- throws NoSuchAlgorithmException {
- super(algorithm);
- digests = new MessageDigest[n];
- digests[0] = digest;
- for (int i = 1; i < n; i++) {
- digests[i] = JsseJce.getMessageDigest(algorithm);
- }
- }
-
- /**
- * Return a MessageDigest for the given algorithm that can be cloned the
- * specified number of times. If the default implementation supports
- * cloning, it is returned. Otherwise, an instance of this class is
- * returned.
- */
- static MessageDigest getDigest(String algorithm, int n)
- throws NoSuchAlgorithmException {
- MessageDigest digest = JsseJce.getMessageDigest(algorithm);
- try {
- digest.clone();
- // already cloneable, use it
- return digest;
- } catch (CloneNotSupportedException e) {
- return new CloneableDigest(digest, n, algorithm);
- }
- }
-
- /**
- * Check if this object is still usable. If it has already been cloned the
- * maximum number of times, there are no digests left and this object can no
- * longer be used.
- */
- private void checkState() {
- // XXX handshaking currently doesn't stop updating hashes...
- // if (digests[0] == null) {
- // throw new IllegalStateException("no digests left");
- // }
- }
-
- protected int engineGetDigestLength() {
- checkState();
- return digests[0].getDigestLength();
- }
-
- protected void engineUpdate(byte b) {
- checkState();
- for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
- digests[i].update(b);
- }
- }
-
- protected void engineUpdate(byte[] b, int offset, int len) {
- checkState();
- for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
- digests[i].update(b, offset, len);
- }
- }
-
- protected byte[] engineDigest() {
- checkState();
- byte[] digest = digests[0].digest();
- digestReset();
- return digest;
- }
-
- protected int engineDigest(byte[] buf, int offset, int len)
- throws DigestException {
- checkState();
- int n = digests[0].digest(buf, offset, len);
- digestReset();
- return n;
- }
-
- /**
- * Reset all digests after a digest() call. digests[0] has already been
- * implicitly reset by the digest() call and does not need to be reset
- * again.
- */
- private void digestReset() {
- for (int i = 1; (i < digests.length) && (digests[i] != null); i++) {
- digests[i].reset();
- }
- }
-
- protected void engineReset() {
- checkState();
- for (int i = 0; (i < digests.length) && (digests[i] != null); i++) {
- digests[i].reset();
- }
- }
-
- public Object clone() {
- checkState();
- for (int i = digests.length - 1; i >= 0; i--) {
- if (digests[i] != null) {
- MessageDigest digest = digests[i];
- digests[i] = null;
- return digest;
- }
- }
- // cannot occur
- throw new InternalError();
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/HandshakeInStream.java b/ojluni/src/main/java/sun/security/ssl/HandshakeInStream.java
deleted file mode 100755
index 81c8464..0000000
--- a/ojluni/src/main/java/sun/security/ssl/HandshakeInStream.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.security.MessageDigest;
-
-import javax.net.ssl.SSLException;
-
-/**
- * InputStream for handshake data, used internally only. Contains the
- * handshake message buffer and methods to parse them.
- *
- * Once a new handshake record arrives, it is buffered in this class until
- * processed by the Handshaker. The buffer may also contain incomplete
- * handshake messages in case the message is split across multiple records.
- * Handshaker.process_record deals with all that. It may also contain
- * handshake messages larger than the default buffer size (e.g. large
- * certificate messages). The buffer is grown dynamically to handle that
- * (see InputRecord.queueHandshake()).
- *
- * Note that the InputRecord used as a buffer here is separate from the
- * AppInStream.r, which is where data from the socket is initially read
- * into. This is because once the initial handshake has been completed,
- * handshake and application data messages may be interleaved arbitrarily
- * and must be processed independently.
- *
- * @author David Brownell
- */
-public class HandshakeInStream extends InputStream {
-
- InputRecord r;
-
- /*
- * Construct the stream; we'll be accumulating hashes of the
- * input records using two sets of digests.
- */
- HandshakeInStream(HandshakeHash handshakeHash) {
- r = new InputRecord();
- r.setHandshakeHash(handshakeHash);
- }
-
-
- // overridden InputStream methods
-
- /*
- * Return the number of bytes available for read().
- *
- * Note that this returns the bytes remaining in the buffer, not
- * the bytes remaining in the current handshake message.
- */
- public int available() {
- return r.available();
- }
-
- /*
- * Get a byte of handshake data.
- */
- public int read() throws IOException {
- int n = r.read();
- if (n == -1) {
- throw new SSLException("Unexpected end of handshake data");
- }
- return n;
- }
-
- /*
- * Get a bunch of bytes of handshake data.
- */
- public int read(byte b [], int off, int len) throws IOException {
- // we read from a ByteArrayInputStream, it always returns the
- // data in a single read if enough is available
- int n = r.read(b, off, len);
- if (n != len) {
- throw new SSLException("Unexpected end of handshake data");
- }
- return n;
- }
-
- /*
- * Skip some handshake data.
- */
- public long skip(long n) throws IOException {
- return r.skip(n);
- }
-
- /*
- * Mark/ reset code, implemented using InputRecord mark/ reset.
- *
- * Note that it currently provides only a limited mark functionality
- * and should be used with care (once a new handshake record has been
- * read, data that has already been consumed is lost even if marked).
- */
-
- public void mark(int readlimit) {
- r.mark(readlimit);
- }
-
- public void reset() {
- r.reset();
- }
-
- public boolean markSupported() {
- return true;
- }
-
-
- // handshake management functions
-
- /*
- * Here's an incoming record with handshake data. Queue the contents;
- * it might be one or more entire messages, complete a message that's
- * partly queued, or both.
- */
- void incomingRecord(InputRecord in) throws IOException {
- r.queueHandshake(in);
- }
-
- /*
- * Hash any data we've consumed but not yet hashed. Useful mostly
- * for processing client certificate messages (so we can check the
- * immediately following cert verify message) and finished messages
- * (so we can compute our own finished message).
- */
- void digestNow() {
- r.doHashes();
- }
-
- /*
- * Do more than skip that handshake data ... totally ignore it.
- * The difference is that the data does not get hashed.
- */
- void ignore(int n) {
- r.ignore(n);
- }
-
-
- // Message parsing methods
-
- /*
- * Read 8, 16, 24, and 32 bit SSL integer data types, encoded
- * in standard big-endian form.
- */
-
- int getInt8() throws IOException {
- return read();
- }
-
- int getInt16() throws IOException {
- return (getInt8() << 8) | getInt8();
- }
-
- int getInt24() throws IOException {
- return (getInt8() << 16) | (getInt8() << 8) | getInt8();
- }
-
- int getInt32() throws IOException {
- return (getInt8() << 24) | (getInt8() << 16)
- | (getInt8() << 8) | getInt8();
- }
-
- /*
- * Read byte vectors with 8, 16, and 24 bit length encodings.
- */
-
- byte[] getBytes8() throws IOException {
- int len = getInt8();
- verifyLength(len);
- byte b[] = new byte[len];
-
- read(b, 0, len);
- return b;
- }
-
- public byte[] getBytes16() throws IOException {
- int len = getInt16();
- verifyLength(len);
- byte b[] = new byte[len];
-
- read(b, 0, len);
- return b;
- }
-
- byte[] getBytes24() throws IOException {
- int len = getInt24();
- verifyLength(len);
- byte b[] = new byte[len];
-
- read(b, 0, len);
- return b;
- }
-
- // Is a length greater than available bytes in the record?
- private void verifyLength(int len) throws SSLException {
- if (len > available()) {
- throw new SSLException(
- "Not enough data to fill declared vector size");
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/HandshakeMessage.java b/ojluni/src/main/java/sun/security/ssl/HandshakeMessage.java
deleted file mode 100755
index 1c85a03..0000000
--- a/ojluni/src/main/java/sun/security/ssl/HandshakeMessage.java
+++ /dev/null
@@ -1,2018 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.math.BigInteger;
-import java.security.*;
-import java.security.interfaces.*;
-import java.security.spec.*;
-import java.security.cert.*;
-import java.security.cert.Certificate;
-import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-
-import java.lang.reflect.*;
-
-import javax.security.auth.x500.X500Principal;
-
-import javax.crypto.KeyGenerator;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.DHPublicKeySpec;
-
-import javax.net.ssl.*;
-
-import sun.security.internal.spec.TlsPrfParameterSpec;
-import sun.security.ssl.CipherSuite.*;
-import static sun.security.ssl.CipherSuite.PRF.*;
-import sun.security.util.KeyUtil;
-
-/**
- * Many data structures are involved in the handshake messages. These
- * classes are used as structures, with public data members. They are
- * not visible outside the SSL package.
- *
- * Handshake messages all have a common header format, and they are all
- * encoded in a "handshake data" SSL record substream. The base class
- * here (HandshakeMessage) provides a common framework and records the
- * SSL record type of the particular handshake message.
- *
- * This file contains subclasses for all the basic handshake messages.
- * All handshake messages know how to encode and decode themselves on
- * SSL streams; this facilitates using the same code on SSL client and
- * server sides, although they don't send and receive the same messages.
- *
- * Messages also know how to print themselves, which is quite handy
- * for debugging. They always identify their type, and can optionally
- * dump all of their content.
- *
- * @author David Brownell
- */
-public abstract class HandshakeMessage {
-
- HandshakeMessage() { }
-
- // enum HandshakeType:
- static final byte ht_hello_request = 0;
- static final byte ht_client_hello = 1;
- static final byte ht_server_hello = 2;
-
- static final byte ht_certificate = 11;
- static final byte ht_server_key_exchange = 12;
- static final byte ht_certificate_request = 13;
- static final byte ht_server_hello_done = 14;
- static final byte ht_certificate_verify = 15;
- static final byte ht_client_key_exchange = 16;
-
- static final byte ht_finished = 20;
-
- /* Class and subclass dynamic debugging support */
- public static final Debug debug = Debug.getInstance("ssl");
-
- /**
- * Utility method to convert a BigInteger to a byte array in unsigned
- * format as needed in the handshake messages. BigInteger uses
- * 2's complement format, i.e. it prepends an extra zero if the MSB
- * is set. We remove that.
- */
- static byte[] toByteArray(BigInteger bi) {
- byte[] b = bi.toByteArray();
- if ((b.length > 1) && (b[0] == 0)) {
- int n = b.length - 1;
- byte[] newarray = new byte[n];
- System.arraycopy(b, 1, newarray, 0, n);
- b = newarray;
- }
- return b;
- }
-
- /*
- * SSL 3.0 MAC padding constants.
- * Also used by CertificateVerify and Finished during the handshake.
- */
- static final byte[] MD5_pad1 = genPad(0x36, 48);
- static final byte[] MD5_pad2 = genPad(0x5c, 48);
-
- static final byte[] SHA_pad1 = genPad(0x36, 40);
- static final byte[] SHA_pad2 = genPad(0x5c, 40);
-
- private static byte[] genPad(int b, int count) {
- byte[] padding = new byte[count];
- Arrays.fill(padding, (byte)b);
- return padding;
- }
-
- /*
- * Write a handshake message on the (handshake) output stream.
- * This is just a four byte header followed by the data.
- *
- * NOTE that huge messages -- notably, ones with huge cert
- * chains -- are handled correctly.
- */
- final void write(HandshakeOutStream s) throws IOException {
- int len = messageLength();
- if (len >= Record.OVERFLOW_OF_INT24) {
- throw new SSLException("Handshake message too big"
- + ", type = " + messageType() + ", len = " + len);
- }
- s.write(messageType());
- s.putInt24(len);
- send(s);
- }
-
- /*
- * Subclasses implement these methods so those kinds of
- * messages can be emitted. Base class delegates to subclass.
- */
- abstract int messageType();
- abstract int messageLength();
- abstract void send(HandshakeOutStream s) throws IOException;
-
- /*
- * Write a descriptive message on the output stream; for debugging.
- */
- abstract void print(PrintStream p) throws IOException;
-
-//
-// NOTE: the rest of these classes are nested within this one, and are
-// imported by other classes in this package. There are a few other
-// handshake message classes, not neatly nested here because of current
-// licensing requirement for native (RSA) methods. They belong here,
-// but those native methods complicate things a lot!
-//
-
-
-/*
- * HelloRequest ... SERVER --> CLIENT
- *
- * Server can ask the client to initiate a new handshake, e.g. to change
- * session parameters after a connection has been (re)established.
- */
-static final class HelloRequest extends HandshakeMessage {
- int messageType() { return ht_hello_request; }
-
- HelloRequest() { }
-
- HelloRequest(HandshakeInStream in) throws IOException
- {
- // nothing in this message
- }
-
- int messageLength() { return 0; }
-
- void send(HandshakeOutStream out) throws IOException
- {
- // nothing in this messaage
- }
-
- void print(PrintStream out) throws IOException
- {
- out.println("*** HelloRequest (empty)");
- }
-
-}
-
-
-/*
- * ClientHello ... CLIENT --> SERVER
- *
- * Client initiates handshake by telling server what it wants, and what it
- * can support (prioritized by what's first in the ciphe suite list).
- *
- * By RFC2246:7.4.1.2 it's explicitly anticipated that this message
- * will have more data added at the end ... e.g. what CAs the client trusts.
- * Until we know how to parse it, we will just read what we know
- * about, and let our caller handle the jumps over unknown data.
- */
-static final class ClientHello extends HandshakeMessage {
-
- ProtocolVersion protocolVersion;
- RandomCookie clnt_random;
- SessionId sessionId;
- private CipherSuiteList cipherSuites;
- byte[] compression_methods;
-
- HelloExtensions extensions = new HelloExtensions();
-
- private final static byte[] NULL_COMPRESSION = new byte[] {0};
-
- ClientHello(SecureRandom generator, ProtocolVersion protocolVersion,
- SessionId sessionId, CipherSuiteList cipherSuites) {
-
- this.protocolVersion = protocolVersion;
- this.sessionId = sessionId;
- this.cipherSuites = cipherSuites;
-
- if (cipherSuites.containsEC()) {
- extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
- extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT);
- }
-
- clnt_random = new RandomCookie(generator);
- compression_methods = NULL_COMPRESSION;
- }
-
- ClientHello(HandshakeInStream s, int messageLength) throws IOException {
- protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8());
- clnt_random = new RandomCookie(s);
- sessionId = new SessionId(s.getBytes8());
- cipherSuites = new CipherSuiteList(s);
- compression_methods = s.getBytes8();
- if (messageLength() != messageLength) {
- extensions = new HelloExtensions(s);
- }
- }
-
- CipherSuiteList getCipherSuites() {
- return cipherSuites;
- }
-
- // add renegotiation_info extension
- void addRenegotiationInfoExtension(byte[] clientVerifyData) {
- HelloExtension renegotiationInfo = new RenegotiationInfoExtension(
- clientVerifyData, new byte[0]);
- extensions.add(renegotiationInfo);
- }
-
- // add server_name extension
- void addServerNameIndicationExtension(String hostname) {
- // We would have checked that the hostname ia a FQDN.
- ArrayList<String> hostnames = new ArrayList<>(1);
- hostnames.add(hostname);
-
- try {
- extensions.add(new ServerNameExtension(hostnames));
- } catch (IOException ioe) {
- // ignore the exception and return
- }
- }
-
- // add signature_algorithm extension
- void addSignatureAlgorithmsExtension(
- Collection<SignatureAndHashAlgorithm> algorithms) {
- HelloExtension signatureAlgorithm =
- new SignatureAlgorithmsExtension(algorithms);
- extensions.add(signatureAlgorithm);
- }
-
- @Override
- int messageType() { return ht_client_hello; }
-
- @Override
- int messageLength() {
- /*
- * Add fixed size parts of each field...
- * version + random + session + cipher + compress
- */
- return (2 + 32 + 1 + 2 + 1
- + sessionId.length() /* ... + variable parts */
- + (cipherSuites.size() * 2)
- + compression_methods.length)
- + extensions.length();
- }
-
- @Override
- void send(HandshakeOutStream s) throws IOException {
- s.putInt8(protocolVersion.major);
- s.putInt8(protocolVersion.minor);
- clnt_random.send(s);
- s.putBytes8(sessionId.getId());
- cipherSuites.send(s);
- s.putBytes8(compression_methods);
- extensions.send(s);
- }
-
- @Override
- void print(PrintStream s) throws IOException {
- s.println("*** ClientHello, " + protocolVersion);
-
- if (debug != null && Debug.isOn("verbose")) {
- s.print("RandomCookie: ");
- clnt_random.print(s);
-
- s.print("Session ID: ");
- s.println(sessionId);
-
- s.println("Cipher Suites: " + cipherSuites);
-
- Debug.println(s, "Compression Methods", compression_methods);
- extensions.print(s);
- s.println("***");
- }
- }
-}
-
-/*
- * ServerHello ... SERVER --> CLIENT
- *
- * Server chooses protocol options from among those it supports and the
- * client supports. Then it sends the basic session descriptive parameters
- * back to the client.
- */
-static final
-class ServerHello extends HandshakeMessage
-{
- int messageType() { return ht_server_hello; }
-
- ProtocolVersion protocolVersion;
- RandomCookie svr_random;
- SessionId sessionId;
- CipherSuite cipherSuite;
- byte compression_method;
- HelloExtensions extensions = new HelloExtensions();
-
- ServerHello() {
- // empty
- }
-
- ServerHello(HandshakeInStream input, int messageLength)
- throws IOException {
- protocolVersion = ProtocolVersion.valueOf(input.getInt8(),
- input.getInt8());
- svr_random = new RandomCookie(input);
- sessionId = new SessionId(input.getBytes8());
- cipherSuite = CipherSuite.valueOf(input.getInt8(), input.getInt8());
- compression_method = (byte)input.getInt8();
- if (messageLength() != messageLength) {
- extensions = new HelloExtensions(input);
- }
- }
-
- int messageLength()
- {
- // almost fixed size, except session ID and extensions:
- // major + minor = 2
- // random = 32
- // session ID len field = 1
- // cipher suite + compression = 3
- // extensions: if present, 2 + length of extensions
- return 38 + sessionId.length() + extensions.length();
- }
-
- void send(HandshakeOutStream s) throws IOException
- {
- s.putInt8(protocolVersion.major);
- s.putInt8(protocolVersion.minor);
- svr_random.send(s);
- s.putBytes8(sessionId.getId());
- s.putInt8(cipherSuite.id >> 8);
- s.putInt8(cipherSuite.id & 0xff);
- s.putInt8(compression_method);
- extensions.send(s);
- }
-
- void print(PrintStream s) throws IOException
- {
- s.println("*** ServerHello, " + protocolVersion);
-
- if (debug != null && Debug.isOn("verbose")) {
- s.print("RandomCookie: ");
- svr_random.print(s);
-
- int i;
-
- s.print("Session ID: ");
- s.println(sessionId);
-
- s.println("Cipher Suite: " + cipherSuite);
- s.println("Compression Method: " + compression_method);
- extensions.print(s);
- s.println("***");
- }
- }
-}
-
-
-/*
- * CertificateMsg ... send by both CLIENT and SERVER
- *
- * Each end of a connection may need to pass its certificate chain to
- * the other end. Such chains are intended to validate an identity with
- * reference to some certifying authority. Examples include companies
- * like Verisign, or financial institutions. There's some control over
- * the certifying authorities which are sent.
- *
- * NOTE: that these messages might be huge, taking many handshake records.
- * Up to 2^48 bytes of certificate may be sent, in records of at most 2^14
- * bytes each ... up to 2^32 records sent on the output stream.
- */
-static final
-class CertificateMsg extends HandshakeMessage
-{
- int messageType() { return ht_certificate; }
-
- private X509Certificate[] chain;
-
- private List<byte[]> encodedChain;
-
- private int messageLength;
-
- CertificateMsg(X509Certificate[] certs) {
- chain = certs;
- }
-
- CertificateMsg(HandshakeInStream input) throws IOException {
- int chainLen = input.getInt24();
- List<Certificate> v = new ArrayList<>(4);
-
- CertificateFactory cf = null;
- while (chainLen > 0) {
- byte[] cert = input.getBytes24();
- chainLen -= (3 + cert.length);
- try {
- if (cf == null) {
- cf = CertificateFactory.getInstance("X.509");
- }
- v.add(cf.generateCertificate(new ByteArrayInputStream(cert)));
- } catch (CertificateException e) {
- throw (SSLProtocolException)new SSLProtocolException(
- e.getMessage()).initCause(e);
- }
- }
-
- chain = v.toArray(new X509Certificate[v.size()]);
- }
-
- int messageLength() {
- if (encodedChain == null) {
- messageLength = 3;
- encodedChain = new ArrayList<byte[]>(chain.length);
- try {
- for (X509Certificate cert : chain) {
- byte[] b = cert.getEncoded();
- encodedChain.add(b);
- messageLength += b.length + 3;
- }
- } catch (CertificateEncodingException e) {
- encodedChain = null;
- throw new RuntimeException("Could not encode certificates", e);
- }
- }
- return messageLength;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putInt24(messageLength() - 3);
- for (byte[] b : encodedChain) {
- s.putBytes24(b);
- }
- }
-
- void print(PrintStream s) throws IOException {
- s.println("*** Certificate chain");
-
- if (debug != null && Debug.isOn("verbose")) {
- for (int i = 0; i < chain.length; i++)
- s.println("chain [" + i + "] = " + chain[i]);
- s.println("***");
- }
- }
-
- X509Certificate[] getCertificateChain() {
- return chain.clone();
- }
-}
-
-/*
- * ServerKeyExchange ... SERVER --> CLIENT
- *
- * The cipher suite selected, when combined with the certificate exchanged,
- * implies one of several different kinds of key exchange. Most current
- * cipher suites require the server to send more than its certificate.
- *
- * The primary exceptions are when a server sends an encryption-capable
- * RSA public key in its cert, to be used with RSA (or RSA_export) key
- * exchange; and when a server sends its Diffie-Hellman cert. Those kinds
- * of key exchange do not require a ServerKeyExchange message.
- *
- * Key exchange can be viewed as having three modes, which are explicit
- * for the Diffie-Hellman flavors and poorly specified for RSA ones:
- *
- * - "Ephemeral" keys. Here, a "temporary" key is allocated by the
- * server, and signed. Diffie-Hellman keys signed using RSA or
- * DSS are ephemeral (DHE flavor). RSA keys get used to do the same
- * thing, to cut the key size down to 512 bits (export restrictions)
- * or for signing-only RSA certificates.
- *
- * - Anonymity. Here no server certificate is sent, only the public
- * key of the server. This case is subject to man-in-the-middle
- * attacks. This can be done with Diffie-Hellman keys (DH_anon) or
- * with RSA keys, but is only used in SSLv3 for DH_anon.
- *
- * - "Normal" case. Here a server certificate is sent, and the public
- * key there is used directly in exchanging the premaster secret.
- * For example, Diffie-Hellman "DH" flavor, and any RSA flavor with
- * only 512 bit keys.
- *
- * If a server certificate is sent, there is no anonymity. However,
- * when a certificate is sent, ephemeral keys may still be used to
- * exchange the premaster secret. That's how RSA_EXPORT often works,
- * as well as how the DHE_* flavors work.
- */
-static abstract class ServerKeyExchange extends HandshakeMessage
-{
- int messageType() { return ht_server_key_exchange; }
-}
-
-
-/*
- * Using RSA for Key Exchange: exchange a session key that's not as big
- * as the signing-only key. Used for export applications, since exported
- * RSA encryption keys can't be bigger than 512 bytes.
- *
- * This is never used when keys are 512 bits or smaller, and isn't used
- * on "US Domestic" ciphers in any case.
- */
-static final
-class RSA_ServerKeyExchange extends ServerKeyExchange
-{
- private byte rsa_modulus[]; // 1 to 2^16 - 1 bytes
- private byte rsa_exponent[]; // 1 to 2^16 - 1 bytes
-
- private Signature signature;
- private byte[] signatureBytes;
-
- /*
- * Hash the nonces and the ephemeral RSA public key.
- */
- private void updateSignature(byte clntNonce[], byte svrNonce[])
- throws SignatureException {
- int tmp;
-
- signature.update(clntNonce);
- signature.update(svrNonce);
-
- tmp = rsa_modulus.length;
- signature.update((byte)(tmp >> 8));
- signature.update((byte)(tmp & 0x0ff));
- signature.update(rsa_modulus);
-
- tmp = rsa_exponent.length;
- signature.update((byte)(tmp >> 8));
- signature.update((byte)(tmp & 0x0ff));
- signature.update(rsa_exponent);
- }
-
-
- /*
- * Construct an RSA server key exchange message, using data
- * known _only_ to the server.
- *
- * The client knows the public key corresponding to this private
- * key, from the Certificate message sent previously. To comply
- * with US export regulations we use short RSA keys ... either
- * long term ones in the server's X509 cert, or else ephemeral
- * ones sent using this message.
- */
- RSA_ServerKeyExchange(PublicKey ephemeralKey, PrivateKey privateKey,
- RandomCookie clntNonce, RandomCookie svrNonce, SecureRandom sr)
- throws GeneralSecurityException {
- RSAPublicKeySpec rsaKey = JsseJce.getRSAPublicKeySpec(ephemeralKey);
- rsa_modulus = toByteArray(rsaKey.getModulus());
- rsa_exponent = toByteArray(rsaKey.getPublicExponent());
- signature = RSASignature.getInstance();
- signature.initSign(privateKey, sr);
- updateSignature(clntNonce.random_bytes, svrNonce.random_bytes);
- signatureBytes = signature.sign();
- }
-
-
- /*
- * Parse an RSA server key exchange message, using data known
- * to the client (and, in some situations, eavesdroppers).
- */
- RSA_ServerKeyExchange(HandshakeInStream input)
- throws IOException, NoSuchAlgorithmException {
- signature = RSASignature.getInstance();
- rsa_modulus = input.getBytes16();
- rsa_exponent = input.getBytes16();
- signatureBytes = input.getBytes16();
- }
-
- /*
- * Get the ephemeral RSA public key that will be used in this
- * SSL connection.
- */
- PublicKey getPublicKey() {
- try {
- KeyFactory kfac = JsseJce.getKeyFactory("RSA");
- // modulus and exponent are always positive
- RSAPublicKeySpec kspec = new RSAPublicKeySpec(
- new BigInteger(1, rsa_modulus),
- new BigInteger(1, rsa_exponent));
- return kfac.generatePublic(kspec);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- /*
- * Verify the signed temporary key using the hashes computed
- * from it and the two nonces. This is called by clients
- * with "exportable" RSA flavors.
- */
- boolean verify(PublicKey certifiedKey, RandomCookie clntNonce,
- RandomCookie svrNonce) throws GeneralSecurityException {
- signature.initVerify(certifiedKey);
- updateSignature(clntNonce.random_bytes, svrNonce.random_bytes);
- return signature.verify(signatureBytes);
- }
-
- int messageLength() {
- return 6 + rsa_modulus.length + rsa_exponent.length
- + signatureBytes.length;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putBytes16(rsa_modulus);
- s.putBytes16(rsa_exponent);
- s.putBytes16(signatureBytes);
- }
-
- void print(PrintStream s) throws IOException {
- s.println("*** RSA ServerKeyExchange");
-
- if (debug != null && Debug.isOn("verbose")) {
- Debug.println(s, "RSA Modulus", rsa_modulus);
- Debug.println(s, "RSA Public Exponent", rsa_exponent);
- }
- }
-}
-
-
-/*
- * Using Diffie-Hellman algorithm for key exchange. All we really need to
- * do is securely get Diffie-Hellman keys (using the same P, G parameters)
- * to our peer, then we automatically have a shared secret without need
- * to exchange any more data. (D-H only solutions, such as SKIP, could
- * eliminate key exchange negotiations and get faster connection setup.
- * But they still need a signature algorithm like DSS/DSA to support the
- * trusted distribution of keys without relying on unscalable physical
- * key distribution systems.)
- *
- * This class supports several DH-based key exchange algorithms, though
- * perhaps eventually each deserves its own class. Notably, this has
- * basic support for DH_anon and its DHE_DSS and DHE_RSA signed variants.
- */
-static final
-class DH_ServerKeyExchange extends ServerKeyExchange
-{
- // Fix message encoding, see 4348279
- private final static boolean dhKeyExchangeFix =
- Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true);
-
- private byte dh_p []; // 1 to 2^16 - 1 bytes
- private byte dh_g []; // 1 to 2^16 - 1 bytes
- private byte dh_Ys []; // 1 to 2^16 - 1 bytes
-
- private byte signature [];
-
- // protocol version being established using this ServerKeyExchange message
- ProtocolVersion protocolVersion;
-
- // the preferable signature algorithm used by this ServerKeyExchange message
- private SignatureAndHashAlgorithm preferableSignatureAlgorithm;
-
- /*
- * Construct from initialized DH key object, for DH_anon
- * key exchange.
- */
- DH_ServerKeyExchange(DHCrypt obj, ProtocolVersion protocolVersion) {
- this.protocolVersion = protocolVersion;
- this.preferableSignatureAlgorithm = null;
-
- // The DH key has been validated in the constructor of DHCrypt.
- setValues(obj);
- signature = null;
- }
-
- /*
- * Construct from initialized DH key object and the key associated
- * with the cert chain which was sent ... for DHE_DSS and DHE_RSA
- * key exchange. (Constructor called by server.)
- */
- DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[],
- byte svrNonce[], SecureRandom sr,
- SignatureAndHashAlgorithm signAlgorithm,
- ProtocolVersion protocolVersion) throws GeneralSecurityException {
-
- this.protocolVersion = protocolVersion;
-
- // The DH key has been validated in the constructor of DHCrypt.
- setValues(obj);
-
- Signature sig;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- this.preferableSignatureAlgorithm = signAlgorithm;
- sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
- } else {
- this.preferableSignatureAlgorithm = null;
- if (key.getAlgorithm().equals("DSA")) {
- sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
- } else {
- sig = RSASignature.getInstance();
- }
- }
-
- sig.initSign(key, sr);
- updateSignature(sig, clntNonce, svrNonce);
- signature = sig.sign();
- }
-
- /*
- * Construct a DH_ServerKeyExchange message from an input
- * stream, as if sent from server to client for use with
- * DH_anon key exchange
- */
- DH_ServerKeyExchange(HandshakeInStream input,
- ProtocolVersion protocolVersion)
- throws IOException, GeneralSecurityException {
-
- this.protocolVersion = protocolVersion;
- this.preferableSignatureAlgorithm = null;
-
- dh_p = input.getBytes16();
- dh_g = input.getBytes16();
- dh_Ys = input.getBytes16();
- KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys),
- new BigInteger(1, dh_p),
- new BigInteger(1, dh_g)));
-
- signature = null;
- }
-
- /*
- * Construct a DH_ServerKeyExchange message from an input stream
- * and a certificate, as if sent from server to client for use with
- * DHE_DSS or DHE_RSA key exchange. (Called by client.)
- */
- DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey,
- byte clntNonce[], byte svrNonce[], int messageSize,
- Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
- ProtocolVersion protocolVersion)
- throws IOException, GeneralSecurityException {
-
- this.protocolVersion = protocolVersion;
-
- // read params: ServerDHParams
- dh_p = input.getBytes16();
- dh_g = input.getBytes16();
- dh_Ys = input.getBytes16();
- KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys),
- new BigInteger(1, dh_p),
- new BigInteger(1, dh_g)));
-
- // read the signature and hash algorithm
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- int hash = input.getInt8(); // hash algorithm
- int signature = input.getInt8(); // signature algorithm
-
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.valueOf(hash, signature, 0);
-
- // Is it a local supported signature algorithm?
- if (!localSupportedSignAlgs.contains(
- preferableSignatureAlgorithm)) {
- throw new SSLHandshakeException(
- "Unsupported SignatureAndHashAlgorithm in " +
- "ServerKeyExchange message");
- }
- } else {
- this.preferableSignatureAlgorithm = null;
- }
-
- // read the signature
- byte signature[];
- if (dhKeyExchangeFix) {
- signature = input.getBytes16();
- } else {
- messageSize -= (dh_p.length + 2);
- messageSize -= (dh_g.length + 2);
- messageSize -= (dh_Ys.length + 2);
-
- signature = new byte[messageSize];
- input.read(signature);
- }
-
- Signature sig;
- String algorithm = publicKey.getAlgorithm();
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- sig = JsseJce.getSignature(
- preferableSignatureAlgorithm.getAlgorithmName());
- } else {
- if (algorithm.equals("DSA")) {
- sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA);
- } else if (algorithm.equals("RSA")) {
- sig = RSASignature.getInstance();
- } else {
- throw new SSLKeyException("neither an RSA or a DSA key");
- }
- }
-
- sig.initVerify(publicKey);
- updateSignature(sig, clntNonce, svrNonce);
-
- if (sig.verify(signature) == false ) {
- throw new SSLKeyException("Server D-H key verification failed");
- }
- }
-
- /* Return the Diffie-Hellman modulus */
- BigInteger getModulus() {
- return new BigInteger(1, dh_p);
- }
-
- /* Return the Diffie-Hellman base/generator */
- BigInteger getBase() {
- return new BigInteger(1, dh_g);
- }
-
- /* Return the server's Diffie-Hellman public key */
- BigInteger getServerPublicKey() {
- return new BigInteger(1, dh_Ys);
- }
-
- /*
- * Update sig with nonces and Diffie-Hellman public key.
- */
- private void updateSignature(Signature sig, byte clntNonce[],
- byte svrNonce[]) throws SignatureException {
- int tmp;
-
- sig.update(clntNonce);
- sig.update(svrNonce);
-
- tmp = dh_p.length;
- sig.update((byte)(tmp >> 8));
- sig.update((byte)(tmp & 0x0ff));
- sig.update(dh_p);
-
- tmp = dh_g.length;
- sig.update((byte)(tmp >> 8));
- sig.update((byte)(tmp & 0x0ff));
- sig.update(dh_g);
-
- tmp = dh_Ys.length;
- sig.update((byte)(tmp >> 8));
- sig.update((byte)(tmp & 0x0ff));
- sig.update(dh_Ys);
- }
-
- private void setValues(DHCrypt obj) {
- dh_p = toByteArray(obj.getModulus());
- dh_g = toByteArray(obj.getBase());
- dh_Ys = toByteArray(obj.getPublicKey());
- }
-
- int messageLength() {
- int temp = 6; // overhead for p, g, y(s) values.
-
- temp += dh_p.length;
- temp += dh_g.length;
- temp += dh_Ys.length;
-
- if (signature != null) {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- temp += SignatureAndHashAlgorithm.sizeInRecord();
- }
-
- temp += signature.length;
- if (dhKeyExchangeFix) {
- temp += 2;
- }
- }
-
- return temp;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putBytes16(dh_p);
- s.putBytes16(dh_g);
- s.putBytes16(dh_Ys);
-
- if (signature != null) {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- s.putInt8(preferableSignatureAlgorithm.getHashValue());
- s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
- }
-
- if (dhKeyExchangeFix) {
- s.putBytes16(signature);
- } else {
- s.write(signature);
- }
- }
- }
-
- void print(PrintStream s) throws IOException {
- s.println("*** Diffie-Hellman ServerKeyExchange");
-
- if (debug != null && Debug.isOn("verbose")) {
- Debug.println(s, "DH Modulus", dh_p);
- Debug.println(s, "DH Base", dh_g);
- Debug.println(s, "Server DH Public Key", dh_Ys);
-
- if (signature == null) {
- s.println("Anonymous");
- } else {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- s.println("Signature Algorithm " +
- preferableSignatureAlgorithm.getAlgorithmName());
- }
-
- s.println("Signed with a DSA or RSA public key");
- }
- }
- }
-}
-
-/*
- * ECDH server key exchange message. Sent by the server for ECDHE and ECDH_anon
- * ciphersuites to communicate its ephemeral public key (including the
- * EC domain parameters).
- *
- * We support named curves only, no explicitly encoded curves.
- */
-static final
-class ECDH_ServerKeyExchange extends ServerKeyExchange {
-
- // constants for ECCurveType
- private final static int CURVE_EXPLICIT_PRIME = 1;
- private final static int CURVE_EXPLICIT_CHAR2 = 2;
- private final static int CURVE_NAMED_CURVE = 3;
-
- // id of the curve we are using
- private int curveId;
- // encoded public point
- private byte[] pointBytes;
-
- // signature bytes (or null if anonymous)
- private byte[] signatureBytes;
-
- // public key object encapsulated in this message
- private ECPublicKey publicKey;
-
- // protocol version being established using this ServerKeyExchange message
- ProtocolVersion protocolVersion;
-
- // the preferable signature algorithm used by this ServerKeyExchange message
- private SignatureAndHashAlgorithm preferableSignatureAlgorithm;
-
- ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey,
- byte[] clntNonce, byte[] svrNonce, SecureRandom sr,
- SignatureAndHashAlgorithm signAlgorithm,
- ProtocolVersion protocolVersion) throws GeneralSecurityException {
-
- this.protocolVersion = protocolVersion;
-
- publicKey = (ECPublicKey)obj.getPublicKey();
- ECParameterSpec params = publicKey.getParams();
- ECPoint point = publicKey.getW();
- pointBytes = JsseJce.encodePoint(point, params.getCurve());
- curveId = SupportedEllipticCurvesExtension.getCurveIndex(params);
-
- if (privateKey == null) {
- // ECDH_anon
- return;
- }
-
- Signature sig;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- this.preferableSignatureAlgorithm = signAlgorithm;
- sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
- } else {
- sig = getSignature(privateKey.getAlgorithm());
- }
- sig.initSign(privateKey); // where is the SecureRandom?
-
- updateSignature(sig, clntNonce, svrNonce);
- signatureBytes = sig.sign();
- }
-
- /*
- * Parse an ECDH server key exchange message.
- */
- ECDH_ServerKeyExchange(HandshakeInStream input, PublicKey signingKey,
- byte[] clntNonce, byte[] svrNonce,
- Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
- ProtocolVersion protocolVersion)
- throws IOException, GeneralSecurityException {
-
- this.protocolVersion = protocolVersion;
-
- // read params: ServerECDHParams
- int curveType = input.getInt8();
- ECParameterSpec parameters;
- // These parsing errors should never occur as we negotiated
- // the supported curves during the exchange of the Hello messages.
- if (curveType == CURVE_NAMED_CURVE) {
- curveId = input.getInt16();
- if (SupportedEllipticCurvesExtension.isSupported(curveId)
- == false) {
- throw new SSLHandshakeException(
- "Unsupported curveId: " + curveId);
- }
- String curveOid =
- SupportedEllipticCurvesExtension.getCurveOid(curveId);
- if (curveOid == null) {
- throw new SSLHandshakeException(
- "Unknown named curve: " + curveId);
- }
- parameters = JsseJce.getECParameterSpec(curveOid);
- if (parameters == null) {
- throw new SSLHandshakeException(
- "Unsupported curve: " + curveOid);
- }
- } else {
- throw new SSLHandshakeException(
- "Unsupported ECCurveType: " + curveType);
- }
- pointBytes = input.getBytes8();
-
- ECPoint point = JsseJce.decodePoint(pointBytes, parameters.getCurve());
- KeyFactory factory = JsseJce.getKeyFactory("EC");
- publicKey = (ECPublicKey)factory.generatePublic(
- new ECPublicKeySpec(point, parameters));
-
- if (signingKey == null) {
- // ECDH_anon
- return;
- }
-
- // read the signature and hash algorithm
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- int hash = input.getInt8(); // hash algorithm
- int signature = input.getInt8(); // signature algorithm
-
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.valueOf(hash, signature, 0);
-
- // Is it a local supported signature algorithm?
- if (!localSupportedSignAlgs.contains(
- preferableSignatureAlgorithm)) {
- throw new SSLHandshakeException(
- "Unsupported SignatureAndHashAlgorithm in " +
- "ServerKeyExchange message");
- }
- }
-
- // read the signature
- signatureBytes = input.getBytes16();
-
- // verify the signature
- Signature sig;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- sig = JsseJce.getSignature(
- preferableSignatureAlgorithm.getAlgorithmName());
- } else {
- sig = getSignature(signingKey.getAlgorithm());
- }
- sig.initVerify(signingKey);
-
- updateSignature(sig, clntNonce, svrNonce);
-
- if (sig.verify(signatureBytes) == false ) {
- throw new SSLKeyException(
- "Invalid signature on ECDH server key exchange message");
- }
- }
-
- /*
- * Get the ephemeral EC public key encapsulated in this message.
- */
- ECPublicKey getPublicKey() {
- return publicKey;
- }
-
- private static Signature getSignature(String keyAlgorithm)
- throws NoSuchAlgorithmException {
- if (keyAlgorithm.equals("EC")) {
- return JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA);
- } else if (keyAlgorithm.equals("RSA")) {
- return RSASignature.getInstance();
- } else {
- throw new NoSuchAlgorithmException("neither an RSA or a EC key");
- }
- }
-
- private void updateSignature(Signature sig, byte clntNonce[],
- byte svrNonce[]) throws SignatureException {
- sig.update(clntNonce);
- sig.update(svrNonce);
-
- sig.update((byte)CURVE_NAMED_CURVE);
- sig.update((byte)(curveId >> 8));
- sig.update((byte)curveId);
- sig.update((byte)pointBytes.length);
- sig.update(pointBytes);
- }
-
- int messageLength() {
- int sigLen = 0;
- if (signatureBytes != null) {
- sigLen = 2 + signatureBytes.length;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- sigLen += SignatureAndHashAlgorithm.sizeInRecord();
- }
- }
-
- return 4 + pointBytes.length + sigLen;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putInt8(CURVE_NAMED_CURVE);
- s.putInt16(curveId);
- s.putBytes8(pointBytes);
-
- if (signatureBytes != null) {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- s.putInt8(preferableSignatureAlgorithm.getHashValue());
- s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
- }
-
- s.putBytes16(signatureBytes);
- }
- }
-
- void print(PrintStream s) throws IOException {
- s.println("*** ECDH ServerKeyExchange");
-
- if (debug != null && Debug.isOn("verbose")) {
- if (signatureBytes == null) {
- s.println("Anonymous");
- } else {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- s.println("Signature Algorithm " +
- preferableSignatureAlgorithm.getAlgorithmName());
- }
- }
-
- s.println("Server key: " + publicKey);
- }
- }
-}
-
-static final class DistinguishedName {
-
- /*
- * DER encoded distinguished name.
- * TLS requires that its not longer than 65535 bytes.
- */
- byte name[];
-
- DistinguishedName(HandshakeInStream input) throws IOException {
- name = input.getBytes16();
- }
-
- DistinguishedName(X500Principal dn) {
- name = dn.getEncoded();
- }
-
- X500Principal getX500Principal() throws IOException {
- try {
- return new X500Principal(name);
- } catch (IllegalArgumentException e) {
- throw (SSLProtocolException)new SSLProtocolException(
- e.getMessage()).initCause(e);
- }
- }
-
- int length() {
- return 2 + name.length;
- }
-
- void send(HandshakeOutStream output) throws IOException {
- output.putBytes16(name);
- }
-
- void print(PrintStream output) throws IOException {
- X500Principal principal = new X500Principal(name);
- output.println("<" + principal.toString() + ">");
- }
-}
-
-/*
- * CertificateRequest ... SERVER --> CLIENT
- *
- * Authenticated servers may ask clients to authenticate themselves
- * in turn, using this message.
- *
- * Prior to TLS 1.2, the structure of the message is defined as:
- * struct {
- * ClientCertificateType certificate_types<1..2^8-1>;
- * DistinguishedName certificate_authorities<0..2^16-1>;
- * } CertificateRequest;
- *
- * In TLS 1.2, the structure is changed to:
- * struct {
- * ClientCertificateType certificate_types<1..2^8-1>;
- * SignatureAndHashAlgorithm
- * supported_signature_algorithms<2^16-1>;
- * DistinguishedName certificate_authorities<0..2^16-1>;
- * } CertificateRequest;
- *
- */
-static final
-class CertificateRequest extends HandshakeMessage
-{
- // enum ClientCertificateType
- static final int cct_rsa_sign = 1;
- static final int cct_dss_sign = 2;
- static final int cct_rsa_fixed_dh = 3;
- static final int cct_dss_fixed_dh = 4;
-
- // The existance of these two values is a bug in the SSL specification.
- // They are never used in the protocol.
- static final int cct_rsa_ephemeral_dh = 5;
- static final int cct_dss_ephemeral_dh = 6;
-
- // From RFC 4492 (ECC)
- static final int cct_ecdsa_sign = 64;
- static final int cct_rsa_fixed_ecdh = 65;
- static final int cct_ecdsa_fixed_ecdh = 66;
-
- private final static byte[] TYPES_NO_ECC = { cct_rsa_sign, cct_dss_sign };
- private final static byte[] TYPES_ECC =
- { cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign };
-
- byte types []; // 1 to 255 types
- DistinguishedName authorities []; // 3 to 2^16 - 1
- // ... "3" because that's the smallest DER-encoded X500 DN
-
- // protocol version being established using this CertificateRequest message
- ProtocolVersion protocolVersion;
-
- // supported_signature_algorithms for TLS 1.2 or later
- private Collection<SignatureAndHashAlgorithm> algorithms;
-
- // length of supported_signature_algorithms
- private int algorithmsLen;
-
- CertificateRequest(X509Certificate ca[], KeyExchange keyExchange,
- Collection<SignatureAndHashAlgorithm> signAlgs,
- ProtocolVersion protocolVersion) throws IOException {
-
- this.protocolVersion = protocolVersion;
-
- // always use X500Principal
- authorities = new DistinguishedName[ca.length];
- for (int i = 0; i < ca.length; i++) {
- X500Principal x500Principal = ca[i].getSubjectX500Principal();
- authorities[i] = new DistinguishedName(x500Principal);
- }
- // we support RSA, DSS, and ECDSA client authentication and they
- // can be used with all ciphersuites. If this changes, the code
- // needs to be adapted to take keyExchange into account.
- // We only request ECDSA client auth if we have ECC crypto available.
- this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC;
-
- // Use supported_signature_algorithms for TLS 1.2 or later.
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (signAlgs == null || signAlgs.isEmpty()) {
- throw new SSLProtocolException(
- "No supported signature algorithms");
- }
-
- algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
- algorithmsLen =
- SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
- } else {
- algorithms = new ArrayList<SignatureAndHashAlgorithm>();
- algorithmsLen = 0;
- }
- }
-
- CertificateRequest(HandshakeInStream input,
- ProtocolVersion protocolVersion) throws IOException {
-
- this.protocolVersion = protocolVersion;
-
- // Read the certificate_types.
- types = input.getBytes8();
-
- // Read the supported_signature_algorithms for TLS 1.2 or later.
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- algorithmsLen = input.getInt16();
- if (algorithmsLen < 2) {
- throw new SSLProtocolException(
- "Invalid supported_signature_algorithms field");
- }
-
- algorithms = new ArrayList<SignatureAndHashAlgorithm>();
- int remains = algorithmsLen;
- int sequence = 0;
- while (remains > 1) { // needs at least two bytes
- int hash = input.getInt8(); // hash algorithm
- int signature = input.getInt8(); // signature algorithm
-
- SignatureAndHashAlgorithm algorithm =
- SignatureAndHashAlgorithm.valueOf(hash, signature,
- ++sequence);
- algorithms.add(algorithm);
- remains -= 2; // one byte for hash, one byte for signature
- }
-
- if (remains != 0) {
- throw new SSLProtocolException(
- "Invalid supported_signature_algorithms field");
- }
- } else {
- algorithms = new ArrayList<SignatureAndHashAlgorithm>();
- algorithmsLen = 0;
- }
-
- // read the certificate_authorities
- int len = input.getInt16();
- ArrayList<DistinguishedName> v = new ArrayList<>();
- while (len >= 3) {
- DistinguishedName dn = new DistinguishedName(input);
- v.add(dn);
- len -= dn.length();
- }
-
- if (len != 0) {
- throw new SSLProtocolException("Bad CertificateRequest DN length");
- }
-
- authorities = v.toArray(new DistinguishedName[v.size()]);
- }
-
- X500Principal[] getAuthorities() throws IOException {
- X500Principal[] ret = new X500Principal[authorities.length];
- for (int i = 0; i < authorities.length; i++) {
- ret[i] = authorities[i].getX500Principal();
- }
- return ret;
- }
-
- Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
- return algorithms;
- }
-
- @Override
- int messageType() {
- return ht_certificate_request;
- }
-
- @Override
- int messageLength() {
- int len = 1 + types.length + 2;
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- len += algorithmsLen + 2;
- }
-
- for (int i = 0; i < authorities.length; i++) {
- len += authorities[i].length();
- }
-
- return len;
- }
-
- @Override
- void send(HandshakeOutStream output) throws IOException {
- // put certificate_types
- output.putBytes8(types);
-
- // put supported_signature_algorithms
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- output.putInt16(algorithmsLen);
- for (SignatureAndHashAlgorithm algorithm : algorithms) {
- output.putInt8(algorithm.getHashValue()); // hash
- output.putInt8(algorithm.getSignatureValue()); // signature
- }
- }
-
- // put certificate_authorities
- int len = 0;
- for (int i = 0; i < authorities.length; i++) {
- len += authorities[i].length();
- }
-
- output.putInt16(len);
- for (int i = 0; i < authorities.length; i++) {
- authorities[i].send(output);
- }
- }
-
- @Override
- void print(PrintStream s) throws IOException {
- s.println("*** CertificateRequest");
-
- if (debug != null && Debug.isOn("verbose")) {
- s.print("Cert Types: ");
- for (int i = 0; i < types.length; i++) {
- switch (types[i]) {
- case cct_rsa_sign:
- s.print("RSA"); break;
- case cct_dss_sign:
- s.print("DSS"); break;
- case cct_rsa_fixed_dh:
- s.print("Fixed DH (RSA sig)"); break;
- case cct_dss_fixed_dh:
- s.print("Fixed DH (DSS sig)"); break;
- case cct_rsa_ephemeral_dh:
- s.print("Ephemeral DH (RSA sig)"); break;
- case cct_dss_ephemeral_dh:
- s.print("Ephemeral DH (DSS sig)"); break;
- case cct_ecdsa_sign:
- s.print("ECDSA"); break;
- case cct_rsa_fixed_ecdh:
- s.print("Fixed ECDH (RSA sig)"); break;
- case cct_ecdsa_fixed_ecdh:
- s.print("Fixed ECDH (ECDSA sig)"); break;
- default:
- s.print("Type-" + (types[i] & 0xff)); break;
- }
- if (i != types.length - 1) {
- s.print(", ");
- }
- }
- s.println();
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- StringBuffer buffer = new StringBuffer();
- boolean opened = false;
- for (SignatureAndHashAlgorithm signAlg : algorithms) {
- if (opened) {
- buffer.append(", " + signAlg.getAlgorithmName());
- } else {
- buffer.append(signAlg.getAlgorithmName());
- opened = true;
- }
- }
- s.println("Supported Signature Algorithms: " + buffer);
- }
-
- s.println("Cert Authorities:");
- if (authorities.length == 0) {
- s.println("<Empty>");
- } else {
- for (int i = 0; i < authorities.length; i++) {
- authorities[i].print(s);
- }
- }
- }
- }
-}
-
-
-/*
- * ServerHelloDone ... SERVER --> CLIENT
- *
- * When server's done sending its messages in response to the client's
- * "hello" (e.g. its own hello, certificate, key exchange message, perhaps
- * client certificate request) it sends this message to flag that it's
- * done that part of the handshake.
- */
-static final
-class ServerHelloDone extends HandshakeMessage
-{
- int messageType() { return ht_server_hello_done; }
-
- ServerHelloDone() { }
-
- ServerHelloDone(HandshakeInStream input)
- {
- // nothing to do
- }
-
- int messageLength()
- {
- return 0;
- }
-
- void send(HandshakeOutStream s) throws IOException
- {
- // nothing to send
- }
-
- void print(PrintStream s) throws IOException
- {
- s.println("*** ServerHelloDone");
- }
-}
-
-
-/*
- * CertificateVerify ... CLIENT --> SERVER
- *
- * Sent after client sends signature-capable certificates (e.g. not
- * Diffie-Hellman) to verify.
- */
-static final class CertificateVerify extends HandshakeMessage {
-
- // the signature bytes
- private byte[] signature;
-
- // protocol version being established using this ServerKeyExchange message
- ProtocolVersion protocolVersion;
-
- // the preferable signature algorithm used by this CertificateVerify message
- private SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
-
- /*
- * Create an RSA or DSA signed certificate verify message.
- */
- CertificateVerify(ProtocolVersion protocolVersion,
- HandshakeHash handshakeHash, PrivateKey privateKey,
- SecretKey masterSecret, SecureRandom sr,
- SignatureAndHashAlgorithm signAlgorithm)
- throws GeneralSecurityException {
-
- this.protocolVersion = protocolVersion;
-
- String algorithm = privateKey.getAlgorithm();
- Signature sig = null;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- this.preferableSignatureAlgorithm = signAlgorithm;
- sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
- } else {
- sig = getSignature(protocolVersion, algorithm);
- }
- sig.initSign(privateKey, sr);
- updateSignature(sig, protocolVersion, handshakeHash, algorithm,
- masterSecret);
- signature = sig.sign();
- }
-
- //
- // Unmarshal the signed data from the input stream.
- //
- CertificateVerify(HandshakeInStream input,
- Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs,
- ProtocolVersion protocolVersion) throws IOException {
-
- this.protocolVersion = protocolVersion;
-
- // read the signature and hash algorithm
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- int hashAlg = input.getInt8(); // hash algorithm
- int signAlg = input.getInt8(); // signature algorithm
-
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.valueOf(hashAlg, signAlg, 0);
-
- // Is it a local supported signature algorithm?
- if (!localSupportedSignAlgs.contains(
- preferableSignatureAlgorithm)) {
- throw new SSLHandshakeException(
- "Unsupported SignatureAndHashAlgorithm in " +
- "ServerKeyExchange message");
- }
- }
-
- // read the signature
- signature = input.getBytes16();
- }
-
- /*
- * Get the preferable signature algorithm used by this message
- */
- SignatureAndHashAlgorithm getPreferableSignatureAlgorithm() {
- return preferableSignatureAlgorithm;
- }
-
- /*
- * Verify a certificate verify message. Return the result of verification,
- * if there is a problem throw a GeneralSecurityException.
- */
- boolean verify(ProtocolVersion protocolVersion,
- HandshakeHash handshakeHash, PublicKey publicKey,
- SecretKey masterSecret) throws GeneralSecurityException {
- String algorithm = publicKey.getAlgorithm();
- Signature sig = null;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- sig = JsseJce.getSignature(
- preferableSignatureAlgorithm.getAlgorithmName());
- } else {
- sig = getSignature(protocolVersion, algorithm);
- }
- sig.initVerify(publicKey);
- updateSignature(sig, protocolVersion, handshakeHash, algorithm,
- masterSecret);
- return sig.verify(signature);
- }
-
- /*
- * Get the Signature object appropriate for verification using the
- * given signature algorithm and protocol version.
- */
- private static Signature getSignature(ProtocolVersion protocolVersion,
- String algorithm) throws GeneralSecurityException {
- if (algorithm.equals("RSA")) {
- return RSASignature.getInternalInstance();
- } else if (algorithm.equals("DSA")) {
- return JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA);
- } else if (algorithm.equals("EC")) {
- return JsseJce.getSignature(JsseJce.SIGNATURE_RAWECDSA);
- } else {
- throw new SignatureException("Unrecognized algorithm: "
- + algorithm);
- }
- }
-
- /*
- * Update the Signature with the data appropriate for the given
- * signature algorithm and protocol version so that the object is
- * ready for signing or verifying.
- */
- private static void updateSignature(Signature sig,
- ProtocolVersion protocolVersion,
- HandshakeHash handshakeHash, String algorithm, SecretKey masterKey)
- throws SignatureException {
-
- if (algorithm.equals("RSA")) {
- if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
- MessageDigest md5Clone = handshakeHash.getMD5Clone();
- MessageDigest shaClone = handshakeHash.getSHAClone();
-
- if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
- updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey);
- updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
- }
-
- // The signature must be an instance of RSASignature, need
- // to use these hashes directly.
- RSASignature.setHashes(sig, md5Clone, shaClone);
- } else { // TLS1.2+
- sig.update(handshakeHash.getAllHandshakeMessages());
- }
- } else { // DSA, ECDSA
- if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
- MessageDigest shaClone = handshakeHash.getSHAClone();
-
- if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
- updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
- }
-
- sig.update(shaClone.digest());
- } else { // TLS1.2+
- sig.update(handshakeHash.getAllHandshakeMessages());
- }
- }
- }
-
- /*
- * Update the MessageDigest for SSLv3 certificate verify or finished
- * message calculation. The digest must already have been updated with
- * all preceding handshake messages.
- * Used by the Finished class as well.
- */
- private static void updateDigest(MessageDigest md,
- byte[] pad1, byte[] pad2,
- SecretKey masterSecret) {
- // Digest the key bytes if available.
- // Otherwise (sensitive key), try digesting the key directly.
- // That is currently only implemented in SunPKCS11 using a private
- // reflection API, so we avoid that if possible.
- byte[] keyBytes = "RAW".equals(masterSecret.getFormat())
- ? masterSecret.getEncoded() : null;
- if (keyBytes != null) {
- md.update(keyBytes);
- } else {
- digestKey(md, masterSecret);
- }
- md.update(pad1);
- byte[] temp = md.digest();
-
- if (keyBytes != null) {
- md.update(keyBytes);
- } else {
- digestKey(md, masterSecret);
- }
- md.update(pad2);
- md.update(temp);
- }
-
- private final static Class delegate;
- private final static Field spiField;
-
- static {
- try {
- delegate = Class.forName("java.security.MessageDigest$Delegate");
- spiField = delegate.getDeclaredField("digestSpi");
- } catch (Exception e) {
- throw new RuntimeException("Reflection failed", e);
- }
- makeAccessible(spiField);
- }
-
- private static void makeAccessible(final AccessibleObject o) {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- o.setAccessible(true);
- return null;
- }
- });
- }
-
- // ConcurrentHashMap does not allow null values, use this marker object
- private final static Object NULL_OBJECT = new Object();
-
- // cache Method objects per Spi class
- // Note that this will prevent the Spi classes from being GC'd. We assume
- // that is not a problem.
- private final static Map<Class,Object> methodCache =
- new ConcurrentHashMap<>();
-
- private static void digestKey(MessageDigest md, SecretKey key) {
- try {
- // Verify that md is implemented via MessageDigestSpi, not
- // via JDK 1.1 style MessageDigest subclassing.
- if (md.getClass() != delegate) {
- throw new Exception("Digest is not a MessageDigestSpi");
- }
- MessageDigestSpi spi = (MessageDigestSpi)spiField.get(md);
- Class<?> clazz = spi.getClass();
- Object r = methodCache.get(clazz);
- if (r == null) {
- try {
- r = clazz.getDeclaredMethod("implUpdate", SecretKey.class);
- makeAccessible((Method)r);
- } catch (NoSuchMethodException e) {
- r = NULL_OBJECT;
- }
- methodCache.put(clazz, r);
- }
- if (r == NULL_OBJECT) {
- throw new Exception(
- "Digest does not support implUpdate(SecretKey)");
- }
- Method update = (Method)r;
- update.invoke(spi, key);
- } catch (Exception e) {
- throw new RuntimeException(
- "Could not obtain encoded key and "
- + "MessageDigest cannot digest key", e);
- }
- }
-
- @Override
- int messageType() {
- return ht_certificate_verify;
- }
-
- @Override
- int messageLength() {
- int temp = 2;
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- temp += SignatureAndHashAlgorithm.sizeInRecord();
- }
-
- return temp + signature.length;
- }
-
- @Override
- void send(HandshakeOutStream s) throws IOException {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- s.putInt8(preferableSignatureAlgorithm.getHashValue());
- s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
- }
-
- s.putBytes16(signature);
- }
-
- @Override
- void print(PrintStream s) throws IOException {
- s.println("*** CertificateVerify");
-
- if (debug != null && Debug.isOn("verbose")) {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- s.println("Signature Algorithm " +
- preferableSignatureAlgorithm.getAlgorithmName());
- }
- }
- }
-}
-
-
-/*
- * FINISHED ... sent by both CLIENT and SERVER
- *
- * This is the FINISHED message as defined in the SSL and TLS protocols.
- * Both protocols define this handshake message slightly differently.
- * This class supports both formats.
- *
- * When handshaking is finished, each side sends a "change_cipher_spec"
- * record, then immediately sends a "finished" handshake message prepared
- * according to the newly adopted cipher spec.
- *
- * NOTE that until this is sent, no application data may be passed, unless
- * some non-default cipher suite has already been set up on this connection
- * connection (e.g. a previous handshake arranged one).
- */
-static final class Finished extends HandshakeMessage {
-
- // constant for a Finished message sent by the client
- final static int CLIENT = 1;
-
- // constant for a Finished message sent by the server
- final static int SERVER = 2;
-
- // enum Sender: "CLNT" and "SRVR"
- private static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 };
- private static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 };
-
- /*
- * Contents of the finished message ("checksum"). For TLS, it
- * is 12 bytes long, for SSLv3 36 bytes.
- */
- private byte[] verifyData;
-
- /*
- * Current cipher suite we are negotiating. TLS 1.2 has
- * ciphersuite-defined PRF algorithms.
- */
- private ProtocolVersion protocolVersion;
- private CipherSuite cipherSuite;
-
- /*
- * Create a finished message to send to the remote peer.
- */
- Finished(ProtocolVersion protocolVersion, HandshakeHash handshakeHash,
- int sender, SecretKey master, CipherSuite cipherSuite) {
- this.protocolVersion = protocolVersion;
- this.cipherSuite = cipherSuite;
- verifyData = getFinished(handshakeHash, sender, master);
- }
-
- /*
- * Constructor that reads FINISHED message from stream.
- */
- Finished(ProtocolVersion protocolVersion, HandshakeInStream input,
- CipherSuite cipherSuite) throws IOException {
- this.protocolVersion = protocolVersion;
- this.cipherSuite = cipherSuite;
- int msgLen = (protocolVersion.v >= ProtocolVersion.TLS10.v) ? 12 : 36;
- verifyData = new byte[msgLen];
- input.read(verifyData);
- }
-
- /*
- * Verify that the hashes here are what would have been produced
- * according to a given set of inputs. This is used to ensure that
- * both client and server are fully in sync, and that the handshake
- * computations have been successful.
- */
- boolean verify(HandshakeHash handshakeHash, int sender, SecretKey master) {
- byte[] myFinished = getFinished(handshakeHash, sender, master);
- return Arrays.equals(myFinished, verifyData);
- }
-
- /*
- * Perform the actual finished message calculation.
- */
- private byte[] getFinished(HandshakeHash handshakeHash,
- int sender, SecretKey masterKey) {
- byte[] sslLabel;
- String tlsLabel;
- if (sender == CLIENT) {
- sslLabel = SSL_CLIENT;
- tlsLabel = "client finished";
- } else if (sender == SERVER) {
- sslLabel = SSL_SERVER;
- tlsLabel = "server finished";
- } else {
- throw new RuntimeException("Invalid sender: " + sender);
- }
-
- if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
- // TLS 1.0+
- try {
- byte [] seed;
- String prfAlg;
- PRF prf;
-
- // Get the KeyGenerator alg and calculate the seed.
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- // TLS 1.2
- seed = handshakeHash.getFinishedHash();
-
- prfAlg = "SunTls12Prf";
- prf = cipherSuite.prfAlg;
- } else {
- // TLS 1.0/1.1
- MessageDigest md5Clone = handshakeHash.getMD5Clone();
- MessageDigest shaClone = handshakeHash.getSHAClone();
- seed = new byte[36];
- md5Clone.digest(seed, 0, 16);
- shaClone.digest(seed, 16, 20);
-
- prfAlg = "SunTlsPrf";
- prf = P_NONE;
- }
-
- String prfHashAlg = prf.getPRFHashAlg();
- int prfHashLength = prf.getPRFHashLength();
- int prfBlockSize = prf.getPRFBlockSize();
-
- /*
- * RFC 5246/7.4.9 says that finished messages can
- * be ciphersuite-specific in both length/PRF hash
- * algorithm. If we ever run across a different
- * length, this call will need to be updated.
- */
- TlsPrfParameterSpec spec = new TlsPrfParameterSpec(
- masterKey, tlsLabel, seed, 12,
- prfHashAlg, prfHashLength, prfBlockSize);
-
- KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg);
- kg.init(spec);
- SecretKey prfKey = kg.generateKey();
- if ("RAW".equals(prfKey.getFormat()) == false) {
- throw new ProviderException(
- "Invalid PRF output, format must be RAW");
- }
- byte[] finished = prfKey.getEncoded();
- return finished;
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("PRF failed", e);
- }
- } else {
- // SSLv3
- MessageDigest md5Clone = handshakeHash.getMD5Clone();
- MessageDigest shaClone = handshakeHash.getSHAClone();
- updateDigest(md5Clone, sslLabel, MD5_pad1, MD5_pad2, masterKey);
- updateDigest(shaClone, sslLabel, SHA_pad1, SHA_pad2, masterKey);
- byte[] finished = new byte[36];
- try {
- md5Clone.digest(finished, 0, 16);
- shaClone.digest(finished, 16, 20);
- } catch (DigestException e) {
- // cannot occur
- throw new RuntimeException("Digest failed", e);
- }
- return finished;
- }
- }
-
- /*
- * Update the MessageDigest for SSLv3 finished message calculation.
- * The digest must already have been updated with all preceding handshake
- * messages. This operation is almost identical to the certificate verify
- * hash, reuse that code.
- */
- private static void updateDigest(MessageDigest md, byte[] sender,
- byte[] pad1, byte[] pad2, SecretKey masterSecret) {
- md.update(sender);
- CertificateVerify.updateDigest(md, pad1, pad2, masterSecret);
- }
-
- // get the verify_data of the finished message
- byte[] getVerifyData() {
- return verifyData;
- }
-
- @Override
- int messageType() { return ht_finished; }
-
- @Override
- int messageLength() {
- return verifyData.length;
- }
-
- @Override
- void send(HandshakeOutStream out) throws IOException {
- out.write(verifyData);
- }
-
- @Override
- void print(PrintStream s) throws IOException {
- s.println("*** Finished");
- if (debug != null && Debug.isOn("verbose")) {
- Debug.println(s, "verify_data", verifyData);
- s.println("***");
- }
- }
-}
-
-//
-// END of nested classes
-//
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/HandshakeOutStream.java b/ojluni/src/main/java/sun/security/ssl/HandshakeOutStream.java
deleted file mode 100755
index 25aeed6..0000000
--- a/ojluni/src/main/java/sun/security/ssl/HandshakeOutStream.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.OutputStream;
-import java.io.IOException;
-import java.security.MessageDigest;
-
-/**
- * Output stream for handshake data. This is used only internally
- * to the SSL classes.
- *
- * MT note: one thread at a time is presumed be writing handshake
- * messages, but (after initial connection setup) it's possible to
- * have other threads reading/writing application data. It's the
- * SSLSocketImpl class that synchronizes record writes.
- *
- * @author David Brownell
- */
-public class HandshakeOutStream extends OutputStream {
-
- private SSLSocketImpl socket;
- private SSLEngineImpl engine;
-
- OutputRecord r;
-
- HandshakeOutStream(ProtocolVersion protocolVersion,
- ProtocolVersion helloVersion, HandshakeHash handshakeHash,
- SSLSocketImpl socket) {
- this.socket = socket;
- r = new OutputRecord(Record.ct_handshake);
- init(protocolVersion, helloVersion, handshakeHash);
- }
-
- HandshakeOutStream(ProtocolVersion protocolVersion,
- ProtocolVersion helloVersion, HandshakeHash handshakeHash,
- SSLEngineImpl engine) {
- this.engine = engine;
- r = new EngineOutputRecord(Record.ct_handshake, engine);
- init(protocolVersion, helloVersion, handshakeHash);
- }
-
- private void init(ProtocolVersion protocolVersion,
- ProtocolVersion helloVersion, HandshakeHash handshakeHash) {
- r.setVersion(protocolVersion);
- r.setHelloVersion(helloVersion);
- r.setHandshakeHash(handshakeHash);
- }
-
-
- /*
- * Update the handshake data hashes ... mostly for use after a
- * client cert has been sent, so the cert verify message can be
- * constructed correctly yet without forcing extra I/O. In all
- * other cases, automatic hash calculation suffices.
- */
- void doHashes() {
- r.doHashes();
- }
-
- /*
- * Write some data out onto the stream ... buffers as much as possible.
- * Hashes are updated automatically if something gets flushed to the
- * network (e.g. a big cert message etc).
- */
- public void write(byte buf[], int off, int len) throws IOException {
- while (len > 0) {
- int howmuch = Math.min(len, r.availableDataBytes());
-
- if (howmuch == 0) {
- flush();
- } else {
- r.write(buf, off, howmuch);
- off += howmuch;
- len -= howmuch;
- }
- }
- }
-
- /*
- * write-a-byte
- */
- public void write(int i) throws IOException {
- if (r.availableDataBytes() < 1) {
- flush();
- }
- r.write(i);
- }
-
- public void flush() throws IOException {
- if (socket != null) {
- try {
- socket.writeRecord(r);
- } catch (IOException e) {
- // Had problems writing; check if there was an
- // alert from peer. If alert received, waitForClose
- // will throw an exception for the alert
- socket.waitForClose(true);
-
- // No alert was received, just rethrow exception
- throw e;
- }
- } else { // engine != null
- /*
- * Even if record might be empty, flush anyway in case
- * there is a finished handshake message that we need
- * to queue.
- */
- engine.writeRecord((EngineOutputRecord)r);
- }
- }
-
- /*
- * Tell the OutputRecord that a finished message was
- * contained either in this record or the one immeiately
- * preceeding it. We need to reliably pass back notifications
- * that a finish message occured.
- */
- void setFinishedMsg() {
- assert(socket == null);
-
- ((EngineOutputRecord)r).setFinishedMsg();
- }
-
- /*
- * Put integers encoded in standard 8, 16, 24, and 32 bit
- * big endian formats. Note that OutputStream.write(int) only
- * writes the least significant 8 bits and ignores the rest.
- */
-
- void putInt8(int i) throws IOException {
- checkOverflow(i, Record.OVERFLOW_OF_INT08);
- r.write(i);
- }
-
- void putInt16(int i) throws IOException {
- checkOverflow(i, Record.OVERFLOW_OF_INT16);
- if (r.availableDataBytes() < 2) {
- flush();
- }
- r.write(i >> 8);
- r.write(i);
- }
-
- void putInt24(int i) throws IOException {
- checkOverflow(i, Record.OVERFLOW_OF_INT24);
- if (r.availableDataBytes() < 3) {
- flush();
- }
- r.write(i >> 16);
- r.write(i >> 8);
- r.write(i);
- }
-
- void putInt32(int i) throws IOException {
- if (r.availableDataBytes() < 4) {
- flush();
- }
- r.write(i >> 24);
- r.write(i >> 16);
- r.write(i >> 8);
- r.write(i);
- }
-
- /*
- * Put byte arrays with length encoded as 8, 16, 24 bit
- * integers in big-endian format.
- */
- void putBytes8(byte b[]) throws IOException {
- if (b == null) {
- putInt8(0);
- return;
- } else {
- checkOverflow(b.length, Record.OVERFLOW_OF_INT08);
- }
- putInt8(b.length);
- write(b, 0, b.length);
- }
-
- public void putBytes16(byte b[]) throws IOException {
- if (b == null) {
- putInt16(0);
- return;
- } else {
- checkOverflow(b.length, Record.OVERFLOW_OF_INT16);
- }
- putInt16(b.length);
- write(b, 0, b.length);
- }
-
- void putBytes24(byte b[]) throws IOException {
- if (b == null) {
- putInt24(0);
- return;
- } else {
- checkOverflow(b.length, Record.OVERFLOW_OF_INT24);
- }
- putInt24(b.length);
- write(b, 0, b.length);
- }
-
- private void checkOverflow(int length, int overflow) {
- if (length >= overflow) {
- // internal_error alert will be triggered
- throw new RuntimeException(
- "Field length overflow, the field length (" +
- length + ") should be less than " + overflow);
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/Handshaker.java b/ojluni/src/main/java/sun/security/ssl/Handshaker.java
deleted file mode 100755
index 2f1d01b..0000000
--- a/ojluni/src/main/java/sun/security/ssl/Handshaker.java
+++ /dev/null
@@ -1,1384 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.util.*;
-import java.security.*;
-import java.security.NoSuchAlgorithmException;
-import java.security.AccessController;
-import java.security.AlgorithmConstraints;
-import java.security.AccessControlContext;
-import java.security.PrivilegedExceptionAction;
-import java.security.PrivilegedActionException;
-
-import javax.crypto.*;
-import javax.crypto.spec.*;
-
-import javax.net.ssl.*;
-import sun.misc.HexDumpEncoder;
-
-import sun.security.internal.spec.*;
-import sun.security.internal.interfaces.TlsMasterSecret;
-
-import sun.security.ssl.HandshakeMessage.*;
-import sun.security.ssl.CipherSuite.*;
-
-import static sun.security.ssl.CipherSuite.PRF.*;
-
-/**
- * Handshaker ... processes handshake records from an SSL V3.0
- * data stream, handling all the details of the handshake protocol.
- *
- * Note that the real protocol work is done in two subclasses, the base
- * class just provides the control flow and key generation framework.
- *
- * @author David Brownell
- */
-abstract class Handshaker {
-
- // protocol version being established using this Handshaker
- ProtocolVersion protocolVersion;
-
- // the currently active protocol version during a renegotiation
- ProtocolVersion activeProtocolVersion;
-
- // security parameters for secure renegotiation.
- boolean secureRenegotiation;
- byte[] clientVerifyData;
- byte[] serverVerifyData;
-
- // Is it an initial negotiation or a renegotiation?
- boolean isInitialHandshake;
-
- // List of enabled protocols
- private ProtocolList enabledProtocols;
-
- // List of enabled CipherSuites
- private CipherSuiteList enabledCipherSuites;
-
- // The endpoint identification protocol
- String identificationProtocol;
-
- // The cryptographic algorithm constraints
- private AlgorithmConstraints algorithmConstraints = null;
-
- // Local supported signature and algorithms
- Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs;
-
- // Peer supported signature and algorithms
- Collection<SignatureAndHashAlgorithm> peerSupportedSignAlgs;
-
- /*
-
- /*
- * List of active protocols
- *
- * Active protocols is a subset of enabled protocols, and will
- * contain only those protocols that have vaild cipher suites
- * enabled.
- */
- private ProtocolList activeProtocols;
-
- /*
- * List of active cipher suites
- *
- * Active cipher suites is a subset of enabled cipher suites, and will
- * contain only those cipher suites available for the active protocols.
- */
- private CipherSuiteList activeCipherSuites;
-
- private boolean isClient;
- private boolean needCertVerify;
-
- SSLSocketImpl conn = null;
- SSLEngineImpl engine = null;
-
- HandshakeHash handshakeHash;
- HandshakeInStream input;
- HandshakeOutStream output;
- int state;
- SSLContextImpl sslContext;
- RandomCookie clnt_random, svr_random;
- SSLSessionImpl session;
-
- // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
- CipherSuite cipherSuite;
-
- // current key exchange. Never null, initially K_NULL
- KeyExchange keyExchange;
-
- /* True if this session is being resumed (fast handshake) */
- boolean resumingSession;
-
- /* True if it's OK to start a new SSL session */
- boolean enableNewSession;
-
- // Temporary storage for the individual keys. Set by
- // calculateConnectionKeys() and cleared once the ciphers are
- // activated.
- private SecretKey clntWriteKey, svrWriteKey;
- private IvParameterSpec clntWriteIV, svrWriteIV;
- private SecretKey clntMacSecret, svrMacSecret;
-
- /*
- * Delegated task subsystem data structures.
- *
- * If thrown is set, we need to propagate this back immediately
- * on entry into processMessage().
- *
- * Data is protected by the SSLEngine.this lock.
- */
- private volatile boolean taskDelegated = false;
- private volatile DelegatedTask delegatedTask = null;
- private volatile Exception thrown = null;
-
- // Could probably use a java.util.concurrent.atomic.AtomicReference
- // here instead of using this lock. Consider changing.
- private Object thrownLock = new Object();
-
- /* Class and subclass dynamic debugging support */
- static final Debug debug = Debug.getInstance("ssl");
-
- // By default, disable the unsafe legacy session renegotiation
- static final boolean allowUnsafeRenegotiation = Debug.getBooleanProperty(
- "sun.security.ssl.allowUnsafeRenegotiation", false);
-
- // For maximum interoperability and backward compatibility, RFC 5746
- // allows server (or client) to accept ClientHello (or ServerHello)
- // message without the secure renegotiation_info extension or SCSV.
- //
- // For maximum security, RFC 5746 also allows server (or client) to
- // reject such message with a fatal "handshake_failure" alert.
- //
- // By default, allow such legacy hello messages.
- static final boolean allowLegacyHelloMessages = Debug.getBooleanProperty(
- "sun.security.ssl.allowLegacyHelloMessages", true);
-
- // need to dispose the object when it is invalidated
- boolean invalidated;
-
- Handshaker(SSLSocketImpl c, SSLContextImpl context,
- ProtocolList enabledProtocols, boolean needCertVerify,
- boolean isClient, ProtocolVersion activeProtocolVersion,
- boolean isInitialHandshake, boolean secureRenegotiation,
- byte[] clientVerifyData, byte[] serverVerifyData) {
- this.conn = c;
- init(context, enabledProtocols, needCertVerify, isClient,
- activeProtocolVersion, isInitialHandshake, secureRenegotiation,
- clientVerifyData, serverVerifyData);
- }
-
- Handshaker(SSLEngineImpl engine, SSLContextImpl context,
- ProtocolList enabledProtocols, boolean needCertVerify,
- boolean isClient, ProtocolVersion activeProtocolVersion,
- boolean isInitialHandshake, boolean secureRenegotiation,
- byte[] clientVerifyData, byte[] serverVerifyData) {
- this.engine = engine;
- init(context, enabledProtocols, needCertVerify, isClient,
- activeProtocolVersion, isInitialHandshake, secureRenegotiation,
- clientVerifyData, serverVerifyData);
- }
-
- private void init(SSLContextImpl context, ProtocolList enabledProtocols,
- boolean needCertVerify, boolean isClient,
- ProtocolVersion activeProtocolVersion,
- boolean isInitialHandshake, boolean secureRenegotiation,
- byte[] clientVerifyData, byte[] serverVerifyData) {
-
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "Allow unsafe renegotiation: " + allowUnsafeRenegotiation +
- "\nAllow legacy hello messages: " + allowLegacyHelloMessages +
- "\nIs initial handshake: " + isInitialHandshake +
- "\nIs secure renegotiation: " + secureRenegotiation);
- }
-
- this.sslContext = context;
- this.isClient = isClient;
- this.needCertVerify = needCertVerify;
- this.activeProtocolVersion = activeProtocolVersion;
- this.isInitialHandshake = isInitialHandshake;
- this.secureRenegotiation = secureRenegotiation;
- this.clientVerifyData = clientVerifyData;
- this.serverVerifyData = serverVerifyData;
- enableNewSession = true;
- invalidated = false;
-
- setCipherSuite(CipherSuite.C_NULL);
- setEnabledProtocols(enabledProtocols);
-
- if (conn != null) {
- algorithmConstraints = new SSLAlgorithmConstraints(conn, true);
- } else { // engine != null
- algorithmConstraints = new SSLAlgorithmConstraints(engine, true);
- }
-
-
- //
- // In addition to the connection state machine, controlling
- // how the connection deals with the different sorts of records
- // that get sent (notably handshake transitions!), there's
- // also a handshaking state machine that controls message
- // sequencing.
- //
- // It's a convenient artifact of the protocol that this can,
- // with only a couple of minor exceptions, be driven by the
- // type constant for the last message seen: except for the
- // client's cert verify, those constants are in a convenient
- // order to drastically simplify state machine checking.
- //
- state = -2; // initialized but not activated
- }
-
- /*
- * Reroutes calls to the SSLSocket or SSLEngine (*SE).
- *
- * We could have also done it by extra classes
- * and letting them override, but this seemed much
- * less involved.
- */
- void fatalSE(byte b, String diagnostic) throws IOException {
- fatalSE(b, diagnostic, null);
- }
-
- void fatalSE(byte b, Throwable cause) throws IOException {
- fatalSE(b, null, cause);
- }
-
- void fatalSE(byte b, String diagnostic, Throwable cause)
- throws IOException {
- if (conn != null) {
- conn.fatal(b, diagnostic, cause);
- } else {
- engine.fatal(b, diagnostic, cause);
- }
- }
-
- void warningSE(byte b) {
- if (conn != null) {
- conn.warning(b);
- } else {
- engine.warning(b);
- }
- }
-
- String getRawHostnameSE() {
- if (conn != null) {
- return conn.getRawHostname();
- } else {
- return engine.getPeerHost();
- }
- }
-
- String getHostSE() {
- if (conn != null) {
- return conn.getHost();
- } else {
- return engine.getPeerHost();
- }
- }
-
- String getHostAddressSE() {
- if (conn != null) {
- return conn.getInetAddress().getHostAddress();
- } else {
- /*
- * This is for caching only, doesn't matter that's is really
- * a hostname. The main thing is that it doesn't do
- * a reverse DNS lookup, potentially slowing things down.
- */
- return engine.getPeerHost();
- }
- }
-
- boolean isLoopbackSE() {
- if (conn != null) {
- return conn.getInetAddress().isLoopbackAddress();
- } else {
- return false;
- }
- }
-
- int getPortSE() {
- if (conn != null) {
- return conn.getPort();
- } else {
- return engine.getPeerPort();
- }
- }
-
- int getLocalPortSE() {
- if (conn != null) {
- return conn.getLocalPort();
- } else {
- return -1;
- }
- }
-
- AccessControlContext getAccSE() {
- if (conn != null) {
- return conn.getAcc();
- } else {
- return engine.getAcc();
- }
- }
-
- private void setVersionSE(ProtocolVersion protocolVersion) {
- if (conn != null) {
- conn.setVersion(protocolVersion);
- } else {
- engine.setVersion(protocolVersion);
- }
- }
-
- /**
- * Set the active protocol version and propagate it to the SSLSocket
- * and our handshake streams. Called from ClientHandshaker
- * and ServerHandshaker with the negotiated protocol version.
- */
- void setVersion(ProtocolVersion protocolVersion) {
- this.protocolVersion = protocolVersion;
- setVersionSE(protocolVersion);
-
- output.r.setVersion(protocolVersion);
- }
-
- /**
- * Set the enabled protocols. Called from the constructor or
- * SSLSocketImpl/SSLEngineImpl.setEnabledProtocols() (if the
- * handshake is not yet in progress).
- */
- void setEnabledProtocols(ProtocolList enabledProtocols) {
- activeCipherSuites = null;
- activeProtocols = null;
-
- this.enabledProtocols = enabledProtocols;
- }
-
- /**
- * Set the enabled cipher suites. Called from
- * SSLSocketImpl/SSLEngineImpl.setEnabledCipherSuites() (if the
- * handshake is not yet in progress).
- */
- void setEnabledCipherSuites(CipherSuiteList enabledCipherSuites) {
- activeCipherSuites = null;
- activeProtocols = null;
- this.enabledCipherSuites = enabledCipherSuites;
- }
-
- /**
- * Set the algorithm constraints. Called from the constructor or
- * SSLSocketImpl/SSLEngineImpl.setAlgorithmConstraints() (if the
- * handshake is not yet in progress).
- */
- void setAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) {
- activeCipherSuites = null;
- activeProtocols = null;
-
- this.algorithmConstraints =
- new SSLAlgorithmConstraints(algorithmConstraints);
- this.localSupportedSignAlgs = null;
- }
-
- Collection<SignatureAndHashAlgorithm> getLocalSupportedSignAlgs() {
- if (localSupportedSignAlgs == null) {
- localSupportedSignAlgs =
- SignatureAndHashAlgorithm.getSupportedAlgorithms(
- algorithmConstraints);
- }
-
- return localSupportedSignAlgs;
- }
-
- void setPeerSupportedSignAlgs(
- Collection<SignatureAndHashAlgorithm> algorithms) {
- peerSupportedSignAlgs =
- new ArrayList<SignatureAndHashAlgorithm>(algorithms);
- }
-
- Collection<SignatureAndHashAlgorithm> getPeerSupportedSignAlgs() {
- return peerSupportedSignAlgs;
- }
-
-
- /**
- * Set the identification protocol. Called from the constructor or
- * SSLSocketImpl/SSLEngineImpl.setIdentificationProtocol() (if the
- * handshake is not yet in progress).
- */
- void setIdentificationProtocol(String protocol) {
- this.identificationProtocol = protocol;
- }
-
- /**
- * Prior to handshaking, activate the handshake and initialize the version,
- * input stream and output stream.
- */
- void activate(ProtocolVersion helloVersion) throws IOException {
- if (activeProtocols == null) {
- activeProtocols = getActiveProtocols();
- }
-
- if (activeProtocols.collection().isEmpty() ||
- activeProtocols.max.v == ProtocolVersion.NONE.v) {
- throw new SSLHandshakeException("No appropriate protocol");
- }
-
- if (activeCipherSuites == null) {
- activeCipherSuites = getActiveCipherSuites();
- }
-
- if (activeCipherSuites.collection().isEmpty()) {
- throw new SSLHandshakeException("No appropriate cipher suite");
- }
-
- // temporary protocol version until the actual protocol version
- // is negotiated in the Hello exchange. This affects the record
- // version we sent with the ClientHello.
- if (!isInitialHandshake) {
- protocolVersion = activeProtocolVersion;
- } else {
- protocolVersion = activeProtocols.max;
- }
-
- if (helloVersion == null || helloVersion.v == ProtocolVersion.NONE.v) {
- helloVersion = activeProtocols.helloVersion;
- }
-
- // We accumulate digests of the handshake messages so that
- // we can read/write CertificateVerify and Finished messages,
- // getting assurance against some particular active attacks.
- Set<String> localSupportedHashAlgorithms =
- SignatureAndHashAlgorithm.getHashAlgorithmNames(
- getLocalSupportedSignAlgs());
- handshakeHash = new HandshakeHash(!isClient, needCertVerify,
- localSupportedHashAlgorithms);
-
- // Generate handshake input/output stream.
- input = new HandshakeInStream(handshakeHash);
- if (conn != null) {
- output = new HandshakeOutStream(protocolVersion, helloVersion,
- handshakeHash, conn);
- conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
- conn.getAppInputStream().r.setHelloVersion(helloVersion);
- conn.getAppOutputStream().r.setHelloVersion(helloVersion);
- } else {
- output = new HandshakeOutStream(protocolVersion, helloVersion,
- handshakeHash, engine);
- engine.inputRecord.setHandshakeHash(handshakeHash);
- engine.inputRecord.setHelloVersion(helloVersion);
- engine.outputRecord.setHelloVersion(helloVersion);
- }
-
- // move state to activated
- state = -1;
- }
-
- /**
- * Set cipherSuite and keyExchange to the given CipherSuite.
- * Does not perform any verification that this is a valid selection,
- * this must be done before calling this method.
- */
- void setCipherSuite(CipherSuite s) {
- this.cipherSuite = s;
- this.keyExchange = s.keyExchange;
- }
-
- /**
- * Check if the given ciphersuite is enabled and available.
- * Does not check if the required server certificates are available.
- */
- boolean isNegotiable(CipherSuite s) {
- if (activeCipherSuites == null) {
- activeCipherSuites = getActiveCipherSuites();
- }
-
- return activeCipherSuites.contains(s) && s.isNegotiable();
- }
-
- /**
- * Check if the given protocol version is enabled and available.
- */
- boolean isNegotiable(ProtocolVersion protocolVersion) {
- if (activeProtocols == null) {
- activeProtocols = getActiveProtocols();
- }
-
- return activeProtocols.contains(protocolVersion);
- }
-
- /**
- * Select a protocol version from the list. Called from
- * ServerHandshaker to negotiate protocol version.
- *
- * Return the lower of the protocol version suggested in the
- * clien hello and the highest supported by the server.
- */
- ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
- if (activeProtocols == null) {
- activeProtocols = getActiveProtocols();
- }
-
- return activeProtocols.selectProtocolVersion(protocolVersion);
- }
-
- /**
- * Get the active cipher suites.
- *
- * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
- * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
- * negotiate these cipher suites in TLS 1.1 or later mode.
- *
- * Therefore, when the active protocols only include TLS 1.1 or later,
- * the client cannot request to negotiate those obsoleted cipher
- * suites. That is, the obsoleted suites should not be included in the
- * client hello. So we need to create a subset of the enabled cipher
- * suites, the active cipher suites, which does not contain obsoleted
- * cipher suites of the minimum active protocol.
- *
- * Return empty list instead of null if no active cipher suites.
- */
- CipherSuiteList getActiveCipherSuites() {
- if (activeCipherSuites == null) {
- if (activeProtocols == null) {
- activeProtocols = getActiveProtocols();
- }
-
- ArrayList<CipherSuite> suites = new ArrayList<>();
- if (!(activeProtocols.collection().isEmpty()) &&
- activeProtocols.min.v != ProtocolVersion.NONE.v) {
- for (CipherSuite suite : enabledCipherSuites.collection()) {
- if (suite.obsoleted > activeProtocols.min.v &&
- suite.supported <= activeProtocols.max.v) {
- if (algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- suite.name, null)) {
- suites.add(suite);
- }
- } else if (debug != null && Debug.isOn("verbose")) {
- if (suite.obsoleted <= activeProtocols.min.v) {
- System.out.println(
- "Ignoring obsoleted cipher suite: " + suite);
- } else {
- System.out.println(
- "Ignoring unsupported cipher suite: " + suite);
- }
- }
- }
- }
- activeCipherSuites = new CipherSuiteList(suites);
- }
-
- return activeCipherSuites;
- }
-
- /*
- * Get the active protocol versions.
- *
- * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted,
- * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT
- * negotiate these cipher suites in TLS 1.1 or later mode.
- *
- * For example, if "TLS_RSA_EXPORT_WITH_RC4_40_MD5" is the
- * only enabled cipher suite, the client cannot request TLS 1.1 or
- * later, even though TLS 1.1 or later is enabled. We need to create a
- * subset of the enabled protocols, called the active protocols, which
- * contains protocols appropriate to the list of enabled Ciphersuites.
- *
- * Return empty list instead of null if no active protocol versions.
- */
- ProtocolList getActiveProtocols() {
- if (activeProtocols == null) {
- ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
- for (ProtocolVersion protocol : enabledProtocols.collection()) {
- boolean found = false;
- for (CipherSuite suite : enabledCipherSuites.collection()) {
- if (suite.isAvailable() && suite.obsoleted > protocol.v &&
- suite.supported <= protocol.v) {
- if (algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- suite.name, null)) {
- protocols.add(protocol);
- found = true;
- break;
- } else if (debug != null && Debug.isOn("verbose")) {
- System.out.println(
- "Ignoring disabled cipher suite: " + suite +
- " for " + protocol);
- }
- } else if (debug != null && Debug.isOn("verbose")) {
- System.out.println(
- "Ignoring unsupported cipher suite: " + suite +
- " for " + protocol);
- }
- }
- if (!found && (debug != null) && Debug.isOn("handshake")) {
- System.out.println(
- "No available cipher suite for " + protocol);
- }
- }
- activeProtocols = new ProtocolList(protocols);
- }
-
- return activeProtocols;
- }
-
- /**
- * As long as handshaking has not activated, we can
- * change whether session creations are allowed.
- *
- * Callers should do their own checking if handshaking
- * has activated.
- */
- void setEnableSessionCreation(boolean newSessions) {
- enableNewSession = newSessions;
- }
-
- /**
- * Create a new read cipher and return it to caller.
- */
- CipherBox newReadCipher() throws NoSuchAlgorithmException {
- BulkCipher cipher = cipherSuite.cipher;
- CipherBox box;
- if (isClient) {
- box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
- sslContext.getSecureRandom(), false);
- svrWriteKey = null;
- svrWriteIV = null;
- } else {
- box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
- sslContext.getSecureRandom(), false);
- clntWriteKey = null;
- clntWriteIV = null;
- }
- return box;
- }
-
- /**
- * Create a new write cipher and return it to caller.
- */
- CipherBox newWriteCipher() throws NoSuchAlgorithmException {
- BulkCipher cipher = cipherSuite.cipher;
- CipherBox box;
- if (isClient) {
- box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
- sslContext.getSecureRandom(), true);
- clntWriteKey = null;
- clntWriteIV = null;
- } else {
- box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
- sslContext.getSecureRandom(), true);
- svrWriteKey = null;
- svrWriteIV = null;
- }
- return box;
- }
-
- /**
- * Create a new read MAC and return it to caller.
- */
- MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException {
- MacAlg macAlg = cipherSuite.macAlg;
- MAC mac;
- if (isClient) {
- mac = macAlg.newMac(protocolVersion, svrMacSecret);
- svrMacSecret = null;
- } else {
- mac = macAlg.newMac(protocolVersion, clntMacSecret);
- clntMacSecret = null;
- }
- return mac;
- }
-
- /**
- * Create a new write MAC and return it to caller.
- */
- MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException {
- MacAlg macAlg = cipherSuite.macAlg;
- MAC mac;
- if (isClient) {
- mac = macAlg.newMac(protocolVersion, clntMacSecret);
- clntMacSecret = null;
- } else {
- mac = macAlg.newMac(protocolVersion, svrMacSecret);
- svrMacSecret = null;
- }
- return mac;
- }
-
- /*
- * Returns true iff the handshake sequence is done, so that
- * this freshly created session can become the current one.
- */
- boolean isDone() {
- return state == HandshakeMessage.ht_finished;
- }
-
-
- /*
- * Returns the session which was created through this
- * handshake sequence ... should be called after isDone()
- * returns true.
- */
- SSLSessionImpl getSession() {
- return session;
- }
-
- /*
- * Set the handshake session
- */
- void setHandshakeSessionSE(SSLSessionImpl handshakeSession) {
- if (conn != null) {
- conn.setHandshakeSession(handshakeSession);
- } else {
- engine.setHandshakeSession(handshakeSession);
- }
- }
-
- /*
- * Returns true if renegotiation is in use for this connection.
- */
- boolean isSecureRenegotiation() {
- return secureRenegotiation;
- }
-
- /*
- * Returns the verify_data from the Finished message sent by the client.
- */
- byte[] getClientVerifyData() {
- return clientVerifyData;
- }
-
- /*
- * Returns the verify_data from the Finished message sent by the server.
- */
- byte[] getServerVerifyData() {
- return serverVerifyData;
- }
-
- /*
- * This routine is fed SSL handshake records when they become available,
- * and processes messages found therein.
- */
- void process_record(InputRecord r, boolean expectingFinished)
- throws IOException {
-
- checkThrown();
-
- /*
- * Store the incoming handshake data, then see if we can
- * now process any completed handshake messages
- */
- input.incomingRecord(r);
-
- /*
- * We don't need to create a separate delegatable task
- * for finished messages.
- */
- if ((conn != null) || expectingFinished) {
- processLoop();
- } else {
- delegateTask(new PrivilegedExceptionAction<Void>() {
- public Void run() throws Exception {
- processLoop();
- return null;
- }
- });
- }
- }
-
- /*
- * On input, we hash messages one at a time since servers may need
- * to access an intermediate hash to validate a CertificateVerify
- * message.
- *
- * Note that many handshake messages can come in one record (and often
- * do, to reduce network resource utilization), and one message can also
- * require multiple records (e.g. very large Certificate messages).
- */
- void processLoop() throws IOException {
-
- // need to read off 4 bytes at least to get the handshake
- // message type and length.
- while (input.available() >= 4) {
- byte messageType;
- int messageLen;
-
- /*
- * See if we can read the handshake message header, and
- * then the entire handshake message. If not, wait till
- * we can read and process an entire message.
- */
- input.mark(4);
-
- messageType = (byte)input.getInt8();
- messageLen = input.getInt24();
-
- if (input.available() < messageLen) {
- input.reset();
- return;
- }
-
- /*
- * Process the messsage. We require
- * that processMessage() consumes the entire message. In
- * lieu of explicit error checks (how?!) we assume that the
- * data will look like garbage on encoding/processing errors,
- * and that other protocol code will detect such errors.
- *
- * Note that digesting is normally deferred till after the
- * message has been processed, though to process at least the
- * client's Finished message (i.e. send the server's) we need
- * to acccelerate that digesting.
- *
- * Also, note that hello request messages are never hashed;
- * that includes the hello request header, too.
- */
- if (messageType == HandshakeMessage.ht_hello_request) {
- input.reset();
- processMessage(messageType, messageLen);
- input.ignore(4 + messageLen);
- } else {
- input.mark(messageLen);
- processMessage(messageType, messageLen);
- input.digestNow();
- }
- }
- }
-
-
- /**
- * Returns true iff the handshaker has been activated.
- *
- * In activated state, the handshaker may not send any messages out.
- */
- boolean activated() {
- return state >= -1;
- }
-
- /**
- * Returns true iff the handshaker has sent any messages.
- */
- boolean started() {
- return state >= 0; // 0: HandshakeMessage.ht_hello_request
- // 1: HandshakeMessage.ht_client_hello
- }
-
-
- /*
- * Used to kickstart the negotiation ... either writing a
- * ClientHello or a HelloRequest as appropriate, whichever
- * the subclass returns. NOP if handshaking's already started.
- */
- void kickstart() throws IOException {
- if (state >= 0) {
- return;
- }
-
- HandshakeMessage m = getKickstartMessage();
-
- if (debug != null && Debug.isOn("handshake")) {
- m.print(System.out);
- }
- m.write(output);
- output.flush();
-
- state = m.messageType();
- }
-
- /**
- * Both client and server modes can start handshaking; but the
- * message they send to do so is different.
- */
- abstract HandshakeMessage getKickstartMessage() throws SSLException;
-
- /*
- * Client and Server side protocols are each driven though this
- * call, which processes a single message and drives the appropriate
- * side of the protocol state machine (depending on the subclass).
- */
- abstract void processMessage(byte messageType, int messageLen)
- throws IOException;
-
- /*
- * Most alerts in the protocol relate to handshaking problems.
- * Alerts are detected as the connection reads data.
- */
- abstract void handshakeAlert(byte description) throws SSLProtocolException;
-
- /*
- * Sends a change cipher spec message and updates the write side
- * cipher state so that future messages use the just-negotiated spec.
- */
- void sendChangeCipherSpec(Finished mesg, boolean lastMessage)
- throws IOException {
-
- output.flush(); // i.e. handshake data
-
- /*
- * The write cipher state is protected by the connection write lock
- * so we must grab it while making the change. We also
- * make sure no writes occur between sending the ChangeCipherSpec
- * message, installing the new cipher state, and sending the
- * Finished message.
- *
- * We already hold SSLEngine/SSLSocket "this" by virtue
- * of this being called from the readRecord code.
- */
- OutputRecord r;
- if (conn != null) {
- r = new OutputRecord(Record.ct_change_cipher_spec);
- } else {
- r = new EngineOutputRecord(Record.ct_change_cipher_spec, engine);
- }
-
- r.setVersion(protocolVersion);
- r.write(1); // single byte of data
-
- if (conn != null) {
- conn.writeLock.lock();
- try {
- conn.writeRecord(r);
- conn.changeWriteCiphers();
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- mesg.write(output);
- output.flush();
- } finally {
- conn.writeLock.unlock();
- }
- } else {
- synchronized (engine.writeLock) {
- engine.writeRecord((EngineOutputRecord)r);
- engine.changeWriteCiphers();
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- mesg.write(output);
-
- if (lastMessage) {
- output.setFinishedMsg();
- }
- output.flush();
- }
- }
- }
-
- /*
- * Single access point to key calculation logic. Given the
- * pre-master secret and the nonces from client and server,
- * produce all the keying material to be used.
- */
- void calculateKeys(SecretKey preMasterSecret, ProtocolVersion version) {
- SecretKey master = calculateMasterSecret(preMasterSecret, version);
- session.setMasterSecret(master);
- calculateConnectionKeys(master);
- }
-
-
- /*
- * Calculate the master secret from its various components. This is
- * used for key exchange by all cipher suites.
- *
- * The master secret is the catenation of three MD5 hashes, each
- * consisting of the pre-master secret and a SHA1 hash. Those three
- * SHA1 hashes are of (different) constant strings, the pre-master
- * secret, and the nonces provided by the client and the server.
- */
- private SecretKey calculateMasterSecret(SecretKey preMasterSecret,
- ProtocolVersion requestedVersion) {
-
- if (debug != null && Debug.isOn("keygen")) {
- HexDumpEncoder dump = new HexDumpEncoder();
-
- System.out.println("SESSION KEYGEN:");
-
- System.out.println("PreMaster Secret:");
- printHex(dump, preMasterSecret.getEncoded());
-
- // Nonces are dumped with connection keygen, no
- // benefit to doing it twice
- }
-
- // What algs/params do we need to use?
- String masterAlg;
- PRF prf;
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- masterAlg = "SunTls12MasterSecret";
- prf = cipherSuite.prfAlg;
- } else {
- masterAlg = "SunTlsMasterSecret";
- prf = P_NONE;
- }
-
- String prfHashAlg = prf.getPRFHashAlg();
- int prfHashLength = prf.getPRFHashLength();
- int prfBlockSize = prf.getPRFBlockSize();
-
- TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec(
- preMasterSecret, protocolVersion.major, protocolVersion.minor,
- clnt_random.random_bytes, svr_random.random_bytes,
- prfHashAlg, prfHashLength, prfBlockSize);
-
- SecretKey masterSecret;
- try {
- KeyGenerator kg = JsseJce.getKeyGenerator(masterAlg);
- kg.init(spec);
- masterSecret = kg.generateKey();
- } catch (GeneralSecurityException e) {
- // For RSA premaster secrets, do not signal a protocol error
- // due to the Bleichenbacher attack. See comments further down.
- if (!preMasterSecret.getAlgorithm().equals(
- "TlsRsaPremasterSecret")) {
- throw new ProviderException(e);
- }
-
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("RSA master secret generation error:");
- e.printStackTrace(System.out);
- }
-
- if (requestedVersion != null) {
- preMasterSecret =
- RSAClientKeyExchange.generateDummySecret(requestedVersion);
- } else {
- preMasterSecret =
- RSAClientKeyExchange.generateDummySecret(protocolVersion);
- }
-
- // recursive call with new premaster secret
- return calculateMasterSecret(preMasterSecret, null);
- }
-
- // if no version check requested (client side handshake), or version
- // information is not available (not an RSA premaster secret),
- // return master secret immediately.
- if ((requestedVersion == null) ||
- !(masterSecret instanceof TlsMasterSecret)) {
- return masterSecret;
- }
-
- // we have checked the ClientKeyExchange message when reading TLS
- // record, the following check is necessary to ensure that
- // JCE provider does not ignore the checking, or the previous
- // checking process bypassed the premaster secret version checking.
- TlsMasterSecret tlsKey = (TlsMasterSecret)masterSecret;
- int major = tlsKey.getMajorVersion();
- int minor = tlsKey.getMinorVersion();
- if ((major < 0) || (minor < 0)) {
- return masterSecret;
- }
-
- // check if the premaster secret version is ok
- // the specification says that it must be the maximum version supported
- // by the client from its ClientHello message. However, many
- // implementations send the negotiated version, so accept both
- // for SSL v3.0 and TLS v1.0.
- // NOTE that we may be comparing two unsupported version numbers, which
- // is why we cannot use object reference equality in this special case.
- ProtocolVersion premasterVersion =
- ProtocolVersion.valueOf(major, minor);
- boolean versionMismatch = (premasterVersion.v != requestedVersion.v);
-
- /*
- * we never checked the client_version in server side
- * for TLS v1.0 and SSL v3.0. For compatibility, we
- * maintain this behavior.
- */
- if (versionMismatch && requestedVersion.v <= ProtocolVersion.TLS10.v) {
- versionMismatch = (premasterVersion.v != protocolVersion.v);
- }
-
- if (versionMismatch == false) {
- // check passed, return key
- return masterSecret;
- }
-
- // Due to the Bleichenbacher attack, do not signal a protocol error.
- // Generate a random premaster secret and continue with the handshake,
- // which will fail when verifying the finished messages.
- // For more information, see comments in PreMasterSecret.
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("RSA PreMasterSecret version error: expected"
- + protocolVersion + " or " + requestedVersion + ", decrypted: "
- + premasterVersion);
- }
- preMasterSecret =
- RSAClientKeyExchange.generateDummySecret(requestedVersion);
-
- // recursive call with new premaster secret
- return calculateMasterSecret(preMasterSecret, null);
- }
-
- /*
- * Calculate the keys needed for this connection, once the session's
- * master secret has been calculated. Uses the master key and nonces;
- * the amount of keying material generated is a function of the cipher
- * suite that's been negotiated.
- *
- * This gets called both on the "full handshake" (where we exchanged
- * a premaster secret and started a new session) as well as on the
- * "fast handshake" (where we just resumed a pre-existing session).
- */
- void calculateConnectionKeys(SecretKey masterKey) {
- /*
- * For both the read and write sides of the protocol, we use the
- * master to generate MAC secrets and cipher keying material. Block
- * ciphers need initialization vectors, which we also generate.
- *
- * First we figure out how much keying material is needed.
- */
- int hashSize = cipherSuite.macAlg.size;
- boolean is_exportable = cipherSuite.exportable;
- BulkCipher cipher = cipherSuite.cipher;
- int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0;
-
- // Which algs/params do we need to use?
- String keyMaterialAlg;
- PRF prf;
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- keyMaterialAlg = "SunTls12KeyMaterial";
- prf = cipherSuite.prfAlg;
- } else {
- keyMaterialAlg = "SunTlsKeyMaterial";
- prf = P_NONE;
- }
-
- String prfHashAlg = prf.getPRFHashAlg();
- int prfHashLength = prf.getPRFHashLength();
- int prfBlockSize = prf.getPRFBlockSize();
-
- TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(
- masterKey, protocolVersion.major, protocolVersion.minor,
- clnt_random.random_bytes, svr_random.random_bytes,
- cipher.algorithm, cipher.keySize, expandedKeySize,
- cipher.ivSize, hashSize,
- prfHashAlg, prfHashLength, prfBlockSize);
-
- try {
- KeyGenerator kg = JsseJce.getKeyGenerator(keyMaterialAlg);
- kg.init(spec);
- TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey();
-
- clntWriteKey = keySpec.getClientCipherKey();
- svrWriteKey = keySpec.getServerCipherKey();
-
- // Return null if IVs are not supposed to be generated.
- // e.g. TLS 1.1+.
- clntWriteIV = keySpec.getClientIv();
- svrWriteIV = keySpec.getServerIv();
-
- clntMacSecret = keySpec.getClientMacKey();
- svrMacSecret = keySpec.getServerMacKey();
- } catch (GeneralSecurityException e) {
- throw new ProviderException(e);
- }
-
- //
- // Dump the connection keys as they're generated.
- //
- if (debug != null && Debug.isOn("keygen")) {
- synchronized (System.out) {
- HexDumpEncoder dump = new HexDumpEncoder();
-
- System.out.println("CONNECTION KEYGEN:");
-
- // Inputs:
- System.out.println("Client Nonce:");
- printHex(dump, clnt_random.random_bytes);
- System.out.println("Server Nonce:");
- printHex(dump, svr_random.random_bytes);
- System.out.println("Master Secret:");
- printHex(dump, masterKey.getEncoded());
-
- // Outputs:
- System.out.println("Client MAC write Secret:");
- printHex(dump, clntMacSecret.getEncoded());
- System.out.println("Server MAC write Secret:");
- printHex(dump, svrMacSecret.getEncoded());
-
- if (clntWriteKey != null) {
- System.out.println("Client write key:");
- printHex(dump, clntWriteKey.getEncoded());
- System.out.println("Server write key:");
- printHex(dump, svrWriteKey.getEncoded());
- } else {
- System.out.println("... no encryption keys used");
- }
-
- if (clntWriteIV != null) {
- System.out.println("Client write IV:");
- printHex(dump, clntWriteIV.getIV());
- System.out.println("Server write IV:");
- printHex(dump, svrWriteIV.getIV());
- } else {
- if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
- System.out.println(
- "... no IV derived for this protocol");
- } else {
- System.out.println("... no IV used for this cipher");
- }
- }
- System.out.flush();
- }
- }
- }
-
- private static void printHex(HexDumpEncoder dump, byte[] bytes) {
- if (bytes == null) {
- System.out.println("(key bytes not available)");
- } else {
- try {
- dump.encodeBuffer(bytes, System.out);
- } catch (IOException e) {
- // just for debugging, ignore this
- }
- }
- }
-
- /**
- * Throw an SSLException with the specified message and cause.
- * Shorthand until a new SSLException constructor is added.
- * This method never returns.
- */
- static void throwSSLException(String msg, Throwable cause)
- throws SSLException {
- SSLException e = new SSLException(msg);
- e.initCause(cause);
- throw e;
- }
-
-
- /*
- * Implement a simple task delegator.
- *
- * We are currently implementing this as a single delegator, may
- * try for parallel tasks later. Client Authentication could
- * benefit from this, where ClientKeyExchange/CertificateVerify
- * could be carried out in parallel.
- */
- class DelegatedTask<E> implements Runnable {
-
- private PrivilegedExceptionAction<E> pea;
-
- DelegatedTask(PrivilegedExceptionAction<E> pea) {
- this.pea = pea;
- }
-
- public void run() {
- synchronized (engine) {
- try {
- AccessController.doPrivileged(pea, engine.getAcc());
- } catch (PrivilegedActionException pae) {
- thrown = pae.getException();
- } catch (RuntimeException rte) {
- thrown = rte;
- }
- delegatedTask = null;
- taskDelegated = false;
- }
- }
- }
-
- private <T> void delegateTask(PrivilegedExceptionAction<T> pea) {
- delegatedTask = new DelegatedTask<T>(pea);
- taskDelegated = false;
- thrown = null;
- }
-
- DelegatedTask getTask() {
- if (!taskDelegated) {
- taskDelegated = true;
- return delegatedTask;
- } else {
- return null;
- }
- }
-
- /*
- * See if there are any tasks which need to be delegated
- *
- * Locked by SSLEngine.this.
- */
- boolean taskOutstanding() {
- return (delegatedTask != null);
- }
-
- /*
- * The previous caller failed for some reason, report back the
- * Exception. We won't worry about Error's.
- *
- * Locked by SSLEngine.this.
- */
- void checkThrown() throws SSLException {
- synchronized (thrownLock) {
- if (thrown != null) {
-
- String msg = thrown.getMessage();
-
- if (msg == null) {
- msg = "Delegated task threw Exception/Error";
- }
-
- /*
- * See what the underlying type of exception is. We should
- * throw the same thing. Chain thrown to the new exception.
- */
- Exception e = thrown;
- thrown = null;
-
- if (e instanceof RuntimeException) {
- throw (RuntimeException)
- new RuntimeException(msg).initCause(e);
- } else if (e instanceof SSLHandshakeException) {
- throw (SSLHandshakeException)
- new SSLHandshakeException(msg).initCause(e);
- } else if (e instanceof SSLKeyException) {
- throw (SSLKeyException)
- new SSLKeyException(msg).initCause(e);
- } else if (e instanceof SSLPeerUnverifiedException) {
- throw (SSLPeerUnverifiedException)
- new SSLPeerUnverifiedException(msg).initCause(e);
- } else if (e instanceof SSLProtocolException) {
- throw (SSLProtocolException)
- new SSLProtocolException(msg).initCause(e);
- } else {
- /*
- * If it's SSLException or any other Exception,
- * we'll wrap it in an SSLException.
- */
- throw (SSLException)
- new SSLException(msg).initCause(e);
- }
- }
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/HelloExtensions.java b/ojluni/src/main/java/sun/security/ssl/HelloExtensions.java
deleted file mode 100755
index 9db6927..0000000
--- a/ojluni/src/main/java/sun/security/ssl/HelloExtensions.java
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.*;
-
-import java.security.spec.ECParameterSpec;
-
-import javax.net.ssl.SSLProtocolException;
-
-/**
- * This file contains all the classes relevant to TLS Extensions for the
- * ClientHello and ServerHello messages. The extension mechanism and
- * several extensions are defined in RFC 3546. Additional extensions are
- * defined in the ECC RFC 4492.
- *
- * Currently, only the two ECC extensions are fully supported.
- *
- * The classes contained in this file are:
- * . HelloExtensions: a List of extensions as used in the client hello
- * and server hello messages.
- * . ExtensionType: an enum style class for the extension type
- * . HelloExtension: abstract base class for all extensions. All subclasses
- * must be immutable.
- *
- * . UnknownExtension: used to represent all parsed extensions that we do not
- * explicitly support.
- * . ServerNameExtension: the server_name extension.
- * . SignatureAlgorithmsExtension: the signature_algorithms extension.
- * . SupportedEllipticCurvesExtension: the ECC supported curves extension.
- * . SupportedEllipticPointFormatsExtension: the ECC supported point formats
- * (compressed/uncompressed) extension.
- *
- * @since 1.6
- * @author Andreas Sterbenz
- */
-final class HelloExtensions {
-
- private List<HelloExtension> extensions;
- private int encodedLength;
-
- HelloExtensions() {
- extensions = Collections.emptyList();
- }
-
- HelloExtensions(HandshakeInStream s) throws IOException {
- int len = s.getInt16();
- extensions = new ArrayList<HelloExtension>();
- encodedLength = len + 2;
- while (len > 0) {
- int type = s.getInt16();
- int extlen = s.getInt16();
- ExtensionType extType = ExtensionType.get(type);
- HelloExtension extension;
- if (extType == ExtensionType.EXT_SERVER_NAME) {
- extension = new ServerNameExtension(s, extlen);
- } else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) {
- extension = new SignatureAlgorithmsExtension(s, extlen);
- } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) {
- extension = new SupportedEllipticCurvesExtension(s, extlen);
- } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) {
- extension =
- new SupportedEllipticPointFormatsExtension(s, extlen);
- } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) {
- extension = new RenegotiationInfoExtension(s, extlen);
- } else {
- extension = new UnknownExtension(s, extlen, extType);
- }
- extensions.add(extension);
- len -= extlen + 4;
- }
- if (len != 0) {
- throw new SSLProtocolException(
- "Error parsing extensions: extra data");
- }
- }
-
- // Return the List of extensions. Must not be modified by the caller.
- List<HelloExtension> list() {
- return extensions;
- }
-
- void add(HelloExtension ext) {
- if (extensions.isEmpty()) {
- extensions = new ArrayList<HelloExtension>();
- }
- extensions.add(ext);
- encodedLength = -1;
- }
-
- HelloExtension get(ExtensionType type) {
- for (HelloExtension ext : extensions) {
- if (ext.type == type) {
- return ext;
- }
- }
- return null;
- }
-
- int length() {
- if (encodedLength >= 0) {
- return encodedLength;
- }
- if (extensions.isEmpty()) {
- encodedLength = 0;
- } else {
- encodedLength = 2;
- for (HelloExtension ext : extensions) {
- encodedLength += ext.length();
- }
- }
- return encodedLength;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- int length = length();
- if (length == 0) {
- return;
- }
- s.putInt16(length - 2);
- for (HelloExtension ext : extensions) {
- ext.send(s);
- }
- }
-
- void print(PrintStream s) throws IOException {
- for (HelloExtension ext : extensions) {
- s.println(ext.toString());
- }
- }
-}
-
-final class ExtensionType {
-
- final int id;
- final String name;
-
- private ExtensionType(int id, String name) {
- this.id = id;
- this.name = name;
- }
-
- public String toString() {
- return name;
- }
-
- static List<ExtensionType> knownExtensions = new ArrayList<>(9);
-
- static ExtensionType get(int id) {
- for (ExtensionType ext : knownExtensions) {
- if (ext.id == id) {
- return ext;
- }
- }
- return new ExtensionType(id, "type_" + id);
- }
-
- private static ExtensionType e(int id, String name) {
- ExtensionType ext = new ExtensionType(id, name);
- knownExtensions.add(ext);
- return ext;
- }
-
- // extensions defined in RFC 3546
- final static ExtensionType EXT_SERVER_NAME =
- e(0x0000, "server_name"); // IANA registry value: 0
- final static ExtensionType EXT_MAX_FRAGMENT_LENGTH =
- e(0x0001, "max_fragment_length"); // IANA registry value: 1
- final static ExtensionType EXT_CLIENT_CERTIFICATE_URL =
- e(0x0002, "client_certificate_url"); // IANA registry value: 2
- final static ExtensionType EXT_TRUSTED_CA_KEYS =
- e(0x0003, "trusted_ca_keys"); // IANA registry value: 3
- final static ExtensionType EXT_TRUNCATED_HMAC =
- e(0x0004, "truncated_hmac"); // IANA registry value: 4
- final static ExtensionType EXT_STATUS_REQUEST =
- e(0x0005, "status_request"); // IANA registry value: 5
-
- // extensions defined in RFC 4681
- final static ExtensionType EXT_USER_MAPPING =
- e(0x0006, "user_mapping"); // IANA registry value: 6
-
- // extensions defined in RFC 5081
- final static ExtensionType EXT_CERT_TYPE =
- e(0x0009, "cert_type"); // IANA registry value: 9
-
- // extensions defined in RFC 4492 (ECC)
- final static ExtensionType EXT_ELLIPTIC_CURVES =
- e(0x000A, "elliptic_curves"); // IANA registry value: 10
- final static ExtensionType EXT_EC_POINT_FORMATS =
- e(0x000B, "ec_point_formats"); // IANA registry value: 11
-
- // extensions defined in RFC 5054
- final static ExtensionType EXT_SRP =
- e(0x000C, "srp"); // IANA registry value: 12
-
- // extensions defined in RFC 5246
- final static ExtensionType EXT_SIGNATURE_ALGORITHMS =
- e(0x000D, "signature_algorithms"); // IANA registry value: 13
-
- // extensions defined in RFC 5746
- final static ExtensionType EXT_RENEGOTIATION_INFO =
- e(0xff01, "renegotiation_info"); // IANA registry value: 65281
-}
-
-abstract class HelloExtension {
-
- final ExtensionType type;
-
- HelloExtension(ExtensionType type) {
- this.type = type;
- }
-
- // Length of the encoded extension, including the type and length fields
- abstract int length();
-
- abstract void send(HandshakeOutStream s) throws IOException;
-
- public abstract String toString();
-
-}
-
-final class UnknownExtension extends HelloExtension {
-
- private final byte[] data;
-
- UnknownExtension(HandshakeInStream s, int len, ExtensionType type)
- throws IOException {
- super(type);
- data = new byte[len];
- // s.read() does not handle 0-length arrays.
- if (len != 0) {
- s.read(data);
- }
- }
-
- int length() {
- return 4 + data.length;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putInt16(type.id);
- s.putBytes16(data);
- }
-
- public String toString() {
- return "Unsupported extension " + type + ", data: " +
- Debug.toString(data);
- }
-}
-
-/*
- * [RFC4366] To facilitate secure connections to servers that host multiple
- * 'virtual' servers at a single underlying network address, clients MAY
- * include an extension of type "server_name" in the (extended) client hello.
- * The "extension_data" field of this extension SHALL contain "ServerNameList"
- * where:
- *
- * struct {
- * NameType name_type;
- * select (name_type) {
- * case host_name: HostName;
- * } name;
- * } ServerName;
- *
- * enum {
- * host_name(0), (255)
- * } NameType;
- *
- * opaque HostName<1..2^16-1>;
- *
- * struct {
- * ServerName server_name_list<1..2^16-1>
- * } ServerNameList;
- */
-final class ServerNameExtension extends HelloExtension {
-
- final static int NAME_HOST_NAME = 0;
-
- private List<ServerName> names;
- private int listLength; // ServerNameList length
-
- ServerNameExtension(List<String> hostnames) throws IOException {
- super(ExtensionType.EXT_SERVER_NAME);
-
- listLength = 0;
- names = new ArrayList<ServerName>(hostnames.size());
- for (String hostname : hostnames) {
- if (hostname != null && hostname.length() != 0) {
- // we only support DNS hostname now.
- ServerName serverName =
- new ServerName(NAME_HOST_NAME, hostname);
- names.add(serverName);
- listLength += serverName.length;
- }
- }
-
- // As we only support DNS hostname now, the hostname list must
- // not contain more than one hostname
- if (names.size() > 1) {
- throw new SSLProtocolException(
- "The ServerNameList MUST NOT contain more than " +
- "one name of the same name_type");
- }
-
- // We only need to add "server_name" extension in ClientHello unless
- // we support SNI in server side in the future. It is possible that
- // the SNI is empty in ServerHello. As we don't support SNI in
- // ServerHello now, we will throw exception for empty list for now.
- if (listLength == 0) {
- throw new SSLProtocolException(
- "The ServerNameList cannot be empty");
- }
- }
-
- ServerNameExtension(HandshakeInStream s, int len)
- throws IOException {
- super(ExtensionType.EXT_SERVER_NAME);
-
- int remains = len;
- if (len >= 2) { // "server_name" extension in ClientHello
- listLength = s.getInt16(); // ServerNameList length
- if (listLength == 0 || listLength + 2 != len) {
- throw new SSLProtocolException(
- "Invalid " + type + " extension");
- }
-
- remains -= 2;
- names = new ArrayList<ServerName>();
- while (remains > 0) {
- ServerName name = new ServerName(s);
- names.add(name);
- remains -= name.length;
-
- // we may need to check the duplicated ServerName type
- }
- } else if (len == 0) { // "server_name" extension in ServerHello
- listLength = 0;
- names = Collections.<ServerName>emptyList();
- }
-
- if (remains != 0) {
- throw new SSLProtocolException("Invalid server_name extension");
- }
- }
-
- static class ServerName {
- final int length;
- final int type;
- final byte[] data;
- final String hostname;
-
- ServerName(int type, String hostname) throws IOException {
- this.type = type; // NameType
- this.hostname = hostname;
- this.data = hostname.getBytes("UTF8"); // HostName
- this.length = data.length + 3; // NameType: 1 byte
- // HostName length: 2 bytes
- }
-
- ServerName(HandshakeInStream s) throws IOException {
- type = s.getInt8(); // NameType
- data = s.getBytes16(); // HostName (length read in getBytes16)
- length = data.length + 3; // NameType: 1 byte
- // HostName length: 2 bytes
- if (type == NAME_HOST_NAME) {
- hostname = new String(data, "UTF8");
- } else {
- hostname = null;
- }
- }
-
- public String toString() {
- if (type == NAME_HOST_NAME) {
- return "host_name: " + hostname;
- } else {
- return "unknown-" + type + ": " + Debug.toString(data);
- }
- }
- }
-
- int length() {
- return listLength == 0 ? 4 : 6 + listLength;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putInt16(type.id);
- s.putInt16(listLength + 2);
- if (listLength != 0) {
- s.putInt16(listLength);
-
- for (ServerName name : names) {
- s.putInt8(name.type); // NameType
- s.putBytes16(name.data); // HostName
- }
- }
- }
-
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- for (ServerName name : names) {
- buffer.append("[" + name + "]");
- }
-
- return "Extension " + type + ", server_name: " + buffer;
- }
-}
-
-final class SupportedEllipticCurvesExtension extends HelloExtension {
-
- // the extension value to send in the ClientHello message
- static final SupportedEllipticCurvesExtension DEFAULT;
-
- private static final boolean fips;
-
- static {
- int[] ids;
- fips = SunJSSE.isFIPS();
- if (fips == false) {
- ids = new int[] {
- // NIST curves first
- // prefer NIST P-256, rest in order of increasing key length
- 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
- // non-NIST curves
- 15, 16, 17, 2, 18, 4, 5, 20, 8, 22,
- };
- } else {
- ids = new int[] {
- // same as above, but allow only NIST curves in FIPS mode
- 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
- };
- }
- DEFAULT = new SupportedEllipticCurvesExtension(ids);
- }
-
- private final int[] curveIds;
-
- private SupportedEllipticCurvesExtension(int[] curveIds) {
- super(ExtensionType.EXT_ELLIPTIC_CURVES);
- this.curveIds = curveIds;
- }
-
- SupportedEllipticCurvesExtension(HandshakeInStream s, int len)
- throws IOException {
- super(ExtensionType.EXT_ELLIPTIC_CURVES);
- int k = s.getInt16();
- if (((len & 1) != 0) || (k + 2 != len)) {
- throw new SSLProtocolException("Invalid " + type + " extension");
- }
- curveIds = new int[k >> 1];
- for (int i = 0; i < curveIds.length; i++) {
- curveIds[i] = s.getInt16();
- }
- }
-
- boolean contains(int index) {
- for (int curveId : curveIds) {
- if (index == curveId) {
- return true;
- }
- }
- return false;
- }
-
- // Return a reference to the internal curveIds array.
- // The caller must NOT modify the contents.
- int[] curveIds() {
- return curveIds;
- }
-
- int length() {
- return 6 + (curveIds.length << 1);
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putInt16(type.id);
- int k = curveIds.length << 1;
- s.putInt16(k + 2);
- s.putInt16(k);
- for (int curveId : curveIds) {
- s.putInt16(curveId);
- }
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("Extension " + type + ", curve names: {");
- boolean first = true;
- for (int curveId : curveIds) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- // first check if it is a known named curve, then try other cases.
- String oid = getCurveOid(curveId);
- if (oid != null) {
- ECParameterSpec spec = JsseJce.getECParameterSpec(oid);
- // this toString() output will look nice for the current
- // implementation of the ECParameterSpec class in the Sun
- // provider, but may not look good for other implementations.
- if (spec != null) {
- sb.append(spec.toString().split(" ")[0]);
- } else {
- sb.append(oid);
- }
- } else if (curveId == ARBITRARY_PRIME) {
- sb.append("arbitrary_explicit_prime_curves");
- } else if (curveId == ARBITRARY_CHAR2) {
- sb.append("arbitrary_explicit_char2_curves");
- } else {
- sb.append("unknown curve " + curveId);
- }
- }
- sb.append("}");
- return sb.toString();
- }
-
- // Test whether we support the curve with the given index.
- static boolean isSupported(int index) {
- if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) {
- return false;
- }
- if (fips == false) {
- // in non-FIPS mode, we support all valid indices
- return true;
- }
- return DEFAULT.contains(index);
- }
-
- static int getCurveIndex(ECParameterSpec params) {
- String oid = JsseJce.getNamedCurveOid(params);
- if (oid == null) {
- return -1;
- }
- Integer n = curveIndices.get(oid);
- return (n == null) ? -1 : n;
- }
-
- static String getCurveOid(int index) {
- if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) {
- return NAMED_CURVE_OID_TABLE[index];
- }
- return null;
- }
-
- private final static int ARBITRARY_PRIME = 0xff01;
- private final static int ARBITRARY_CHAR2 = 0xff02;
-
- // See sun.security.ec.NamedCurve for the OIDs
- private final static String[] NAMED_CURVE_OID_TABLE = new String[] {
- null, // (0) unused
- "1.3.132.0.1", // (1) sect163k1, NIST K-163
- "1.3.132.0.2", // (2) sect163r1
- "1.3.132.0.15", // (3) sect163r2, NIST B-163
- "1.3.132.0.24", // (4) sect193r1
- "1.3.132.0.25", // (5) sect193r2
- "1.3.132.0.26", // (6) sect233k1, NIST K-233
- "1.3.132.0.27", // (7) sect233r1, NIST B-233
- "1.3.132.0.3", // (8) sect239k1
- "1.3.132.0.16", // (9) sect283k1, NIST K-283
- "1.3.132.0.17", // (10) sect283r1, NIST B-283
- "1.3.132.0.36", // (11) sect409k1, NIST K-409
- "1.3.132.0.37", // (12) sect409r1, NIST B-409
- "1.3.132.0.38", // (13) sect571k1, NIST K-571
- "1.3.132.0.39", // (14) sect571r1, NIST B-571
- "1.3.132.0.9", // (15) secp160k1
- "1.3.132.0.8", // (16) secp160r1
- "1.3.132.0.30", // (17) secp160r2
- "1.3.132.0.31", // (18) secp192k1
- "1.2.840.10045.3.1.1", // (19) secp192r1, NIST P-192
- "1.3.132.0.32", // (20) secp224k1
- "1.3.132.0.33", // (21) secp224r1, NIST P-224
- "1.3.132.0.10", // (22) secp256k1
- "1.2.840.10045.3.1.7", // (23) secp256r1, NIST P-256
- "1.3.132.0.34", // (24) secp384r1, NIST P-384
- "1.3.132.0.35", // (25) secp521r1, NIST P-521
- };
-
- private final static Map<String,Integer> curveIndices;
-
- static {
- curveIndices = new HashMap<String,Integer>();
- for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) {
- curveIndices.put(NAMED_CURVE_OID_TABLE[i], i);
- }
- }
-
-}
-
-final class SupportedEllipticPointFormatsExtension extends HelloExtension {
-
- final static int FMT_UNCOMPRESSED = 0;
- final static int FMT_ANSIX962_COMPRESSED_PRIME = 1;
- final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2;
-
- static final HelloExtension DEFAULT =
- new SupportedEllipticPointFormatsExtension(
- new byte[] {FMT_UNCOMPRESSED});
-
- private final byte[] formats;
-
- private SupportedEllipticPointFormatsExtension(byte[] formats) {
- super(ExtensionType.EXT_EC_POINT_FORMATS);
- this.formats = formats;
- }
-
- SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len)
- throws IOException {
- super(ExtensionType.EXT_EC_POINT_FORMATS);
- formats = s.getBytes8();
- // RFC 4492 says uncompressed points must always be supported.
- // Check just to make sure.
- boolean uncompressed = false;
- for (int format : formats) {
- if (format == FMT_UNCOMPRESSED) {
- uncompressed = true;
- break;
- }
- }
- if (uncompressed == false) {
- throw new SSLProtocolException
- ("Peer does not support uncompressed points");
- }
- }
-
- int length() {
- return 5 + formats.length;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putInt16(type.id);
- s.putInt16(formats.length + 1);
- s.putBytes8(formats);
- }
-
- private static String toString(byte format) {
- int f = format & 0xff;
- switch (f) {
- case FMT_UNCOMPRESSED:
- return "uncompressed";
- case FMT_ANSIX962_COMPRESSED_PRIME:
- return "ansiX962_compressed_prime";
- case FMT_ANSIX962_COMPRESSED_CHAR2:
- return "ansiX962_compressed_char2";
- default:
- return "unknown-" + f;
- }
- }
-
- public String toString() {
- List<String> list = new ArrayList<>();
- for (byte format : formats) {
- list.add(toString(format));
- }
- return "Extension " + type + ", formats: " + list;
- }
-}
-
-/*
- * For secure renegotiation, RFC5746 defines a new TLS extension,
- * "renegotiation_info" (with extension type 0xff01), which contains a
- * cryptographic binding to the enclosing TLS connection (if any) for
- * which the renegotiation is being performed. The "extension data"
- * field of this extension contains a "RenegotiationInfo" structure:
- *
- * struct {
- * opaque renegotiated_connection<0..255>;
- * } RenegotiationInfo;
- */
-final class RenegotiationInfoExtension extends HelloExtension {
- private final byte[] renegotiated_connection;
-
- RenegotiationInfoExtension(byte[] clientVerifyData,
- byte[] serverVerifyData) {
- super(ExtensionType.EXT_RENEGOTIATION_INFO);
-
- if (clientVerifyData.length != 0) {
- renegotiated_connection =
- new byte[clientVerifyData.length + serverVerifyData.length];
- System.arraycopy(clientVerifyData, 0, renegotiated_connection,
- 0, clientVerifyData.length);
-
- if (serverVerifyData.length != 0) {
- System.arraycopy(serverVerifyData, 0, renegotiated_connection,
- clientVerifyData.length, serverVerifyData.length);
- }
- } else {
- // ignore both the client and server verify data.
- renegotiated_connection = new byte[0];
- }
- }
-
- RenegotiationInfoExtension(HandshakeInStream s, int len)
- throws IOException {
- super(ExtensionType.EXT_RENEGOTIATION_INFO);
-
- // check the extension length
- if (len < 1) {
- throw new SSLProtocolException("Invalid " + type + " extension");
- }
-
- int renegoInfoDataLen = s.getInt8();
- if (renegoInfoDataLen + 1 != len) { // + 1 = the byte we just read
- throw new SSLProtocolException("Invalid " + type + " extension");
- }
-
- renegotiated_connection = new byte[renegoInfoDataLen];
- if (renegoInfoDataLen != 0) {
- s.read(renegotiated_connection, 0, renegoInfoDataLen);
- }
- }
-
-
- // Length of the encoded extension, including the type and length fields
- int length() {
- return 5 + renegotiated_connection.length;
- }
-
- void send(HandshakeOutStream s) throws IOException {
- s.putInt16(type.id);
- s.putInt16(renegotiated_connection.length + 1);
- s.putBytes8(renegotiated_connection);
- }
-
- boolean isEmpty() {
- return renegotiated_connection.length == 0;
- }
-
- byte[] getRenegotiatedConnection() {
- return renegotiated_connection;
- }
-
- public String toString() {
- return "Extension " + type + ", renegotiated_connection: " +
- (renegotiated_connection.length == 0 ? "<empty>" :
- Debug.toString(renegotiated_connection));
- }
-
-}
-
-/*
- * [RFC5246] The client uses the "signature_algorithms" extension to
- * indicate to the server which signature/hash algorithm pairs may be
- * used in digital signatures. The "extension_data" field of this
- * extension contains a "supported_signature_algorithms" value.
- *
- * enum {
- * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
- * sha512(6), (255)
- * } HashAlgorithm;
- *
- * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
- * SignatureAlgorithm;
- *
- * struct {
- * HashAlgorithm hash;
- * SignatureAlgorithm signature;
- * } SignatureAndHashAlgorithm;
- *
- * SignatureAndHashAlgorithm
- * supported_signature_algorithms<2..2^16-2>;
- */
-final class SignatureAlgorithmsExtension extends HelloExtension {
-
- private Collection<SignatureAndHashAlgorithm> algorithms;
- private int algorithmsLen; // length of supported_signature_algorithms
-
- SignatureAlgorithmsExtension(
- Collection<SignatureAndHashAlgorithm> signAlgs) {
-
- super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
-
- algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs);
- algorithmsLen =
- SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size();
- }
-
- SignatureAlgorithmsExtension(HandshakeInStream s, int len)
- throws IOException {
- super(ExtensionType.EXT_SIGNATURE_ALGORITHMS);
-
- algorithmsLen = s.getInt16();
- if (algorithmsLen == 0 || algorithmsLen + 2 != len) {
- throw new SSLProtocolException("Invalid " + type + " extension");
- }
-
- algorithms = new ArrayList<SignatureAndHashAlgorithm>();
- int remains = algorithmsLen;
- int sequence = 0;
- while (remains > 1) { // needs at least two bytes
- int hash = s.getInt8(); // hash algorithm
- int signature = s.getInt8(); // signature algorithm
-
- SignatureAndHashAlgorithm algorithm =
- SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence);
- algorithms.add(algorithm);
- remains -= 2; // one byte for hash, one byte for signature
- }
-
- if (remains != 0) {
- throw new SSLProtocolException("Invalid server_name extension");
- }
- }
-
- Collection<SignatureAndHashAlgorithm> getSignAlgorithms() {
- return algorithms;
- }
-
- @Override
- int length() {
- return 6 + algorithmsLen;
- }
-
- @Override
- void send(HandshakeOutStream s) throws IOException {
- s.putInt16(type.id);
- s.putInt16(algorithmsLen + 2);
- s.putInt16(algorithmsLen);
-
- for (SignatureAndHashAlgorithm algorithm : algorithms) {
- s.putInt8(algorithm.getHashValue()); // HashAlgorithm
- s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm
- }
- }
-
- @Override
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- boolean opened = false;
- for (SignatureAndHashAlgorithm signAlg : algorithms) {
- if (opened) {
- buffer.append(", " + signAlg.getAlgorithmName());
- } else {
- buffer.append(signAlg.getAlgorithmName());
- opened = true;
- }
- }
-
- return "Extension " + type + ", signature_algorithms: " + buffer;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/InputRecord.java b/ojluni/src/main/java/sun/security/ssl/InputRecord.java
deleted file mode 100755
index f714488..0000000
--- a/ojluni/src/main/java/sun/security/ssl/InputRecord.java
+++ /dev/null
@@ -1,833 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-
-import javax.crypto.BadPaddingException;
-
-import javax.net.ssl.*;
-
-import sun.misc.HexDumpEncoder;
-
-
-/**
- * SSL 3.0 records, as pulled off a TCP stream. Input records are
- * basically buffers tied to a particular input stream ... a layer
- * above this must map these records into the model of a continuous
- * stream of data.
- *
- * Since this returns SSL 3.0 records, it's the layer that needs to
- * map SSL 2.0 style handshake records into SSL 3.0 ones for those
- * "old" clients that interop with both V2 and V3 servers. Not as
- * pretty as might be desired.
- *
- * NOTE: During handshaking, each message must be hashed to support
- * verification that the handshake process wasn't compromised.
- *
- * @author David Brownell
- */
-class InputRecord extends ByteArrayInputStream implements Record {
-
- private HandshakeHash handshakeHash;
- private int lastHashed;
- boolean formatVerified = true; // SSLv2 ruled out?
- private boolean isClosed;
- private boolean appDataValid;
-
- // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
- // and the first message we read is a ClientHello in V2 format, we convert
- // it to V3. Otherwise we throw an exception when encountering a V2 hello.
- private ProtocolVersion helloVersion;
-
- /* Class and subclass dynamic debugging support */
- static final Debug debug = Debug.getInstance("ssl");
-
- /* The existing record length */
- private int exlen;
-
- /* V2 handshake message */
- private byte v2Buf[];
-
- /*
- * Construct the record to hold the maximum sized input record.
- * Data will be filled in separately.
- */
- InputRecord() {
- super(new byte[maxRecordSize]);
- setHelloVersion(ProtocolVersion.DEFAULT_HELLO);
- pos = headerSize;
- count = headerSize;
- lastHashed = count;
- exlen = 0;
- v2Buf = null;
- }
-
- void setHelloVersion(ProtocolVersion helloVersion) {
- this.helloVersion = helloVersion;
- }
-
- ProtocolVersion getHelloVersion() {
- return helloVersion;
- }
-
- /*
- * Enable format checks if initial handshaking hasn't completed
- */
- void enableFormatChecks() {
- formatVerified = false;
- }
-
- // return whether the data in this record is valid, decrypted data
- boolean isAppDataValid() {
- return appDataValid;
- }
-
- void setAppDataValid(boolean value) {
- appDataValid = value;
- }
-
- /*
- * Return the content type of the record.
- */
- byte contentType() {
- return buf[0];
- }
-
- /*
- * For handshaking, we need to be able to hash every byte above the
- * record marking layer. This is where we're guaranteed to see those
- * bytes, so this is where we can hash them ... especially in the
- * case of hashing the initial V2 message!
- */
- void setHandshakeHash(HandshakeHash handshakeHash) {
- this.handshakeHash = handshakeHash;
- }
-
- HandshakeHash getHandshakeHash() {
- return handshakeHash;
- }
-
- void decrypt(MAC signer, CipherBox box) throws BadPaddingException {
-
- BadPaddingException reservedBPE = null;
- int tagLen = signer.MAClen();
- int cipheredLength = count - headerSize;
-
- if (!box.isNullCipher()) {
- // sanity check length of the ciphertext
- if (!box.sanityCheck(tagLen, cipheredLength)) {
- throw new BadPaddingException(
- "ciphertext sanity check failed");
- }
-
- try {
- // Note that the CipherBox.decrypt() does not change
- // the capacity of the buffer.
- count = headerSize +
- box.decrypt(buf, headerSize, cipheredLength, tagLen);
- } catch (BadPaddingException bpe) {
- // RFC 2246 states that decryption_failed should be used
- // for this purpose. However, that allows certain attacks,
- // so we just send bad record MAC. We also need to make
- // sure to always check the MAC to avoid a timing attack
- // for the same issue. See paper by Vaudenay et al and the
- // update in RFC 4346/5246.
- //
- // Failover to message authentication code checking.
- reservedBPE = bpe;
- }
- }
-
- if (tagLen != 0) {
- int macOffset = count - tagLen;
- int contentLen = macOffset - headerSize;
-
- // Note that although it is not necessary, we run the same MAC
- // computation and comparison on the payload for both stream
- // cipher and CBC block cipher.
- if (contentLen < 0) {
- // negative data length, something is wrong
- if (reservedBPE == null) {
- reservedBPE = new BadPaddingException("bad record");
- }
-
- // set offset of the dummy MAC
- macOffset = headerSize + cipheredLength - tagLen;
- contentLen = macOffset - headerSize;
- }
-
- count -= tagLen; // Set the count before any MAC checking
- // exception occurs, so that the following
- // process can read the actual decrypted
- // content (minus the MAC) in the fragment
- // if necessary.
-
- // Run MAC computation and comparison on the payload.
- if (checkMacTags(contentType(),
- buf, headerSize, contentLen, signer, false)) {
- if (reservedBPE == null) {
- reservedBPE = new BadPaddingException("bad record MAC");
- }
- }
-
- // Run MAC computation and comparison on the remainder.
- //
- // It is only necessary for CBC block cipher. It is used to get a
- // constant time of MAC computation and comparison on each record.
- if (box.isCBCMode()) {
- int remainingLen = calculateRemainingLen(
- signer, cipheredLength, contentLen);
-
- // NOTE: remainingLen may be bigger (less than 1 block of the
- // hash algorithm of the MAC) than the cipheredLength. However,
- // We won't need to worry about it because we always use a
- // maximum buffer for every record. We need a change here if
- // we use small buffer size in the future.
- if (remainingLen > buf.length) {
- // unlikely to happen, just a placehold
- throw new RuntimeException(
- "Internal buffer capacity error");
- }
-
- // Won't need to worry about the result on the remainder. And
- // then we won't need to worry about what's actual data to
- // check MAC tag on. We start the check from the header of the
- // buffer so that we don't need to construct a new byte buffer.
- checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
- }
- }
-
- // Is it a failover?
- if (reservedBPE != null) {
- throw reservedBPE;
- }
- }
-
- /*
- * Run MAC computation and comparison
- *
- * Please DON'T change the content of the byte buffer parameter!
- */
- static boolean checkMacTags(byte contentType, byte[] buffer,
- int offset, int contentLen, MAC signer, boolean isSimulated) {
-
- int tagLen = signer.MAClen();
- byte[] hash = signer.compute(
- contentType, buffer, offset, contentLen, isSimulated);
- if (hash == null || tagLen != hash.length) {
- // Something is wrong with MAC implementation.
- throw new RuntimeException("Internal MAC error");
- }
-
- int[] results = compareMacTags(buffer, offset + contentLen, hash);
- return (results[0] != 0);
- }
-
- /*
- * A constant-time comparison of the MAC tags.
- *
- * Please DON'T change the content of the byte buffer parameter!
- */
- private static int[] compareMacTags(
- byte[] buffer, int offset, byte[] tag) {
-
- // An array of hits is used to prevent Hotspot optimization for
- // the purpose of a constant-time check.
- int[] results = {0, 0}; // {missed #, matched #}
-
- // The caller ensures there are enough bytes available in the buffer.
- // So we won't need to check the length of the buffer.
- for (int i = 0; i < tag.length; i++) {
- if (buffer[offset + i] != tag[i]) {
- results[0]++; // mismatched bytes
- } else {
- results[1]++; // matched bytes
- }
- }
-
- return results;
- }
-
- /*
- * Calculate the length of a dummy buffer to run MAC computation
- * and comparison on the remainder.
- *
- * The caller MUST ensure that the fullLen is not less than usedLen.
- */
- static int calculateRemainingLen(
- MAC signer, int fullLen, int usedLen) {
-
- int blockLen = signer.hashBlockLen();
- int minimalPaddingLen = signer.minimalPaddingLen();
-
- // (blockLen - minimalPaddingLen) is the maximum message size of
- // the last block of hash function operation. See FIPS 180-4, or
- // MD5 specification.
- fullLen += 13 - (blockLen - minimalPaddingLen);
- usedLen += 13 - (blockLen - minimalPaddingLen);
-
- // Note: fullLen is always not less than usedLen, and blockLen
- // is always bigger than minimalPaddingLen, so we don't worry
- // about negative values. 0x01 is added to the result to ensure
- // that the return value is positive. The extra one byte does
- // not impact the overall MAC compression function evaluations.
- return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
- Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen();
- }
-
- /*
- * Well ... hello_request messages are _never_ hashed since we can't
- * know when they'd appear in the sequence.
- */
- void ignore(int bytes) {
- if (bytes > 0) {
- pos += bytes;
- lastHashed = pos;
- }
- }
-
- /*
- * We hash the (plaintext) we've processed, but only on demand.
- *
- * There is one place where we want to access the hash in the middle
- * of a record: client cert message gets hashed, and part of the
- * same record is the client cert verify message which uses that hash.
- * So we track how much we've read and hashed.
- */
- void doHashes() {
- int len = pos - lastHashed;
-
- if (len > 0) {
- hashInternal(buf, lastHashed, len);
- lastHashed = pos;
- }
- }
-
- /*
- * Need a helper function so we can hash the V2 hello correctly
- */
- private void hashInternal(byte databuf [], int offset, int len) {
- if (debug != null && Debug.isOn("data")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
-
- System.out.println("[read] MD5 and SHA1 hashes: len = "
- + len);
- hd.encodeBuffer(new ByteArrayInputStream(databuf, offset, len),
- System.out);
- } catch (IOException e) { }
- }
- handshakeHash.update(databuf, offset, len);
- }
-
-
- /*
- * Handshake messages may cross record boundaries. We "queue"
- * these in big buffers if we need to cope with this problem.
- * This is not anticipated to be a common case; if this turns
- * out to be wrong, this can readily be sped up.
- */
- void queueHandshake(InputRecord r) throws IOException {
- int len;
-
- /*
- * Hash any data that's read but unhashed.
- */
- doHashes();
-
- /*
- * Move any unread data to the front of the buffer,
- * flagging it all as unhashed.
- */
- if (pos > headerSize) {
- len = count - pos;
- if (len != 0) {
- System.arraycopy(buf, pos, buf, headerSize, len);
- }
- pos = headerSize;
- lastHashed = pos;
- count = headerSize + len;
- }
-
- /*
- * Grow "buf" if needed
- */
- len = r.available() + count;
- if (buf.length < len) {
- byte newbuf [];
-
- newbuf = new byte [len];
- System.arraycopy(buf, 0, newbuf, 0, count);
- buf = newbuf;
- }
-
- /*
- * Append the new buffer to this one.
- */
- System.arraycopy(r.buf, r.pos, buf, count, len - count);
- count = len;
-
- /*
- * Adjust lastHashed; important for now with clients which
- * send SSL V2 client hellos. This will go away eventually,
- * by buffer code cleanup.
- */
- len = r.lastHashed - r.pos;
- if (pos == headerSize) {
- lastHashed += len;
- } else {
- throw new SSLProtocolException("?? confused buffer hashing ??");
- }
- // we've read the record, advance the pointers
- r.pos = r.count;
- }
-
-
- /**
- * Prevent any more data from being read into this record,
- * and flag the record as holding no data.
- */
- public void close() {
- appDataValid = false;
- isClosed = true;
- mark = 0;
- pos = 0;
- count = 0;
- }
-
-
- /*
- * We may need to send this SSL v2 "No Cipher" message back, if we
- * are faced with an SSLv2 "hello" that's not saying "I talk v3".
- * It's the only one documented in the V2 spec as a fatal error.
- */
- private static final byte[] v2NoCipher = {
- (byte)0x80, (byte)0x03, // unpadded 3 byte record
- (byte)0x00, // ... error message
- (byte)0x00, (byte)0x01 // ... NO_CIPHER error
- };
-
- private int readFully(InputStream s, byte b[], int off, int len)
- throws IOException {
- int n = 0;
- while (n < len) {
- int readLen = s.read(b, off + n, len - n);
- if (readLen < 0) {
- return readLen;
- }
-
- if (debug != null && Debug.isOn("packet")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
- ByteBuffer bb = ByteBuffer.wrap(b, off + n, readLen);
-
- System.out.println("[Raw read]: length = " +
- bb.remaining());
- hd.encodeBuffer(bb, System.out);
- } catch (IOException e) { }
- }
-
- n += readLen;
- exlen += readLen;
- }
-
- return n;
- }
-
- /*
- * Read the SSL V3 record ... first time around, check to see if it
- * really IS a V3 record. Handle SSL V2 clients which can talk V3.0,
- * as well as real V3 record format; otherwise report an error.
- */
- void read(InputStream s, OutputStream o) throws IOException {
- if (isClosed) {
- return;
- }
-
- /*
- * For SSL it really _is_ an error if the other end went away
- * so ungracefully as to not shut down cleanly.
- */
- if(exlen < headerSize) {
- int really = readFully(s, buf, exlen, headerSize - exlen);
- if (really < 0) {
- throw new EOFException("SSL peer shut down incorrectly");
- }
-
- pos = headerSize;
- count = headerSize;
- lastHashed = pos;
- }
-
- /*
- * The first record might use some other record marking convention,
- * typically SSL v2 header. (PCT could also be detected here.)
- * This case is currently common -- Navigator 3.0 usually works
- * this way, as do IE 3.0 and other products.
- */
- if (!formatVerified) {
- formatVerified = true;
- /*
- * The first record must either be a handshake record or an
- * alert message. If it's not, it is either invalid or an
- * SSLv2 message.
- */
- if (buf[0] != ct_handshake && buf[0] != ct_alert) {
- handleUnknownRecord(s, o);
- } else {
- readV3Record(s, o);
- }
- } else { // formatVerified == true
- readV3Record(s, o);
- }
- }
-
- /**
- * Read a SSL/TLS record. Throw an IOException if the format is invalid.
- */
- private void readV3Record(InputStream s, OutputStream o)
- throws IOException {
- ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]);
- // Check if too old (currently not possible)
- // or if the major version does not match.
- // The actual version negotiation is in the handshaker classes
- if ((recordVersion.v < ProtocolVersion.MIN.v)
- || (recordVersion.major > ProtocolVersion.MAX.major)) {
- throw new SSLException(
- "Unsupported record version " + recordVersion);
- }
-
- /*
- * Get and check length, then the data.
- */
- int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff);
-
- /*
- * Check for upper bound.
- */
- if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
- throw new SSLProtocolException("Bad InputRecord size"
- + ", count = " + contentLen
- + ", buf.length = " + buf.length);
- }
-
- /*
- * Grow "buf" if needed. Since buf is maxRecordSize by default,
- * this only occurs when we receive records which violate the
- * SSL specification. This is a workaround for a Microsoft SSL bug.
- */
- if (contentLen > buf.length - headerSize) {
- byte[] newbuf = new byte[contentLen + headerSize];
- System.arraycopy(buf, 0, newbuf, 0, headerSize);
- buf = newbuf;
- }
-
- if (exlen < contentLen + headerSize) {
- int really = readFully(
- s, buf, exlen, contentLen + headerSize - exlen);
- if (really < 0) {
- throw new SSLException("SSL peer shut down incorrectly");
- }
- }
-
- // now we've got a complete record.
- count = contentLen + headerSize;
- exlen = 0;
-
- if (debug != null && Debug.isOn("record")) {
- if (count < 0 || count > (maxRecordSize - headerSize)) {
- System.out.println(Thread.currentThread().getName()
- + ", Bad InputRecord size" + ", count = " + count);
- }
- System.out.println(Thread.currentThread().getName()
- + ", READ: " + recordVersion + " "
- + contentName(contentType()) + ", length = " + available());
- }
- /*
- * then caller decrypts, verifies, and uncompresses
- */
- }
-
- /**
- * Deal with unknown records. Called if the first data we read on this
- * connection does not look like an SSL/TLS record. It could a SSLv2
- * message, or just garbage.
- */
- private void handleUnknownRecord(InputStream s, OutputStream o)
- throws IOException {
- /*
- * No? Oh well; does it look like a V2 "ClientHello"?
- * That'd be an unpadded handshake message; we don't
- * bother checking length just now.
- */
- if (((buf[0] & 0x080) != 0) && buf[2] == 1) {
- /*
- * if the user has disabled SSLv2Hello (using
- * setEnabledProtocol) then throw an
- * exception
- */
- if (helloVersion != ProtocolVersion.SSL20Hello) {
- throw new SSLHandshakeException("SSLv2Hello is disabled");
- }
-
- ProtocolVersion recordVersion =
- ProtocolVersion.valueOf(buf[3], buf[4]);
-
- if (recordVersion == ProtocolVersion.SSL20Hello) {
- /*
- * Looks like a V2 client hello, but not one saying
- * "let's talk SSLv3". So we send an SSLv2 error
- * message, one that's treated as fatal by clients.
- * (Otherwise we'll hang.)
- */
- try {
- writeBuffer(o, v2NoCipher, 0, v2NoCipher.length);
- } catch (Exception e) {
- /* NOTHING */
- }
- throw new SSLException("Unsupported SSL v2.0 ClientHello");
- }
-
- /*
- * If we can map this into a V3 ClientHello, read and
- * hash the rest of the V2 handshake, turn it into a
- * V3 ClientHello message, and pass it up.
- */
- int len = ((buf[0] & 0x7f) << 8) +
- (buf[1] & 0xff) - 3;
- if (v2Buf == null) {
- v2Buf = new byte[len];
- }
- if (exlen < len + headerSize) {
- int really = readFully(
- s, v2Buf, exlen - headerSize, len + headerSize - exlen);
- if (really < 0) {
- throw new EOFException("SSL peer shut down incorrectly");
- }
- }
-
- // now we've got a complete record.
- exlen = 0;
-
- hashInternal(buf, 2, 3);
- hashInternal(v2Buf, 0, len);
- V2toV3ClientHello(v2Buf);
- v2Buf = null;
- lastHashed = count;
-
- if (debug != null && Debug.isOn("record")) {
- System.out.println(
- Thread.currentThread().getName()
- + ", READ: SSL v2, contentType = "
- + contentName(contentType())
- + ", translated length = " + available());
- }
- return;
-
- } else {
- /*
- * Does it look like a V2 "ServerHello"?
- */
- if (((buf [0] & 0x080) != 0) && buf [2] == 4) {
- throw new SSLException(
- "SSL V2.0 servers are not supported.");
- }
-
- /*
- * If this is a V2 NoCipher message then this means
- * the other server doesn't support V3. Otherwise, we just
- * don't understand what it's saying.
- */
- for (int i = 0; i < v2NoCipher.length; i++) {
- if (buf[i] != v2NoCipher[i]) {
- throw new SSLException(
- "Unrecognized SSL message, plaintext connection?");
- }
- }
-
- throw new SSLException("SSL V2.0 servers are not supported.");
- }
- }
-
- /*
- * Actually do the write here. For SSLEngine's HS data,
- * we'll override this method and let it take the appropriate
- * action.
- */
- void writeBuffer(OutputStream s, byte [] buf, int off, int len)
- throws IOException {
- s.write(buf, 0, len);
- s.flush();
- }
-
- /*
- * Support "old" clients which are capable of SSL V3.0 protocol ... for
- * example, Navigator 3.0 clients. The V2 message is in the header and
- * the bytes passed as parameter. This routine translates the V2 message
- * into an equivalent V3 one.
- */
- private void V2toV3ClientHello(byte v2Msg []) throws SSLException
- {
- int i;
-
- /*
- * Build the first part of the V3 record header from the V2 one
- * that's now buffered up. (Lengths are fixed up later).
- */
- buf [0] = ct_handshake;
- buf [1] = buf [3]; // V3.x
- buf[2] = buf[4];
- // header [3..4] for handshake message length
- // count = 5;
-
- /*
- * Store the generic V3 handshake header: 4 bytes
- */
- buf [5] = 1; // HandshakeMessage.ht_client_hello
- // buf [6..8] for length of ClientHello (int24)
- // count += 4;
-
- /*
- * ClientHello header starts with SSL version
- */
- buf [9] = buf [1];
- buf [10] = buf [2];
- // count += 2;
- count = 11;
-
- /*
- * Start parsing the V2 message ...
- */
- int cipherSpecLen, sessionIdLen, nonceLen;
-
- cipherSpecLen = ((v2Msg [0] & 0xff) << 8) + (v2Msg [1] & 0xff);
- sessionIdLen = ((v2Msg [2] & 0xff) << 8) + (v2Msg [3] & 0xff);
- nonceLen = ((v2Msg [4] & 0xff) << 8) + (v2Msg [5] & 0xff);
-
- /*
- * Copy Random value/nonce ... if less than the 32 bytes of
- * a V3 "Random", right justify and zero pad to the left. Else
- * just take the last 32 bytes.
- */
- int offset = 6 + cipherSpecLen + sessionIdLen;
-
- if (nonceLen < 32) {
- for (i = 0; i < (32 - nonceLen); i++)
- buf [count++] = 0;
- System.arraycopy(v2Msg, offset, buf, count, nonceLen);
- count += nonceLen;
- } else {
- System.arraycopy(v2Msg, offset + (nonceLen - 32),
- buf, count, 32);
- count += 32;
- }
-
- /*
- * Copy Session ID (only one byte length!)
- */
- offset -= sessionIdLen;
- buf [count++] = (byte) sessionIdLen;
-
- System.arraycopy(v2Msg, offset, buf, count, sessionIdLen);
- count += sessionIdLen;
-
- /*
- * Copy and translate cipher suites ... V2 specs with first byte zero
- * are really V3 specs (in the last 2 bytes), just copy those and drop
- * the other ones. Preference order remains unchanged.
- *
- * Example: Netscape Navigator 3.0 (exportable) says:
- *
- * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5
- * 0/6, SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
- *
- * Microsoft Internet Explorer 3.0 (exportable) supports only
- *
- * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5
- */
- int j;
-
- offset -= cipherSpecLen;
- j = count + 2;
-
- for (i = 0; i < cipherSpecLen; i += 3) {
- if (v2Msg [offset + i] != 0)
- continue;
- buf [j++] = v2Msg [offset + i + 1];
- buf [j++] = v2Msg [offset + i + 2];
- }
-
- j -= count + 2;
- buf [count++] = (byte) (j >>> 8);
- buf [count++] = (byte) j;
- count += j;
-
- /*
- * Append compression methods (default/null only)
- */
- buf [count++] = 1;
- buf [count++] = 0; // Session.compression_null
-
- /*
- * Fill in lengths of the messages we synthesized (nested:
- * V3 handshake message within V3 record) and then return
- */
- buf [3] = (byte) (count - headerSize);
- buf [4] = (byte) ((count - headerSize) >>> 8);
-
- buf [headerSize + 1] = 0;
- buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8);
- buf [headerSize + 3] = (byte) ((count - headerSize) - 4);
-
- pos = headerSize;
- }
-
- /**
- * Return a description for the given content type. This method should be
- * in Record, but since that is an interface this is not possible.
- * Called from InputRecord and OutputRecord.
- */
- static String contentName(int contentType) {
- switch (contentType) {
- case ct_change_cipher_spec:
- return "Change Cipher Spec";
- case ct_alert:
- return "Alert";
- case ct_handshake:
- return "Handshake";
- case ct_application_data:
- return "Application Data";
- default:
- return "contentType = " + contentType;
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/JsseJce.java b/ojluni/src/main/java/sun/security/ssl/JsseJce.java
deleted file mode 100755
index d91b8f4..0000000
--- a/ojluni/src/main/java/sun/security/ssl/JsseJce.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.util.*;
-import java.math.BigInteger;
-
-import java.security.*;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.*;
-
-import javax.crypto.*;
-
-// explicit import to override the Provider class in this package
-import java.security.Provider;
-
-// need internal Sun classes for FIPS tricks
-import sun.security.jca.Providers;
-import sun.security.jca.ProviderList;
-
-import sun.security.ec.ECParameters;
-import sun.security.ec.NamedCurve;
-
-import static sun.security.ssl.SunJSSE.cryptoProvider;
-
-/**
- * This class contains a few static methods for interaction with the JCA/JCE
- * to obtain implementations, etc.
- *
- * @author Andreas Sterbenz
- */
-final class JsseJce {
-
- private final static Debug debug = Debug.getInstance("ssl");
-
- private final static ProviderList fipsProviderList;
-
- // Flag indicating whether EC crypto is available.
- // If null, then we have not checked yet.
- // If yes, then all the EC based crypto we need is available.
- private static Boolean ecAvailable;
-
- // Flag indicating whether Kerberos crypto is available.
- // If true, then all the Kerberos-based crypto we need is available.
- private final static boolean kerberosAvailable;
- static {
- boolean temp;
- try {
- AccessController.doPrivileged(
- new PrivilegedExceptionAction<Void>() {
- public Void run() throws Exception {
- // Test for Kerberos using the bootstrap class loader
- Class.forName("sun.security.krb5.PrincipalName", true,
- null);
- return null;
- }
- });
- temp = true;
-
- } catch (Exception e) {
- temp = false;
- }
- kerberosAvailable = temp;
- }
-
- static {
- // force FIPS flag initialization
- // Because isFIPS() is synchronized and cryptoProvider is not modified
- // after it completes, this also eliminates the need for any further
- // synchronization when accessing cryptoProvider
- if (SunJSSE.isFIPS() == false) {
- fipsProviderList = null;
- } else {
- // Setup a ProviderList that can be used by the trust manager
- // during certificate chain validation. All the crypto must be
- // from the FIPS provider, but we also allow the required
- // certificate related services from the SUN provider.
- Provider sun = Security.getProvider("SUN");
- if (sun == null) {
- throw new RuntimeException
- ("FIPS mode: SUN provider must be installed");
- }
- Provider sunCerts = new SunCertificates(sun);
- fipsProviderList = ProviderList.newList(cryptoProvider, sunCerts);
- }
- }
-
- private static final class SunCertificates extends Provider {
- SunCertificates(final Provider p) {
- super("SunCertificates", 1.0d, "SunJSSE internal");
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- // copy certificate related services from the Sun provider
- for (Map.Entry<Object,Object> entry : p.entrySet()) {
- String key = (String)entry.getKey();
- if (key.startsWith("CertPathValidator.")
- || key.startsWith("CertPathBuilder.")
- || key.startsWith("CertStore.")
- || key.startsWith("CertificateFactory.")) {
- put(key, entry.getValue());
- }
- }
- return null;
- }
- });
- }
- }
-
- /**
- * JCE transformation string for RSA with PKCS#1 v1.5 padding.
- * Can be used for encryption, decryption, signing, verifying.
- */
- final static String CIPHER_RSA_PKCS1 = "RSA/ECB/PKCS1Padding";
- /**
- * JCE transformation string for the stream cipher RC4.
- */
- final static String CIPHER_RC4 = "RC4";
- /**
- * JCE transformation string for DES in CBC mode without padding.
- */
- final static String CIPHER_DES = "DES/CBC/NoPadding";
- /**
- * JCE transformation string for (3-key) Triple DES in CBC mode
- * without padding.
- */
- final static String CIPHER_3DES = "DESede/CBC/NoPadding";
- /**
- * JCE transformation string for AES in CBC mode
- * without padding.
- */
- final static String CIPHER_AES = "AES/CBC/NoPadding";
- /**
- * JCA identifier string for DSA, i.e. a DSA with SHA-1.
- */
- final static String SIGNATURE_DSA = "DSA";
- /**
- * JCA identifier string for ECDSA, i.e. a ECDSA with SHA-1.
- */
- final static String SIGNATURE_ECDSA = "SHA1withECDSA";
- /**
- * JCA identifier string for Raw DSA, i.e. a DSA signature without
- * hashing where the application provides the SHA-1 hash of the data.
- * Note that the standard name is "NONEwithDSA" but we use "RawDSA"
- * for compatibility.
- */
- final static String SIGNATURE_RAWDSA = "RawDSA";
- /**
- * JCA identifier string for Raw ECDSA, i.e. a DSA signature without
- * hashing where the application provides the SHA-1 hash of the data.
- */
- final static String SIGNATURE_RAWECDSA = "NONEwithECDSA";
- /**
- * JCA identifier string for Raw RSA, i.e. a RSA PKCS#1 v1.5 signature
- * without hashing where the application provides the hash of the data.
- * Used for RSA client authentication with a 36 byte hash.
- */
- final static String SIGNATURE_RAWRSA = "NONEwithRSA";
- /**
- * JCA identifier string for the SSL/TLS style RSA Signature. I.e.
- * an signature using RSA with PKCS#1 v1.5 padding signing a
- * concatenation of an MD5 and SHA-1 digest.
- */
- final static String SIGNATURE_SSLRSA = "MD5andSHA1withRSA";
-
- private JsseJce() {
- // no instantiation of this class
- }
-
- synchronized static boolean isEcAvailable() {
- if (ecAvailable == null) {
- try {
- JsseJce.getSignature(SIGNATURE_ECDSA);
- JsseJce.getSignature(SIGNATURE_RAWECDSA);
- JsseJce.getKeyAgreement("ECDH");
- JsseJce.getKeyFactory("EC");
- JsseJce.getKeyPairGenerator("EC");
- ecAvailable = true;
- } catch (Exception e) {
- ecAvailable = false;
- }
- }
- return ecAvailable;
- }
-
- synchronized static void clearEcAvailable() {
- ecAvailable = null;
- }
-
- static boolean isKerberosAvailable() {
- return kerberosAvailable;
- }
-
- /**
- * Return an JCE cipher implementation for the specified algorithm.
- */
- static Cipher getCipher(String transformation)
- throws NoSuchAlgorithmException {
- try {
- if (cryptoProvider == null) {
- return Cipher.getInstance(transformation);
- } else {
- return Cipher.getInstance(transformation, cryptoProvider);
- }
- } catch (NoSuchPaddingException e) {
- throw new NoSuchAlgorithmException(e);
- }
- }
-
- /**
- * Return an JCA signature implementation for the specified algorithm.
- * The algorithm string should be one of the constants defined
- * in this class.
- */
- static Signature getSignature(String algorithm)
- throws NoSuchAlgorithmException {
- if (cryptoProvider == null) {
- return Signature.getInstance(algorithm);
- } else {
- // reference equality
- if (algorithm == SIGNATURE_SSLRSA) {
- // The SunPKCS11 provider currently does not support this
- // special algorithm. We allow a fallback in this case because
- // the SunJSSE implementation does the actual crypto using
- // a NONEwithRSA signature obtained from the cryptoProvider.
- if (cryptoProvider.getService("Signature", algorithm) == null) {
- // Calling Signature.getInstance() and catching the
- // exception would be cleaner, but exceptions are a little
- // expensive. So we check directly via getService().
- try {
- return Signature.getInstance(algorithm, "SunJSSE");
- } catch (NoSuchProviderException e) {
- throw new NoSuchAlgorithmException(e);
- }
- }
- }
- return Signature.getInstance(algorithm, cryptoProvider);
- }
- }
-
- static KeyGenerator getKeyGenerator(String algorithm)
- throws NoSuchAlgorithmException {
- if (cryptoProvider == null) {
- return KeyGenerator.getInstance(algorithm);
- } else {
- return KeyGenerator.getInstance(algorithm, cryptoProvider);
- }
- }
-
- static KeyPairGenerator getKeyPairGenerator(String algorithm)
- throws NoSuchAlgorithmException {
- if (cryptoProvider == null) {
- return KeyPairGenerator.getInstance(algorithm);
- } else {
- return KeyPairGenerator.getInstance(algorithm, cryptoProvider);
- }
- }
-
- static KeyAgreement getKeyAgreement(String algorithm)
- throws NoSuchAlgorithmException {
- if (cryptoProvider == null) {
- return KeyAgreement.getInstance(algorithm);
- } else {
- return KeyAgreement.getInstance(algorithm, cryptoProvider);
- }
- }
-
- static Mac getMac(String algorithm)
- throws NoSuchAlgorithmException {
- if (cryptoProvider == null) {
- return Mac.getInstance(algorithm);
- } else {
- return Mac.getInstance(algorithm, cryptoProvider);
- }
- }
-
- static KeyFactory getKeyFactory(String algorithm)
- throws NoSuchAlgorithmException {
- if (cryptoProvider == null) {
- return KeyFactory.getInstance(algorithm);
- } else {
- return KeyFactory.getInstance(algorithm, cryptoProvider);
- }
- }
-
- static SecureRandom getSecureRandom() throws KeyManagementException {
- if (cryptoProvider == null) {
- return new SecureRandom();
- }
- // Try "PKCS11" first. If that is not supported, iterate through
- // the provider and return the first working implementation.
- try {
- return SecureRandom.getInstance("PKCS11", cryptoProvider);
- } catch (NoSuchAlgorithmException e) {
- // ignore
- }
- for (Provider.Service s : cryptoProvider.getServices()) {
- if (s.getType().equals("SecureRandom")) {
- try {
- return SecureRandom.getInstance(s.getAlgorithm(), cryptoProvider);
- } catch (NoSuchAlgorithmException ee) {
- // ignore
- }
- }
- }
- throw new KeyManagementException("FIPS mode: no SecureRandom "
- + " implementation found in provider " + cryptoProvider.getName());
- }
-
- static MessageDigest getMD5() {
- return getMessageDigest("MD5");
- }
-
- static MessageDigest getSHA() {
- return getMessageDigest("SHA");
- }
-
- static MessageDigest getMessageDigest(String algorithm) {
- try {
- if (cryptoProvider == null) {
- return MessageDigest.getInstance(algorithm);
- } else {
- return MessageDigest.getInstance(algorithm, cryptoProvider);
- }
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException
- ("Algorithm " + algorithm + " not available", e);
- }
- }
-
- static int getRSAKeyLength(PublicKey key) {
- BigInteger modulus;
- if (key instanceof RSAPublicKey) {
- modulus = ((RSAPublicKey)key).getModulus();
- } else {
- RSAPublicKeySpec spec = getRSAPublicKeySpec(key);
- modulus = spec.getModulus();
- }
- return modulus.bitLength();
- }
-
- static RSAPublicKeySpec getRSAPublicKeySpec(PublicKey key) {
- if (key instanceof RSAPublicKey) {
- RSAPublicKey rsaKey = (RSAPublicKey)key;
- return new RSAPublicKeySpec(rsaKey.getModulus(),
- rsaKey.getPublicExponent());
- }
- try {
- KeyFactory factory = JsseJce.getKeyFactory("RSA");
- return factory.getKeySpec(key, RSAPublicKeySpec.class);
- } catch (Exception e) {
- throw (RuntimeException)new RuntimeException().initCause(e);
- }
- }
-
- static ECParameterSpec getECParameterSpec(String namedCurveOid) {
- return NamedCurve.getECParameterSpec(namedCurveOid);
- }
-
- static String getNamedCurveOid(ECParameterSpec params) {
- return ECParameters.getCurveName(params);
- }
-
- static ECPoint decodePoint(byte[] encoded, EllipticCurve curve)
- throws java.io.IOException {
- return ECParameters.decodePoint(encoded, curve);
- }
-
- static byte[] encodePoint(ECPoint point, EllipticCurve curve) {
- return ECParameters.encodePoint(point, curve);
- }
-
- // In FIPS mode, set thread local providers; otherwise a no-op.
- // Must be paired with endFipsProvider.
- static Object beginFipsProvider() {
- if (fipsProviderList == null) {
- return null;
- } else {
- return Providers.beginThreadProviderList(fipsProviderList);
- }
- }
-
- static void endFipsProvider(Object o) {
- if (fipsProviderList != null) {
- Providers.endThreadProviderList((ProviderList)o);
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/KerberosClientKeyExchange.java b/ojluni/src/main/java/sun/security/ssl/KerberosClientKeyExchange.java
deleted file mode 100755
index 339f94b..0000000
--- a/ojluni/src/main/java/sun/security/ssl/KerberosClientKeyExchange.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.security.AccessController;
-import java.security.AccessControlContext;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.security.SecureRandom;
-import javax.crypto.SecretKey;
-
-/**
- * A helper class that calls the KerberosClientKeyExchange implementation.
- */
-public class KerberosClientKeyExchange extends HandshakeMessage {
-
- private static final String IMPL_CLASS =
- "sun.security.ssl.krb5.KerberosClientKeyExchangeImpl";
-
- private static final Class<?> implClass = AccessController.doPrivileged(
- new PrivilegedAction<Class<?>>() {
- public Class<?> run() {
- try {
- return Class.forName(IMPL_CLASS, true, null);
- } catch (ClassNotFoundException cnf) {
- return null;
- }
- }
- }
- );
- private final KerberosClientKeyExchange impl = createImpl();
-
- private KerberosClientKeyExchange createImpl() {
- if (getClass() == KerberosClientKeyExchange.class) {
- try {
- return (KerberosClientKeyExchange)implClass.newInstance();
- } catch (InstantiationException e) {
- throw new AssertionError(e);
- } catch (IllegalAccessException e) {
- throw new AssertionError(e);
- }
- }
- return null;
- }
-
- public KerberosClientKeyExchange() {
- // empty
- }
-
- public KerberosClientKeyExchange(String serverName, boolean isLoopback,
- AccessControlContext acc, ProtocolVersion protocolVersion,
- SecureRandom rand) throws IOException {
-
- if (impl != null) {
- init(serverName, isLoopback, acc, protocolVersion, rand);
- } else {
- throw new IllegalStateException("Kerberos is unavailable");
- }
- }
-
- public KerberosClientKeyExchange(ProtocolVersion protocolVersion,
- ProtocolVersion clientVersion, SecureRandom rand,
- HandshakeInStream input, SecretKey[] serverKeys) throws IOException {
-
- if (impl != null) {
- init(protocolVersion, clientVersion, rand, input, serverKeys);
- } else {
- throw new IllegalStateException("Kerberos is unavailable");
- }
- }
-
- @Override
- int messageType() {
- return ht_client_key_exchange;
- }
-
- @Override
- public int messageLength() {
- return impl.messageLength();
- }
-
- @Override
- public void send(HandshakeOutStream s) throws IOException {
- impl.send(s);
- }
-
- @Override
- public void print(PrintStream p) throws IOException {
- impl.print(p);
- }
-
- public void init(String serverName, boolean isLoopback,
- AccessControlContext acc, ProtocolVersion protocolVersion,
- SecureRandom rand) throws IOException {
-
- if (impl != null) {
- impl.init(serverName, isLoopback, acc, protocolVersion, rand);
- }
- }
-
- public void init(ProtocolVersion protocolVersion,
- ProtocolVersion clientVersion, SecureRandom rand,
- HandshakeInStream input, SecretKey[] serverKeys) throws IOException {
-
- if (impl != null) {
- impl.init(protocolVersion, clientVersion, rand, input, serverKeys);
- }
- }
-
- public byte[] getUnencryptedPreMasterSecret() {
- return impl.getUnencryptedPreMasterSecret();
- }
-
- public Principal getPeerPrincipal(){
- return impl.getPeerPrincipal();
- }
-
- public Principal getLocalPrincipal(){
- return impl.getLocalPrincipal();
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/Krb5Helper.java b/ojluni/src/main/java/sun/security/ssl/Krb5Helper.java
deleted file mode 100755
index d1bbe83..0000000
--- a/ojluni/src/main/java/sun/security/ssl/Krb5Helper.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.Permission;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-
-/**
- * A helper class for Kerberos APIs.
- */
-public final class Krb5Helper {
-
- private Krb5Helper() { }
-
- // loads Krb5Proxy implementation class if available
- private static final String IMPL_CLASS =
- "sun.security.ssl.krb5.Krb5ProxyImpl";
-
- private static final Krb5Proxy proxy =
- AccessController.doPrivileged(new PrivilegedAction<Krb5Proxy>() {
- public Krb5Proxy run() {
- try {
- Class<?> c = Class.forName(IMPL_CLASS, true, null);
- return (Krb5Proxy)c.newInstance();
- } catch (ClassNotFoundException cnf) {
- return null;
- } catch (InstantiationException e) {
- throw new AssertionError(e);
- } catch (IllegalAccessException e) {
- throw new AssertionError(e);
- }
- }});
-
- /**
- * Returns true if Kerberos is available.
- */
- public static boolean isAvailable() {
- return proxy != null;
- }
-
- private static void ensureAvailable() {
- if (proxy == null)
- throw new AssertionError("Kerberos should have been available");
- }
-
- /**
- * Returns the Subject associated with client-side of the SSL socket.
- */
- public static Subject getClientSubject(AccessControlContext acc)
- throws LoginException {
- ensureAvailable();
- return proxy.getClientSubject(acc);
- }
-
- /**
- * Returns the Subject associated with server-side of the SSL socket.
- */
- public static Subject getServerSubject(AccessControlContext acc)
- throws LoginException {
- ensureAvailable();
- return proxy.getServerSubject(acc);
- }
-
- /**
- * Returns the KerberosKeys for the default server-side principal.
- */
- public static SecretKey[] getServerKeys(AccessControlContext acc)
- throws LoginException {
- ensureAvailable();
- return proxy.getServerKeys(acc);
- }
-
- /**
- * Returns the server-side principal name associated with the KerberosKey.
- */
- public static String getServerPrincipalName(SecretKey kerberosKey) {
- ensureAvailable();
- return proxy.getServerPrincipalName(kerberosKey);
- }
-
- /**
- * Returns the hostname embedded in the principal name.
- */
- public static String getPrincipalHostName(Principal principal) {
- ensureAvailable();
- return proxy.getPrincipalHostName(principal);
- }
-
- /**
- * Returns a ServicePermission for the principal name and action.
- */
- public static Permission getServicePermission(String principalName,
- String action) {
- ensureAvailable();
- return proxy.getServicePermission(principalName, action);
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/Krb5Proxy.java b/ojluni/src/main/java/sun/security/ssl/Krb5Proxy.java
deleted file mode 100755
index 14a1501..0000000
--- a/ojluni/src/main/java/sun/security/ssl/Krb5Proxy.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.AccessControlContext;
-import java.security.Permission;
-import java.security.Principal;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-
-/**
- * An interface to a subset of the Kerberos APIs to avoid a static dependency
- * on the types defined by these APIs.
- */
-public interface Krb5Proxy {
-
- /**
- * Returns the Subject associated with the client-side of the SSL socket.
- */
- Subject getClientSubject(AccessControlContext acc) throws LoginException;
-
- /**
- * Returns the Subject associated with the server-side of the SSL socket.
- */
- Subject getServerSubject(AccessControlContext acc) throws LoginException;
-
-
- /**
- * Returns the KerberosKeys for the default server-side principal.
- */
- SecretKey[] getServerKeys(AccessControlContext acc) throws LoginException;
-
- /**
- * Returns the server-side principal name associated with the KerberosKey.
- */
- String getServerPrincipalName(SecretKey kerberosKey);
-
- /**
- * Returns the hostname embedded in the principal name.
- */
- String getPrincipalHostName(Principal principal);
-
- /**
- * Returns a ServicePermission for the principal name and action.
- */
- Permission getServicePermission(String principalName, String action);
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/MAC.java b/ojluni/src/main/java/sun/security/ssl/MAC.java
deleted file mode 100755
index e491cc3..0000000
--- a/ojluni/src/main/java/sun/security/ssl/MAC.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import java.nio.ByteBuffer;
-
-import javax.crypto.Mac;
-import javax.crypto.SecretKey;
-
-import sun.security.ssl.CipherSuite.MacAlg;
-import static sun.security.ssl.CipherSuite.*;
-
-/**
- * This class computes the "Message Authentication Code" (MAC) for each
- * SSL message. This is essentially a shared-secret signature, used to
- * provide integrity protection for SSL messages. The MAC is actually
- * one of several keyed hashes, as associated with the cipher suite and
- * protocol version. (SSL v3.0 uses one construct, TLS uses another.)
- * <P>
- * NOTE: MAC computation is the only place in the SSL protocol that the
- * sequence number is used. It's also reset to zero with each change of
- * a cipher spec, so this is the only place this state is needed.
- *
- * @author David Brownell
- * @author Andreas Sterbenz
- */
-final class MAC {
-
- final static MAC NULL = new MAC();
-
- // Value of the null MAC is fixed
- private static final byte nullMAC[] = new byte[0];
-
- // internal identifier for the MAC algorithm
- private final MacAlg macAlg;
-
- // stuff defined by the kind of MAC algorithm
- private final int macSize;
-
- // JCE Mac object
- private final Mac mac;
-
- // byte array containing the additional information we MAC in each record
- // (see below)
- private final byte[] block;
-
- // sequence number + record type + + record length
- private static final int BLOCK_SIZE_SSL = 8 + 1 + 2;
-
- // sequence number + record type + protocol version + record length
- private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2;
-
- // offset of record type in block
- private static final int BLOCK_OFFSET_TYPE = 8;
-
- // offset of protocol version number in block (TLS only)
- private static final int BLOCK_OFFSET_VERSION = 8 + 1;
-
- private MAC() {
- macSize = 0;
- macAlg = M_NULL;
- mac = null;
- block = null;
- }
-
- /**
- * Set up, configured for the given SSL/TLS MAC type and version.
- */
- MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key)
- throws NoSuchAlgorithmException, InvalidKeyException {
- this.macAlg = macAlg;
- this.macSize = macAlg.size;
-
- String algorithm;
- boolean tls = (protocolVersion.v >= ProtocolVersion.TLS10.v);
-
- if (macAlg == M_MD5) {
- algorithm = tls ? "HmacMD5" : "SslMacMD5";
- } else if (macAlg == M_SHA) {
- algorithm = tls ? "HmacSHA1" : "SslMacSHA1";
- } else if (macAlg == M_SHA256) {
- algorithm = "HmacSHA256"; // TLS 1.2+
- } else if (macAlg == M_SHA384) {
- algorithm = "HmacSHA384"; // TLS 1.2+
- } else {
- throw new RuntimeException("Unknown Mac " + macAlg);
- }
-
- mac = JsseJce.getMac(algorithm);
- mac.init(key);
-
- if (tls) {
- block = new byte[BLOCK_SIZE_TLS];
- block[BLOCK_OFFSET_VERSION] = protocolVersion.major;
- block[BLOCK_OFFSET_VERSION+1] = protocolVersion.minor;
- } else {
- block = new byte[BLOCK_SIZE_SSL];
- }
- }
-
- /**
- * Returns the length of the MAC.
- */
- int MAClen() {
- return macSize;
- }
-
- /**
- * Returns the hash function block length of the MAC alorithm.
- */
- int hashBlockLen() {
- return macAlg.hashBlockSize;
- }
-
- /**
- * Returns the hash function minimal padding length of the MAC alorithm.
- */
- int minimalPaddingLen() {
- return macAlg.minimalPaddingSize;
- }
-
- /**
- * Computes and returns the MAC for the data in this byte array.
- *
- * @param type record type
- * @param buf compressed record on which the MAC is computed
- * @param offset start of compressed record data
- * @param len the size of the compressed record
- * @param isSimulated if true, simulate the the MAC computation
- */
- final byte[] compute(byte type, byte buf[],
- int offset, int len, boolean isSimulated) {
- return compute(type, null, buf, offset, len, isSimulated);
- }
-
- /**
- * Compute and returns the MAC for the remaining data
- * in this ByteBuffer.
- *
- * On return, the bb position == limit, and limit will
- * have not changed.
- *
- * @param type record type
- * @param bb a ByteBuffer in which the position and limit
- * demarcate the data to be MAC'd.
- * @param isSimulated if true, simulate the the MAC computation
- */
- final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) {
- return compute(type, bb, null, 0, bb.remaining(), isSimulated);
- }
-
- /**
- * Check whether the sequence number is close to wrap
- *
- * Sequence numbers are of type uint64 and may not exceed 2^64-1.
- * Sequence numbers do not wrap. When the sequence number is near
- * to wrap, we need to close the connection immediately.
- */
- final boolean seqNumOverflow() {
- /*
- * Conservatively, we don't allow more records to be generated
- * when there are only 2^8 sequence numbers left.
- */
- return (block != null && mac != null &&
- block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
- block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
- block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
- block[6] == (byte)0xFF);
- }
-
- /*
- * Check whether to renew the sequence number
- *
- * Sequence numbers are of type uint64 and may not exceed 2^64-1.
- * Sequence numbers do not wrap. If a TLS
- * implementation would need to wrap a sequence number, it must
- * renegotiate instead.
- */
- final boolean seqNumIsHuge() {
- /*
- * Conservatively, we should ask for renegotiation when there are
- * only 2^48 sequence numbers left.
- */
- return (block != null && mac != null &&
- block[0] == (byte)0xFF && block[1] == (byte)0xFF);
- }
-
- // increment the sequence number in the block array
- // it is a 64-bit number stored in big-endian format
- private void incrementSequenceNumber() {
- int k = 7;
- while ((k >= 0) && (++block[k] == 0)) {
- k--;
- }
- }
-
- /*
- * Compute based on either buffer type, either bb.position/limit
- * or buf/offset/len.
- */
- private byte[] compute(byte type, ByteBuffer bb, byte[] buf,
- int offset, int len, boolean isSimulated) {
-
- if (macSize == 0) {
- return nullMAC;
- }
-
- // MUST NOT increase the sequence number for a simulated computation.
- if (!isSimulated) {
- block[BLOCK_OFFSET_TYPE] = type;
- block[block.length - 2] = (byte)(len >> 8);
- block[block.length - 1] = (byte)(len );
-
- mac.update(block);
- incrementSequenceNumber();
- }
-
- // content
- if (bb != null) {
- mac.update(bb);
- } else {
- mac.update(buf, offset, len);
- }
-
- return mac.doFinal();
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/OutputRecord.java b/ojluni/src/main/java/sun/security/ssl/OutputRecord.java
deleted file mode 100755
index 012816d..0000000
--- a/ojluni/src/main/java/sun/security/ssl/OutputRecord.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-import java.util.Arrays;
-
-import javax.net.ssl.SSLException;
-import sun.misc.HexDumpEncoder;
-
-
-/**
- * SSL 3.0 records, as written to a TCP stream.
- *
- * Each record has a message area that starts out with data supplied by the
- * application. It may grow/shrink due to compression and will be modified
- * in place for mac-ing and encryption.
- *
- * Handshake records have additional needs, notably accumulation of a set
- * of hashes which are used to establish that handshaking was done right.
- * Handshake records usually have several handshake messages each, and we
- * need message-level control over what's hashed.
- *
- * @author David Brownell
- */
-class OutputRecord extends ByteArrayOutputStream implements Record {
-
- private HandshakeHash handshakeHash;
- private int lastHashed;
- private boolean firstMessage;
- final private byte contentType;
-
- // current protocol version, sent as record version
- ProtocolVersion protocolVersion;
-
- // version for the ClientHello message. Only relevant if this is a
- // client handshake record. If set to ProtocolVersion.SSL20Hello,
- // the V3 client hello is converted to V2 format.
- private ProtocolVersion helloVersion;
-
- /* Class and subclass dynamic debugging support */
- static final Debug debug = Debug.getInstance("ssl");
-
- /*
- * Default constructor makes a record supporting the maximum
- * SSL record size. It allocates the header bytes directly.
- *
- * @param type the content type for the record
- */
- OutputRecord(byte type, int size) {
- super(size);
- this.protocolVersion = ProtocolVersion.DEFAULT;
- this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
- firstMessage = true;
- count = headerSize;
- contentType = type;
- lastHashed = count;
- }
-
- OutputRecord(byte type) {
- this(type, recordSize(type));
- }
-
- /**
- * Get the size of the buffer we need for records of the specified
- * type.
- */
- private static int recordSize(byte type) {
- if ((type == ct_change_cipher_spec) || (type == ct_alert)) {
- return maxAlertRecordSize;
- } else {
- return maxRecordSize;
- }
- }
-
- /*
- * Updates the SSL version of this record.
- */
- synchronized void setVersion(ProtocolVersion protocolVersion) {
- this.protocolVersion = protocolVersion;
- }
-
- /*
- * Updates helloVersion of this record.
- */
- synchronized void setHelloVersion(ProtocolVersion helloVersion) {
- this.helloVersion = helloVersion;
- }
-
- /*
- * Reset the record so that it can be refilled, starting
- * immediately after the header.
- */
- public synchronized void reset() {
- super.reset();
- count = headerSize;
- lastHashed = count;
- }
-
- /*
- * For handshaking, we need to be able to hash every byte above the
- * record marking layer. This is where we're guaranteed to see those
- * bytes, so this is where we can hash them.
- */
- void setHandshakeHash(HandshakeHash handshakeHash) {
- assert(contentType == ct_handshake);
- this.handshakeHash = handshakeHash;
- }
-
- /*
- * We hash (the plaintext) on demand. There is one place where
- * we want to access the hash in the middle of a record: client
- * cert message gets hashed, and part of the same record is the
- * client cert verify message which uses that hash. So we track
- * how much of each record we've hashed so far.
- */
- void doHashes() {
- int len = count - lastHashed;
-
- if (len > 0) {
- hashInternal(buf, lastHashed, len);
- lastHashed = count;
- }
- }
-
- /*
- * Need a helper function so we can hash the V2 hello correctly
- */
- private void hashInternal(byte buf [], int offset, int len) {
- if (debug != null && Debug.isOn("data")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
-
- System.out.println("[write] MD5 and SHA1 hashes: len = "
- + len);
- hd.encodeBuffer(new ByteArrayInputStream(buf,
- lastHashed, len), System.out);
- } catch (IOException e) { }
- }
-
- handshakeHash.update(buf, lastHashed, len);
- lastHashed = count;
- }
-
- /*
- * Return true iff the record is empty -- to avoid doing the work
- * of sending empty records over the network.
- */
- boolean isEmpty() {
- return count == headerSize;
- }
-
- /*
- * Return true if the record is of a given alert.
- */
- boolean isAlert(byte description) {
- // An alert is defined with a two bytes struct,
- // {byte level, byte description}, following after the header bytes.
- if (count > (headerSize + 1) && contentType == ct_alert) {
- return buf[headerSize + 1] == description;
- }
-
- return false;
- }
-
- /*
- * Compute the MAC and append it to this record. In case we
- * are automatically flushing a handshake stream, make sure we
- * have hashed the message first.
- */
- void addMAC(MAC signer) throws IOException {
- //
- // when we support compression, hashing can't go here
- // since it'll need to be done on the uncompressed data,
- // and the MAC applies to the compressed data.
- //
- if (contentType == ct_handshake) {
- doHashes();
- }
- if (signer.MAClen() != 0) {
- byte[] hash = signer.compute(contentType, buf,
- headerSize, count - headerSize, false);
- write(hash);
- }
- }
-
- /*
- * Encrypt ... length may grow due to block cipher padding
- */
- void encrypt(CipherBox box) {
- int len = count - headerSize;
- count = headerSize + box.encrypt(buf, headerSize, len);
- }
-
-
- /*
- * Tell how full the buffer is ... for filling it with application or
- * handshake data.
- */
- final int availableDataBytes() {
- int dataSize = count - headerSize;
- return maxDataSize - dataSize;
- }
-
- /*
- * Increases the capacity if necessary to ensure that it can hold
- * at least the number of elements specified by the minimum
- * capacity argument.
- *
- * Note that the increased capacity is only can be used for held
- * record buffer. Please DO NOT update the availableDataBytes()
- * according to the expended buffer capacity.
- *
- * @see availableDataBytes()
- */
- private void ensureCapacity(int minCapacity) {
- // overflow-conscious code
- if (minCapacity > buf.length) {
- buf = Arrays.copyOf(buf, minCapacity);
- }
- }
-
- /*
- * Return the type of SSL record that's buffered here.
- */
- final byte contentType() {
- return contentType;
- }
-
- /*
- * Write the record out on the stream. Note that you must have (in
- * order) compressed the data, appended the MAC, and encrypted it in
- * order for the record to be understood by the other end. (Some of
- * those steps will be null early in handshaking.)
- *
- * Note that this does no locking for the connection, it's required
- * that synchronization be done elsewhere. Also, this does its work
- * in a single low level write, for efficiency.
- */
- void write(OutputStream s, boolean holdRecord,
- ByteArrayOutputStream heldRecordBuffer) throws IOException {
- /*
- * Don't emit content-free records. (Even change cipher spec
- * messages have a byte of data!)
- */
- if (count == headerSize) {
- return;
- }
-
- int length = count - headerSize;
- // "should" really never write more than about 14 Kb...
- if (length < 0) {
- throw new SSLException("output record size too small: "
- + length);
- }
-
- if (debug != null
- && (Debug.isOn("record") || Debug.isOn("handshake"))) {
- if ((debug != null && Debug.isOn("record"))
- || contentType() == ct_change_cipher_spec)
- System.out.println(Thread.currentThread().getName()
- // v3.0/v3.1 ...
- + ", WRITE: " + protocolVersion
- + " " + InputRecord.contentName(contentType())
- + ", length = " + length);
- }
-
- /*
- * If this is the initial ClientHello on this connection and
- * we're not trying to resume a (V3) session then send a V2
- * ClientHello instead so we can detect V2 servers cleanly.
- */
- if (firstMessage && useV2Hello()) {
- byte[] v3Msg = new byte[length - 4];
- System.arraycopy(buf, headerSize + 4, v3Msg, 0, v3Msg.length);
- V3toV2ClientHello(v3Msg);
- handshakeHash.reset();
- lastHashed = 2;
- doHashes();
- if (debug != null && Debug.isOn("record")) {
- System.out.println(
- Thread.currentThread().getName()
- + ", WRITE: SSLv2 client hello message"
- + ", length = " + (count - 2)); // 2 byte SSLv2 header
- }
- } else {
- /*
- * Fill out the header, write it and the message.
- */
- buf[0] = contentType;
- buf[1] = protocolVersion.major;
- buf[2] = protocolVersion.minor;
- buf[3] = (byte)(length >> 8);
- buf[4] = (byte)(length);
- }
- firstMessage = false;
-
- /*
- * The upper levels may want us to delay sending this packet so
- * multiple TLS Records can be sent in one (or more) TCP packets.
- * If so, add this packet to the heldRecordBuffer.
- *
- * NOTE: all writes have been synchronized by upper levels.
- */
- int debugOffset = 0;
- if (holdRecord) {
- /*
- * If holdRecord is true, we must have a heldRecordBuffer.
- *
- * Don't worry about the override of writeBuffer(), because
- * when holdRecord is true, the implementation in this class
- * will be used.
- */
- writeBuffer(heldRecordBuffer, buf, 0, count, debugOffset);
- } else {
- // It's time to send, do we have buffered data?
- // May or may not have a heldRecordBuffer.
- if (heldRecordBuffer != null && heldRecordBuffer.size() > 0) {
- int heldLen = heldRecordBuffer.size();
-
- // Ensure the capacity of this buffer.
- ensureCapacity(count + heldLen);
-
- // Slide everything in the buffer to the right.
- System.arraycopy(buf, 0, buf, heldLen, count);
-
- // Prepend the held record to the buffer.
- System.arraycopy(
- heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen);
- count += heldLen;
-
- // Clear the held buffer.
- heldRecordBuffer.reset();
-
- // The held buffer has been dumped, set the debug dump offset.
- debugOffset = heldLen;
- }
- writeBuffer(s, buf, 0, count, debugOffset);
- }
-
- reset();
- }
-
- /*
- * Actually do the write here. For SSLEngine's HS data,
- * we'll override this method and let it take the appropriate
- * action.
- */
- void writeBuffer(OutputStream s, byte [] buf, int off, int len,
- int debugOffset) throws IOException {
-
- s.write(buf, off, len);
- s.flush();
-
- // Output only the record from the specified debug offset.
- if (debug != null && Debug.isOn("packet")) {
- try {
- HexDumpEncoder hd = new HexDumpEncoder();
- ByteBuffer bb = ByteBuffer.wrap(
- buf, off + debugOffset, len - debugOffset);
-
- System.out.println("[Raw write]: length = " +
- bb.remaining());
- hd.encodeBuffer(bb, System.out);
- } catch (IOException e) { }
- }
- }
-
- /*
- * Return whether the buffer contains a ClientHello message that should
- * be converted to V2 format.
- */
- private boolean useV2Hello() {
- return firstMessage
- && (helloVersion == ProtocolVersion.SSL20Hello)
- && (contentType == ct_handshake)
- && (buf[5] == HandshakeMessage.ht_client_hello)
- && (buf[headerSize + 4+2+32] == 0); // V3 session ID is empty
- }
-
- /*
- * Detect "old" servers which are capable of SSL V2.0 protocol ... for
- * example, Netscape Commerce 1.0 servers. The V3 message is in the
- * header and the bytes passed as parameter. This routine translates
- * the V3 message into an equivalent V2 one.
- *
- * Note that the translation will strip off all hello extensions as
- * SSL V2.0 does not support hello extension.
- */
- private void V3toV2ClientHello(byte v3Msg []) throws SSLException {
- int v3SessionIdLenOffset = 2 + 32; // version + nonce
- int v3SessionIdLen = v3Msg[v3SessionIdLenOffset];
- int v3CipherSpecLenOffset = v3SessionIdLenOffset + 1 + v3SessionIdLen;
- int v3CipherSpecLen = ((v3Msg[v3CipherSpecLenOffset] & 0xff) << 8) +
- (v3Msg[v3CipherSpecLenOffset + 1] & 0xff);
- int cipherSpecs = v3CipherSpecLen / 2; // 2 bytes each in V3
-
- /*
- * Copy over the cipher specs. We don't care about actually translating
- * them for use with an actual V2 server since we only talk V3.
- * Therefore, just copy over the V3 cipher spec values with a leading
- * 0.
- */
- int v3CipherSpecOffset = v3CipherSpecLenOffset + 2; // skip length
- int v2CipherSpecLen = 0;
- count = 11;
- boolean containsRenegoInfoSCSV = false;
- for (int i = 0; i < cipherSpecs; i++) {
- byte byte1, byte2;
-
- byte1 = v3Msg[v3CipherSpecOffset++];
- byte2 = v3Msg[v3CipherSpecOffset++];
- v2CipherSpecLen += V3toV2CipherSuite(byte1, byte2);
- if (!containsRenegoInfoSCSV &&
- byte1 == (byte)0x00 && byte2 == (byte)0xFF) {
- containsRenegoInfoSCSV = true;
- }
- }
-
- if (!containsRenegoInfoSCSV) {
- v2CipherSpecLen += V3toV2CipherSuite((byte)0x00, (byte)0xFF);
- }
-
- /*
- * Build the first part of the V3 record header from the V2 one
- * that's now buffered up. (Lengths are fixed up later).
- */
- buf[2] = HandshakeMessage.ht_client_hello;
- buf[3] = v3Msg[0]; // major version
- buf[4] = v3Msg[1]; // minor version
- buf[5] = (byte)(v2CipherSpecLen >>> 8);
- buf[6] = (byte)v2CipherSpecLen;
- buf[7] = 0;
- buf[8] = 0; // always no session
- buf[9] = 0;
- buf[10] = 32; // nonce length (always 32 in V3)
-
- /*
- * Copy in the nonce.
- */
- System.arraycopy(v3Msg, 2, buf, count, 32);
- count += 32;
-
- /*
- * Set the length of the message.
- */
- count -= 2; // don't include length field itself
- buf[0] = (byte)(count >>> 8);
- buf[0] |= 0x80;
- buf[1] = (byte)(count);
- count += 2;
- }
-
- /*
- * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
- * This is taken from the SSL V3 specification, Appendix E.
- */
- private static int[] V3toV2CipherMap1 =
- {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
- private static int[] V3toV2CipherMap3 =
- {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
-
- /*
- * See which matching pure-V2 cipher specs we need to include.
- * We are including these not because we are actually prepared
- * to talk V2 but because the Oracle Web Server insists on receiving
- * at least 1 "pure V2" cipher suite that it supports and returns an
- * illegal_parameter alert unless one is present. Rather than mindlessly
- * claiming to implement all documented pure V2 cipher suites the code below
- * just claims to implement the V2 cipher suite that is "equivalent"
- * in terms of cipher algorithm & exportability with the actual V3 cipher
- * suite that we do support.
- */
- private int V3toV2CipherSuite(byte byte1, byte byte2) {
- buf[count++] = 0;
- buf[count++] = byte1;
- buf[count++] = byte2;
-
- if (((byte2 & 0xff) > 0xA) ||
- (V3toV2CipherMap1[byte2] == -1)) {
- return 3;
- }
-
- buf[count++] = (byte)V3toV2CipherMap1[byte2];
- buf[count++] = 0;
- buf[count++] = (byte)V3toV2CipherMap3[byte2];
-
- return 6;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/ProtocolList.java b/ojluni/src/main/java/sun/security/ssl/ProtocolList.java
deleted file mode 100755
index a57a9bd..0000000
--- a/ojluni/src/main/java/sun/security/ssl/ProtocolList.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.util.*;
-
-/**
- * A list of ProtocolVersions. Also maintains the list of supported protocols.
- * Instances of this class are immutable. Some member variables are final
- * and can be accessed directly without method accessors.
- *
- * @author Andreas Sterbenz
- * @since 1.4.1
- */
-final class ProtocolList {
-
- // the sorted protocol version list
- private final ArrayList<ProtocolVersion> protocols;
-
- private String[] protocolNames;
-
- // the minimum and maximum ProtocolVersions in this list
- final ProtocolVersion min, max;
-
- // the format for the hello version to use
- final ProtocolVersion helloVersion;
-
- ProtocolList(String[] names) {
- this(convert(names));
- }
-
- ProtocolList(ArrayList<ProtocolVersion> versions) {
- this.protocols = versions;
-
- if ((protocols.size() == 1) &&
- protocols.contains(ProtocolVersion.SSL20Hello)) {
- throw new IllegalArgumentException("SSLv2Hello cannot be " +
- "enabled unless at least one other supported version " +
- "is also enabled.");
- }
-
- if (protocols.size() != 0) {
- Collections.sort(protocols);
- min = protocols.get(0);
- max = protocols.get(protocols.size() - 1);
- helloVersion = protocols.get(0);
- } else {
- min = ProtocolVersion.NONE;
- max = ProtocolVersion.NONE;
- helloVersion = ProtocolVersion.NONE;
- }
- }
-
- private static ArrayList<ProtocolVersion> convert(String[] names) {
- if (names == null) {
- throw new IllegalArgumentException("Protocols may not be null");
- }
-
- ArrayList<ProtocolVersion> versions = new ArrayList<>(3);
- for (int i = 0; i < names.length; i++ ) {
- ProtocolVersion version = ProtocolVersion.valueOf(names[i]);
- if (versions.contains(version) == false) {
- versions.add(version);
- }
- }
-
- return versions;
- }
-
- /**
- * Return whether this list contains the specified protocol version.
- * SSLv2Hello is not a real protocol version we support, we always
- * return false for it.
- */
- boolean contains(ProtocolVersion protocolVersion) {
- if (protocolVersion == ProtocolVersion.SSL20Hello) {
- return false;
- }
- return protocols.contains(protocolVersion);
- }
-
- /**
- * Return a reference to the internal Collection of CipherSuites.
- * The Collection MUST NOT be modified.
- */
- Collection<ProtocolVersion> collection() {
- return protocols;
- }
-
- /**
- * Select a protocol version from the list.
- *
- * Return the lower of the protocol version of that suggested by
- * the <code>protocolVersion</code> and the highest version of this
- * protocol list, or null if no protocol version is available.
- *
- * The method is used by TLS server to negotiated the protocol
- * version between client suggested protocol version in the
- * client hello and protocol versions supported by the server.
- */
- ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
- ProtocolVersion selectedVersion = null;
- for (ProtocolVersion pv : protocols) {
- if (pv.v > protocolVersion.v) {
- break; // Safe to break here as this.protocols is sorted
- }
- selectedVersion = pv;
- }
-
- return selectedVersion;
- }
-
- /**
- * Return an array with the names of the ProtocolVersions in this list.
- */
- synchronized String[] toStringArray() {
- if (protocolNames == null) {
- protocolNames = new String[protocols.size()];
- int i = 0;
- for (ProtocolVersion version : protocols) {
- protocolNames[i++] = version.name;
- }
- }
- return protocolNames.clone();
- }
-
- public String toString() {
- return protocols.toString();
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/ProtocolVersion.java b/ojluni/src/main/java/sun/security/ssl/ProtocolVersion.java
deleted file mode 100755
index 77c102a..0000000
--- a/ojluni/src/main/java/sun/security/ssl/ProtocolVersion.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-/**
- * Type safe enum for an SSL/TLS protocol version. Instances are obtained
- * using the static factory methods or by referencing the static members
- * in this class. Member variables are final and can be accessed without
- * accessor methods.
- *
- * There is only ever one instance per supported protocol version, this
- * means == can be used for comparision instead of equals() if desired.
- *
- * Checks for a particular version number should generally take this form:
- *
- * if (protocolVersion.v >= ProtocolVersion.TLS10) {
- * // TLS 1.0 code goes here
- * } else {
- * // SSL 3.0 code here
- * }
- *
- * @author Andreas Sterbenz
- * @since 1.4.1
- */
-public final class ProtocolVersion implements Comparable<ProtocolVersion> {
-
- // The limit of maximum protocol version
- final static int LIMIT_MAX_VALUE = 0xFFFF;
-
- // The limit of minimum protocol version
- final static int LIMIT_MIN_VALUE = 0x0000;
-
- // Dummy protocol version value for invalid SSLSession
- final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
-
- // If enabled, send/ accept SSLv2 hello messages
- final static ProtocolVersion SSL20Hello = new ProtocolVersion(0x0002,
- "SSLv2Hello");
-
- // SSL 3.0
- final static ProtocolVersion SSL30 = new ProtocolVersion(0x0300, "SSLv3");
-
- // TLS 1.0
- final static ProtocolVersion TLS10 = new ProtocolVersion(0x0301, "TLSv1");
-
- // TLS 1.1
- final static ProtocolVersion TLS11 = new ProtocolVersion(0x0302, "TLSv1.1");
-
- // TLS 1.2
- final static ProtocolVersion TLS12 = new ProtocolVersion(0x0303, "TLSv1.2");
-
- private static final boolean FIPS = SunJSSE.isFIPS();
-
- // minimum version we implement (SSL 3.0)
- final static ProtocolVersion MIN = FIPS ? TLS10 : SSL30;
-
- // maximum version we implement (TLS 1.2)
- final static ProtocolVersion MAX = TLS12;
-
- // ProtocolVersion to use by default (TLS 1.0)
- final static ProtocolVersion DEFAULT = TLS10;
-
- // Default version for hello messages (SSLv2Hello)
- final static ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL30;
-
- // version in 16 bit MSB format as it appears in records and
- // messages, i.e. 0x0301 for TLS 1.0
- public final int v;
-
- // major and minor version
- public final byte major, minor;
-
- // name used in JSSE (e.g. TLSv1 for TLS 1.0)
- final String name;
-
- // private
- private ProtocolVersion(int v, String name) {
- this.v = v;
- this.name = name;
- major = (byte)(v >>> 8);
- minor = (byte)(v & 0xff);
- }
-
- // private
- private static ProtocolVersion valueOf(int v) {
- if (v == SSL30.v) {
- return SSL30;
- } else if (v == TLS10.v) {
- return TLS10;
- } else if (v == TLS11.v) {
- return TLS11;
- } else if (v == TLS12.v) {
- return TLS12;
- } else if (v == SSL20Hello.v) {
- return SSL20Hello;
- } else {
- int major = (v >>> 8) & 0xff;
- int minor = v & 0xff;
- return new ProtocolVersion(v, "Unknown-" + major + "." + minor);
- }
- }
-
- /**
- * Return a ProtocolVersion with the specified major and minor version
- * numbers. Never throws exceptions.
- */
- public static ProtocolVersion valueOf(int major, int minor) {
- major &= 0xff;
- minor &= 0xff;
- int v = (major << 8) | minor;
- return valueOf(v);
- }
-
- /**
- * Return a ProtocolVersion for the given name.
- *
- * @exception IllegalArgumentException if name is null or does not
- * identify a supported protocol
- */
- static ProtocolVersion valueOf(String name) {
- if (name == null) {
- throw new IllegalArgumentException("Protocol cannot be null");
- }
-
- if (FIPS && (name.equals(SSL30.name) || name.equals(SSL20Hello.name))) {
- throw new IllegalArgumentException
- ("Only TLS 1.0 or later allowed in FIPS mode");
- }
-
- if (name.equals(SSL30.name)) {
- return SSL30;
- } else if (name.equals(TLS10.name)) {
- return TLS10;
- } else if (name.equals(TLS11.name)) {
- return TLS11;
- } else if (name.equals(TLS12.name)) {
- return TLS12;
- } else if (name.equals(SSL20Hello.name)) {
- return SSL20Hello;
- } else {
- throw new IllegalArgumentException(name);
- }
- }
-
- public String toString() {
- return name;
- }
-
- /**
- * Compares this object with the specified object for order.
- */
- public int compareTo(ProtocolVersion protocolVersion) {
- return this.v - protocolVersion.v;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/RSAClientKeyExchange.java b/ojluni/src/main/java/sun/security/ssl/RSAClientKeyExchange.java
deleted file mode 100755
index f8e501e..0000000
--- a/ojluni/src/main/java/sun/security/ssl/RSAClientKeyExchange.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.security.*;
-import java.security.interfaces.*;
-
-import javax.crypto.*;
-import javax.crypto.spec.*;
-
-import javax.net.ssl.*;
-
-import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
-import sun.security.util.KeyUtil;
-
-/**
- * This is the client key exchange message (CLIENT --> SERVER) used with
- * all RSA key exchanges; it holds the RSA-encrypted pre-master secret.
- *
- * The message is encrypted using PKCS #1 block type 02 encryption with the
- * server's public key. The padding and resulting message size is a function
- * of this server's public key modulus size, but the pre-master secret is
- * always exactly 48 bytes.
- *
- */
-final class RSAClientKeyExchange extends HandshakeMessage {
-
- /**
- * The TLS spec says that the version in the RSA premaster secret must
- * be the maximum version supported by the client (i.e. the version it
- * requested in its client hello version). However, we (and other
- * implementations) used to send the active negotiated version. The
- * system property below allows to toggle the behavior.
- */
- private final static String PROP_NAME =
- "com.sun.net.ssl.rsaPreMasterSecretFix";
-
- /*
- * Default is "false" (old behavior) for compatibility reasons in
- * SSLv3/TLSv1. Later protocols (TLSv1.1+) do not use this property.
- */
- private final static boolean rsaPreMasterSecretFix =
- Debug.getBooleanProperty(PROP_NAME, false);
-
- /*
- * The following field values were encrypted with the server's public
- * key (or temp key from server key exchange msg) and are presented
- * here in DECRYPTED form.
- */
- private ProtocolVersion protocolVersion; // preMaster [0,1]
- SecretKey preMaster;
- private byte[] encrypted; // same size as public modulus
-
- /*
- * Client randomly creates a pre-master secret and encrypts it
- * using the server's RSA public key; only the server can decrypt
- * it, using its RSA private key. Result is the same size as the
- * server's public key, and uses PKCS #1 block format 02.
- */
- RSAClientKeyExchange(ProtocolVersion protocolVersion,
- ProtocolVersion maxVersion,
- SecureRandom generator, PublicKey publicKey) throws IOException {
- if (publicKey.getAlgorithm().equals("RSA") == false) {
- throw new SSLKeyException("Public key not of type RSA");
- }
- this.protocolVersion = protocolVersion;
-
- int major, minor;
-
- if (rsaPreMasterSecretFix || maxVersion.v >= ProtocolVersion.TLS11.v) {
- major = maxVersion.major;
- minor = maxVersion.minor;
- } else {
- major = protocolVersion.major;
- minor = protocolVersion.minor;
- }
-
- try {
- String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ?
- "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
- KeyGenerator kg = JsseJce.getKeyGenerator(s);
- kg.init(new TlsRsaPremasterSecretParameterSpec(major, minor),
- generator);
- preMaster = kg.generateKey();
-
- Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
- cipher.init(Cipher.WRAP_MODE, publicKey, generator);
- encrypted = cipher.wrap(preMaster);
- } catch (GeneralSecurityException e) {
- throw (SSLKeyException)new SSLKeyException
- ("RSA premaster secret error").initCause(e);
- }
- }
-
- /*
- * Server gets the PKCS #1 (block format 02) data, decrypts
- * it with its private key.
- */
- RSAClientKeyExchange(ProtocolVersion currentVersion,
- ProtocolVersion maxVersion,
- SecureRandom generator, HandshakeInStream input,
- int messageSize, PrivateKey privateKey) throws IOException {
-
- if (privateKey.getAlgorithm().equals("RSA") == false) {
- throw new SSLKeyException("Private key not of type RSA");
- }
-
- if (currentVersion.v >= ProtocolVersion.TLS10.v) {
- encrypted = input.getBytes16();
- } else {
- encrypted = new byte [messageSize];
- if (input.read(encrypted) != messageSize) {
- throw new SSLProtocolException
- ("SSL: read PreMasterSecret: short read");
- }
- }
-
- try {
- Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1);
- cipher.init(Cipher.UNWRAP_MODE, privateKey);
- preMaster = (SecretKey)cipher.unwrap(encrypted,
- "TlsRsaPremasterSecret", Cipher.SECRET_KEY);
-
- // polish the premaster secret
- preMaster = polishPreMasterSecretKey(currentVersion, maxVersion,
- generator, preMaster, null);
- } catch (Exception e) {
- // polish the premaster secret
- preMaster =
- polishPreMasterSecretKey(currentVersion, maxVersion,
- generator, null, e);
- }
- }
-
- /**
- * To avoid vulnerabilities described by section 7.4.7.1, RFC 5246,
- * treating incorrectly formatted message blocks and/or mismatched
- * version numbers in a manner indistinguishable from correctly
- * formatted RSA blocks.
- *
- * RFC 5246 describes the approach as :
- *
- * 1. Generate a string R of 46 random bytes
- *
- * 2. Decrypt the message to recover the plaintext M
- *
- * 3. If the PKCS#1 padding is not correct, or the length of message
- * M is not exactly 48 bytes:
- * pre_master_secret = ClientHello.client_version || R
- * else If ClientHello.client_version <= TLS 1.0, and version
- * number check is explicitly disabled:
- * pre_master_secret = M
- * else:
- * pre_master_secret = ClientHello.client_version || M[2..47]
- */
- private SecretKey polishPreMasterSecretKey(ProtocolVersion currentVersion,
- ProtocolVersion clientHelloVersion, SecureRandom generator,
- SecretKey secretKey, Exception failoverException) {
-
- this.protocolVersion = clientHelloVersion;
-
- if (failoverException == null && secretKey != null) {
- // check the length
- byte[] encoded = secretKey.getEncoded();
- if (encoded == null) { // unable to get the encoded key
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "unable to get the plaintext of the premaster secret");
- }
-
- int keySize = KeyUtil.getKeySize(secretKey);
- if (keySize > 0 && keySize != 384) { // 384 = 48 * 8
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "incorrect length of premaster secret: " +
- (keySize/8));
- }
-
- return generateDummySecret(clientHelloVersion);
- }
-
- // The key size is exactly 48 bytes or not accessible.
- //
- // Conservatively, pass the checking to master secret
- // calculation.
- return secretKey;
- } else if (encoded.length == 48) {
- // check the version
- if (clientHelloVersion.major == encoded[0] &&
- clientHelloVersion.minor == encoded[1]) {
-
- return secretKey;
- } else if (clientHelloVersion.v <= ProtocolVersion.TLS10.v &&
- currentVersion.major == encoded[0] &&
- currentVersion.minor == encoded[1]) {
- /*
- * For compatibility, we maintain the behavior that the
- * version in pre_master_secret can be the negotiated
- * version for TLS v1.0 and SSL v3.0.
- */
- this.protocolVersion = currentVersion;
- return secretKey;
- }
-
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("Mismatching Protocol Versions, " +
- "ClientHello.client_version is " + clientHelloVersion +
- ", while PreMasterSecret.client_version is " +
- ProtocolVersion.valueOf(encoded[0], encoded[1]));
- }
-
- return generateDummySecret(clientHelloVersion);
- } else {
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "incorrect length of premaster secret: " +
- encoded.length);
- }
-
- return generateDummySecret(clientHelloVersion);
- }
- }
-
- if (debug != null && Debug.isOn("handshake") &&
- failoverException != null) {
- System.out.println("Error decrypting premaster secret:");
- failoverException.printStackTrace(System.out);
- }
-
- return generateDummySecret(clientHelloVersion);
- }
-
- // generate a premaster secret with the specified version number
- static SecretKey generateDummySecret(ProtocolVersion version) {
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("Generating a random fake premaster secret");
- }
-
- try {
- String s = ((version.v >= ProtocolVersion.TLS12.v) ?
- "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
- KeyGenerator kg = JsseJce.getKeyGenerator(s);
- kg.init(new TlsRsaPremasterSecretParameterSpec
- (version.major, version.minor));
- return kg.generateKey();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate dummy secret", e);
- }
- }
-
- @Override
- int messageType() {
- return ht_client_key_exchange;
- }
-
- @Override
- int messageLength() {
- if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
- return encrypted.length + 2;
- } else {
- return encrypted.length;
- }
- }
-
- @Override
- void send(HandshakeOutStream s) throws IOException {
- if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
- s.putBytes16(encrypted);
- } else {
- s.write(encrypted);
- }
- }
-
- @Override
- void print(PrintStream s) throws IOException {
- s.println("*** ClientKeyExchange, RSA PreMasterSecret, " +
- protocolVersion);
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/RSASignature.java b/ojluni/src/main/java/sun/security/ssl/RSASignature.java
deleted file mode 100755
index 5b97bed..0000000
--- a/ojluni/src/main/java/sun/security/ssl/RSASignature.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.util.Arrays;
-
-import java.security.*;
-
-/**
- * Signature implementation for the SSL/TLS RSA Signature variant with both
- * MD5 and SHA-1 MessageDigests. Used for explicit RSA server authentication
- * (RSA signed server key exchange for RSA_EXPORT and DHE_RSA) and RSA client
- * authentication (RSA signed certificate verify message).
- *
- * It conforms to the standard JCA Signature API. It is registered in the
- * SunJSSE provider to avoid more complicated getInstance() code and
- * negative interaction with the JCA mechanisms for hardware providers.
- *
- * The class should be instantiated via the getInstance() method in this class,
- * which returns the implementation from the prefered provider. The internal
- * implementation allows the hashes to be explicitly set, which is required
- * for RSA client authentication. It can be obtained via the
- * getInternalInstance() method.
- *
- * This class is not thread safe.
- *
- */
-public final class RSASignature extends SignatureSpi {
-
- private final Signature rawRsa;
- private MessageDigest md5, sha;
-
- // flag indicating if the MessageDigests are in reset state
- private boolean isReset;
-
- public RSASignature() throws NoSuchAlgorithmException {
- super();
- rawRsa = JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA);
- isReset = true;
- }
-
- /**
- * Get an implementation for the RSA signature. Follows the standard
- * JCA getInstance() model, so it return the implementation from the
- * provider with the highest precedence, which may be this class.
- */
- static Signature getInstance() throws NoSuchAlgorithmException {
- return JsseJce.getSignature(JsseJce.SIGNATURE_SSLRSA);
- }
-
- /**
- * Get an internal implementation for the RSA signature. Used for RSA
- * client authentication, which needs the ability to set the digests
- * to externally provided values via the setHashes() method.
- */
- static Signature getInternalInstance()
- throws NoSuchAlgorithmException, NoSuchProviderException {
- return Signature.getInstance(JsseJce.SIGNATURE_SSLRSA, "SunJSSE");
- }
-
- /**
- * Set the MD5 and SHA hashes to the provided objects.
- */
- static void setHashes(Signature sig, MessageDigest md5, MessageDigest sha) {
- sig.setParameter("hashes", new MessageDigest[] {md5, sha});
- }
-
- /**
- * Reset the MessageDigests unless they are already reset.
- */
- private void reset() {
- if (isReset == false) {
- md5.reset();
- sha.reset();
- isReset = true;
- }
- }
-
- private static void checkNull(Key key) throws InvalidKeyException {
- if (key == null) {
- throw new InvalidKeyException("Key must not be null");
- }
- }
-
- protected void engineInitVerify(PublicKey publicKey)
- throws InvalidKeyException {
- checkNull(publicKey);
- reset();
- rawRsa.initVerify(publicKey);
- }
-
- protected void engineInitSign(PrivateKey privateKey)
- throws InvalidKeyException {
- engineInitSign(privateKey, null);
- }
-
- protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
- throws InvalidKeyException {
- checkNull(privateKey);
- reset();
- rawRsa.initSign(privateKey, random);
- }
-
- // lazily initialize the MessageDigests
- private void initDigests() {
- if (md5 == null) {
- md5 = JsseJce.getMD5();
- sha = JsseJce.getSHA();
- }
- }
-
- protected void engineUpdate(byte b) {
- initDigests();
- isReset = false;
- md5.update(b);
- sha.update(b);
- }
-
- protected void engineUpdate(byte[] b, int off, int len) {
- initDigests();
- isReset = false;
- md5.update(b, off, len);
- sha.update(b, off, len);
- }
-
- private byte[] getDigest() throws SignatureException {
- try {
- initDigests();
- byte[] data = new byte[36];
- md5.digest(data, 0, 16);
- sha.digest(data, 16, 20);
- isReset = true;
- return data;
- } catch (DigestException e) {
- // should never occur
- throw new SignatureException(e);
- }
- }
-
- protected byte[] engineSign() throws SignatureException {
- rawRsa.update(getDigest());
- return rawRsa.sign();
- }
-
- protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
- return engineVerify(sigBytes, 0, sigBytes.length);
- }
-
- protected boolean engineVerify(byte[] sigBytes, int offset, int length)
- throws SignatureException {
- rawRsa.update(getDigest());
- return rawRsa.verify(sigBytes, offset, length);
- }
-
- protected void engineSetParameter(String param, Object value)
- throws InvalidParameterException {
- if (param.equals("hashes") == false) {
- throw new InvalidParameterException
- ("Parameter not supported: " + param);
- }
- if (value instanceof MessageDigest[] == false) {
- throw new InvalidParameterException
- ("value must be MessageDigest[]");
- }
- MessageDigest[] digests = (MessageDigest[])value;
- md5 = digests[0];
- sha = digests[1];
- }
-
- protected Object engineGetParameter(String param)
- throws InvalidParameterException {
- throw new InvalidParameterException("Parameters not supported");
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/RandomCookie.java b/ojluni/src/main/java/sun/security/ssl/RandomCookie.java
deleted file mode 100755
index 5f414c4..0000000
--- a/ojluni/src/main/java/sun/security/ssl/RandomCookie.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.security.SecureRandom;
-
-/*
- * RandomCookie ... SSL hands standard format random cookies (nonces)
- * around. These know how to encode/decode themselves on SSL streams,
- * and can be created and printed.
- *
- * @author David Brownell
- */
-final class RandomCookie {
-
- byte random_bytes[]; // exactly 32 bytes
-
- RandomCookie(SecureRandom generator) {
- long temp = System.currentTimeMillis() / 1000;
- int gmt_unix_time;
- if (temp < Integer.MAX_VALUE) {
- gmt_unix_time = (int) temp;
- } else {
- gmt_unix_time = Integer.MAX_VALUE; // Whoops!
- }
-
- random_bytes = new byte[32];
- generator.nextBytes(random_bytes);
-
- random_bytes[0] = (byte)(gmt_unix_time >> 24);
- random_bytes[1] = (byte)(gmt_unix_time >> 16);
- random_bytes[2] = (byte)(gmt_unix_time >> 8);
- random_bytes[3] = (byte)gmt_unix_time;
- }
-
- RandomCookie(HandshakeInStream m) throws IOException {
- random_bytes = new byte[32];
- m.read(random_bytes, 0, 32);
- }
-
- void send(HandshakeOutStream out) throws IOException {
- out.write(random_bytes, 0, 32);
- }
-
- void print(PrintStream s) {
- int i, gmt_unix_time;
-
- gmt_unix_time = random_bytes[0] << 24;
- gmt_unix_time += random_bytes[1] << 16;
- gmt_unix_time += random_bytes[2] << 8;
- gmt_unix_time += random_bytes[3];
-
- s.print("GMT: " + gmt_unix_time + " ");
- s.print("bytes = { ");
-
- for (i = 4; i < 32; i++) {
- if (i != 4) {
- s.print(", ");
- }
- s.print(random_bytes[i] & 0x0ff);
- }
- s.println(" }");
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/Record.java b/ojluni/src/main/java/sun/security/ssl/Record.java
deleted file mode 100755
index 0494d9a..0000000
--- a/ojluni/src/main/java/sun/security/ssl/Record.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-
-/**
- * SSL/TLS records, as pulled off (and put onto) a TCP stream. This is
- * the base interface, which defines common information and interfaces
- * used by both Input and Output records.
- *
- * @author David Brownell
- */
-interface Record {
- /*
- * There are four SSL record types, which are part of the interface
- * to this level (along with the maximum record size)
- *
- * enum { change_cipher_spec(20), alert(21), handshake(22),
- * application_data(23), (255) } ContentType;
- */
- static final byte ct_change_cipher_spec = 20;
- static final byte ct_alert = 21;
- static final byte ct_handshake = 22;
- static final byte ct_application_data = 23;
-
- static final int headerSize = 5; // SSLv3 record header
- static final int maxExpansion = 1024; // for bad compression
- static final int trailerSize = 20; // SHA1 hash size
- static final int maxDataSize = 16384; // 2^14 bytes of data
- static final int maxPadding = 256; // block cipher padding
- static final int maxIVLength = 256; // block length
-
- /*
- * SSL has a maximum record size. It's header, (compressed) data,
- * padding, and a trailer for the MAC.
- * Some compression algorithms have rare cases where they expand the data.
- * As we don't support compression at this time, leave that out.
- */
- static final int maxRecordSize =
- headerSize // header
- + maxIVLength // iv
- + maxDataSize // data
- + maxPadding // padding
- + trailerSize; // MAC
-
- static final boolean enableCBCProtection =
- Debug.getBooleanProperty("jsse.enableCBCProtection", true);
-
- /*
- * For CBC protection in SSL3/TLS1, we break some plaintext into two
- * packets. Max application data size for the second packet.
- */
- static final int maxDataSizeMinusOneByteRecord =
- maxDataSize // max data size
- - ( // max one byte record size
- headerSize // header
- + maxIVLength // iv
- + 1 // one byte data
- + maxPadding // padding
- + trailerSize // MAC
- );
-
- /*
- * The maximum large record size.
- *
- * Some SSL/TLS implementations support large fragment upto 2^15 bytes,
- * such as Microsoft. We support large incoming fragments.
- *
- * The maximum large record size is defined as maxRecordSize plus 2^14,
- * this is the amount OpenSSL is using.
- */
- static final int maxLargeRecordSize =
- maxRecordSize // Max size with a conforming implemenation
- + maxDataSize; // extra 2^14 bytes for large data packets.
-
-
- /*
- * Maximum record size for alert and change cipher spec records.
- * They only contain 2 and 1 bytes of data, respectively.
- * Allocate a smaller array.
- */
- static final int maxAlertRecordSize =
- headerSize // header
- + maxIVLength // iv
- + 2 // alert
- + maxPadding // padding
- + trailerSize; // MAC
-
- /*
- * The overflow values of integers of 8, 16 and 24 bits.
- */
- static final int OVERFLOW_OF_INT08 = (1 << 8);
- static final int OVERFLOW_OF_INT16 = (1 << 16);
- static final int OVERFLOW_OF_INT24 = (1 << 24);
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLAlgorithmConstraints.java b/ojluni/src/main/java/sun/security/ssl/SSLAlgorithmConstraints.java
deleted file mode 100755
index 3980705..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLAlgorithmConstraints.java
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.AlgorithmConstraints;
-import java.security.CryptoPrimitive;
-import java.security.AlgorithmParameters;
-
-import javax.net.ssl.*;
-
-import java.security.Key;
-
-import java.util.Set;
-import java.util.HashSet;
-
-import sun.security.util.DisabledAlgorithmConstraints;
-import sun.security.ssl.CipherSuite.*;
-
-/**
- * Algorithm constraints for disabled algorithms property
- *
- * See the "jdk.certpath.disabledAlgorithms" specification in java.security
- * for the syntax of the disabled algorithm string.
- */
-final class SSLAlgorithmConstraints implements AlgorithmConstraints {
- private final static AlgorithmConstraints tlsDisabledAlgConstraints =
- new TLSDisabledAlgConstraints();
- private final static AlgorithmConstraints x509DisabledAlgConstraints =
- new X509DisabledAlgConstraints();
- private AlgorithmConstraints userAlgConstraints = null;
- private AlgorithmConstraints peerAlgConstraints = null;
-
- private boolean enabledX509DisabledAlgConstraints = true;
-
- SSLAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) {
- userAlgConstraints = algorithmConstraints;
- }
-
- SSLAlgorithmConstraints(SSLSocket socket,
- boolean withDefaultCertPathConstraints) {
- if (socket != null) {
- userAlgConstraints =
- socket.getSSLParameters().getAlgorithmConstraints();
- }
-
- if (!withDefaultCertPathConstraints) {
- enabledX509DisabledAlgConstraints = false;
- }
- }
-
- SSLAlgorithmConstraints(SSLEngine engine,
- boolean withDefaultCertPathConstraints) {
- if (engine != null) {
- userAlgConstraints =
- engine.getSSLParameters().getAlgorithmConstraints();
- }
-
- if (!withDefaultCertPathConstraints) {
- enabledX509DisabledAlgConstraints = false;
- }
- }
-
- SSLAlgorithmConstraints(SSLSocket socket, String[] supportedAlgorithms,
- boolean withDefaultCertPathConstraints) {
- if (socket != null) {
- userAlgConstraints =
- socket.getSSLParameters().getAlgorithmConstraints();
- peerAlgConstraints =
- new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
- }
-
- if (!withDefaultCertPathConstraints) {
- enabledX509DisabledAlgConstraints = false;
- }
- }
-
- SSLAlgorithmConstraints(SSLEngine engine, String[] supportedAlgorithms,
- boolean withDefaultCertPathConstraints) {
- if (engine != null) {
- userAlgConstraints =
- engine.getSSLParameters().getAlgorithmConstraints();
- peerAlgConstraints =
- new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
- }
-
- if (!withDefaultCertPathConstraints) {
- enabledX509DisabledAlgConstraints = false;
- }
- }
-
- public boolean permits(Set<CryptoPrimitive> primitives,
- String algorithm, AlgorithmParameters parameters) {
-
- boolean permitted = true;
-
- if (peerAlgConstraints != null) {
- permitted = peerAlgConstraints.permits(
- primitives, algorithm, parameters);
- }
-
- if (permitted && userAlgConstraints != null) {
- permitted = userAlgConstraints.permits(
- primitives, algorithm, parameters);
- }
-
- if (permitted) {
- permitted = tlsDisabledAlgConstraints.permits(
- primitives, algorithm, parameters);
- }
-
- if (permitted && enabledX509DisabledAlgConstraints) {
- permitted = x509DisabledAlgConstraints.permits(
- primitives, algorithm, parameters);
- }
-
- return permitted;
- }
-
- public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
-
- boolean permitted = true;
-
- if (peerAlgConstraints != null) {
- permitted = peerAlgConstraints.permits(primitives, key);
- }
-
- if (permitted && userAlgConstraints != null) {
- permitted = userAlgConstraints.permits(primitives, key);
- }
-
- if (permitted) {
- permitted = tlsDisabledAlgConstraints.permits(primitives, key);
- }
-
- if (permitted && enabledX509DisabledAlgConstraints) {
- permitted = x509DisabledAlgConstraints.permits(primitives, key);
- }
-
- return permitted;
- }
-
- public boolean permits(Set<CryptoPrimitive> primitives,
- String algorithm, Key key, AlgorithmParameters parameters) {
-
- boolean permitted = true;
-
- if (peerAlgConstraints != null) {
- permitted = peerAlgConstraints.permits(
- primitives, algorithm, key, parameters);
- }
-
- if (permitted && userAlgConstraints != null) {
- permitted = userAlgConstraints.permits(
- primitives, algorithm, key, parameters);
- }
-
- if (permitted) {
- permitted = tlsDisabledAlgConstraints.permits(
- primitives, algorithm, key, parameters);
- }
-
- if (permitted && enabledX509DisabledAlgConstraints) {
- permitted = x509DisabledAlgConstraints.permits(
- primitives, algorithm, key, parameters);
- }
-
- return permitted;
- }
-
-
- static private class SupportedSignatureAlgorithmConstraints
- implements AlgorithmConstraints {
- // supported signature algorithms
- private String[] supportedAlgorithms;
-
- SupportedSignatureAlgorithmConstraints(String[] supportedAlgorithms) {
- if (supportedAlgorithms != null) {
- this.supportedAlgorithms = supportedAlgorithms.clone();
- } else {
- this.supportedAlgorithms = null;
- }
- }
-
- public boolean permits(Set<CryptoPrimitive> primitives,
- String algorithm, AlgorithmParameters parameters) {
-
- if (algorithm == null || algorithm.length() == 0) {
- throw new IllegalArgumentException(
- "No algorithm name specified");
- }
-
- if (primitives == null || primitives.isEmpty()) {
- throw new IllegalArgumentException(
- "No cryptographic primitive specified");
- }
-
- if (supportedAlgorithms == null ||
- supportedAlgorithms.length == 0) {
- return false;
- }
-
- // trim the MGF part: <digest>with<encryption>and<mgf>
- int position = algorithm.indexOf("and");
- if (position > 0) {
- algorithm = algorithm.substring(0, position);
- }
-
- for (String supportedAlgorithm : supportedAlgorithms) {
- if (algorithm.equalsIgnoreCase(supportedAlgorithm)) {
- return true;
- }
- }
-
- return false;
- }
-
- final public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
- return true;
- }
-
- final public boolean permits(Set<CryptoPrimitive> primitives,
- String algorithm, Key key, AlgorithmParameters parameters) {
-
- if (algorithm == null || algorithm.length() == 0) {
- throw new IllegalArgumentException(
- "No algorithm name specified");
- }
-
- return permits(primitives, algorithm, parameters);
- }
- }
-
- static private class BasicDisabledAlgConstraints
- extends DisabledAlgorithmConstraints {
- BasicDisabledAlgConstraints(String propertyName) {
- super(propertyName);
- }
-
- protected Set<String> decomposes(KeyExchange keyExchange,
- boolean forCertPathOnly) {
- Set<String> components = new HashSet<>();
- switch (keyExchange) {
- case K_NULL:
- if (!forCertPathOnly) {
- components.add("NULL");
- }
- break;
- case K_RSA:
- components.add("RSA");
- break;
- case K_RSA_EXPORT:
- components.add("RSA");
- components.add("RSA_EXPORT");
- break;
- case K_DH_RSA:
- components.add("RSA");
- components.add("DH");
- components.add("DiffieHellman");
- components.add("DH_RSA");
- break;
- case K_DH_DSS:
- components.add("DSA");
- components.add("DSS");
- components.add("DH");
- components.add("DiffieHellman");
- components.add("DH_DSS");
- break;
- case K_DHE_DSS:
- components.add("DSA");
- components.add("DSS");
- components.add("DH");
- components.add("DHE");
- components.add("DiffieHellman");
- components.add("DHE_DSS");
- break;
- case K_DHE_RSA:
- components.add("RSA");
- components.add("DH");
- components.add("DHE");
- components.add("DiffieHellman");
- components.add("DHE_RSA");
- break;
- case K_DH_ANON:
- if (!forCertPathOnly) {
- components.add("ANON");
- components.add("DH");
- components.add("DiffieHellman");
- components.add("DH_ANON");
- }
- break;
- case K_ECDH_ECDSA:
- components.add("ECDH");
- components.add("ECDSA");
- components.add("ECDH_ECDSA");
- break;
- case K_ECDH_RSA:
- components.add("ECDH");
- components.add("RSA");
- components.add("ECDH_RSA");
- break;
- case K_ECDHE_ECDSA:
- components.add("ECDHE");
- components.add("ECDSA");
- components.add("ECDHE_ECDSA");
- break;
- case K_ECDHE_RSA:
- components.add("ECDHE");
- components.add("RSA");
- components.add("ECDHE_RSA");
- break;
- case K_ECDH_ANON:
- if (!forCertPathOnly) {
- components.add("ECDH");
- components.add("ANON");
- components.add("ECDH_ANON");
- }
- break;
- case K_KRB5:
- if (!forCertPathOnly) {
- components.add("KRB5");
- }
- break;
- case K_KRB5_EXPORT:
- if (!forCertPathOnly) {
- components.add("KRB5_EXPORT");
- }
- break;
- default:
- // ignore
- }
-
- return components;
- }
-
- protected Set<String> decomposes(BulkCipher bulkCipher) {
- Set<String> components = new HashSet<>();
-
- if (bulkCipher.transformation != null) {
- components.addAll(super.decomposes(bulkCipher.transformation));
- }
-
- return components;
- }
-
- protected Set<String> decomposes(MacAlg macAlg) {
- Set<String> components = new HashSet<>();
-
- if (macAlg == CipherSuite.M_MD5) {
- components.add("MD5");
- components.add("HmacMD5");
- } else if (macAlg == CipherSuite.M_SHA) {
- components.add("SHA1");
- components.add("SHA-1");
- components.add("HmacSHA1");
- } else if (macAlg == CipherSuite.M_SHA256) {
- components.add("SHA256");
- components.add("SHA-256");
- components.add("HmacSHA256");
- } else if (macAlg == CipherSuite.M_SHA384) {
- components.add("SHA384");
- components.add("SHA-384");
- components.add("HmacSHA384");
- }
-
- return components;
- }
- }
-
- static private class TLSDisabledAlgConstraints
- extends BasicDisabledAlgConstraints {
-
- TLSDisabledAlgConstraints() {
- super(DisabledAlgorithmConstraints.PROPERTY_TLS_DISABLED_ALGS);
- }
-
- @Override
- protected Set<String> decomposes(String algorithm) {
- if (algorithm.startsWith("SSL_") || algorithm.startsWith("TLS_")) {
- CipherSuite cipherSuite = null;
- try {
- cipherSuite = CipherSuite.valueOf(algorithm);
- } catch (IllegalArgumentException iae) {
- // ignore: unknown or unsupported ciphersuite
- }
-
- if (cipherSuite != null) {
- Set<String> components = new HashSet<>();
-
- if(cipherSuite.keyExchange != null) {
- components.addAll(
- decomposes(cipherSuite.keyExchange, false));
- }
-
- if (cipherSuite.cipher != null) {
- components.addAll(decomposes(cipherSuite.cipher));
- }
-
- if (cipherSuite.macAlg != null) {
- components.addAll(decomposes(cipherSuite.macAlg));
- }
-
- return components;
- }
- }
-
- return super.decomposes(algorithm);
- }
- }
-
- static private class X509DisabledAlgConstraints
- extends BasicDisabledAlgConstraints {
-
- X509DisabledAlgConstraints() {
- super(DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
- }
-
- @Override
- protected Set<String> decomposes(String algorithm) {
- if (algorithm.startsWith("SSL_") || algorithm.startsWith("TLS_")) {
- CipherSuite cipherSuite = null;
- try {
- cipherSuite = CipherSuite.valueOf(algorithm);
- } catch (IllegalArgumentException iae) {
- // ignore: unknown or unsupported ciphersuite
- }
-
- if (cipherSuite != null) {
- Set<String> components = new HashSet<>();
-
- if(cipherSuite.keyExchange != null) {
- components.addAll(
- decomposes(cipherSuite.keyExchange, true));
- }
-
- // Certification path algorithm constraints do not apply
- // to cipherSuite.cipher and cipherSuite.macAlg.
-
- return components;
- }
- }
-
- return super.decomposes(algorithm);
- }
- }
-}
-
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLContextImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLContextImpl.java
deleted file mode 100755
index c2081b7..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLContextImpl.java
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.net.Socket;
-
-import java.io.*;
-import java.util.*;
-import java.security.*;
-import java.security.cert.*;
-import java.security.cert.Certificate;
-
-import javax.net.ssl.*;
-
-import sun.security.provider.certpath.AlgorithmChecker;
-
-public abstract class SSLContextImpl extends SSLContextSpi {
-
- private static final Debug debug = Debug.getInstance("ssl");
-
- private final EphemeralKeyManager ephemeralKeyManager;
- private final SSLSessionContextImpl clientCache;
- private final SSLSessionContextImpl serverCache;
-
- private boolean isInitialized;
-
- private X509ExtendedKeyManager keyManager;
- private X509TrustManager trustManager;
- private SecureRandom secureRandom;
-
- // The default algrithm constraints
- private AlgorithmConstraints defaultAlgorithmConstraints =
- new SSLAlgorithmConstraints(null);
-
- // supported and default protocols
- private ProtocolList defaultServerProtocolList;
- private ProtocolList defaultClientProtocolList;
- private ProtocolList supportedProtocolList;
-
- // supported and default cipher suites
- private CipherSuiteList defaultServerCipherSuiteList;
- private CipherSuiteList defaultClientCipherSuiteList;
- private CipherSuiteList supportedCipherSuiteList;
-
- SSLContextImpl() {
- ephemeralKeyManager = new EphemeralKeyManager();
- clientCache = new SSLSessionContextImpl();
- serverCache = new SSLSessionContextImpl();
- }
-
- protected void engineInit(KeyManager[] km, TrustManager[] tm,
- SecureRandom sr) throws KeyManagementException {
- isInitialized = false;
- keyManager = chooseKeyManager(km);
-
- if (tm == null) {
- try {
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(
- TrustManagerFactory.getDefaultAlgorithm());
- tmf.init((KeyStore)null);
- tm = tmf.getTrustManagers();
- } catch (Exception e) {
- // eat
- }
- }
- trustManager = chooseTrustManager(tm);
-
- if (sr == null) {
- secureRandom = JsseJce.getSecureRandom();
- } else {
- if (SunJSSE.isFIPS() &&
- (sr.getProvider() != SunJSSE.cryptoProvider)) {
- throw new KeyManagementException
- ("FIPS mode: SecureRandom must be from provider "
- + SunJSSE.cryptoProvider.getName());
- }
- secureRandom = sr;
- }
-
- /*
- * The initial delay of seeding the random number generator
- * could be long enough to cause the initial handshake on our
- * first connection to timeout and fail. Make sure it is
- * primed and ready by getting some initial output from it.
- */
- if (debug != null && Debug.isOn("sslctx")) {
- System.out.println("trigger seeding of SecureRandom");
- }
- secureRandom.nextInt();
- if (debug != null && Debug.isOn("sslctx")) {
- System.out.println("done seeding SecureRandom");
- }
- isInitialized = true;
- }
-
- private X509TrustManager chooseTrustManager(TrustManager[] tm)
- throws KeyManagementException {
- // We only use the first instance of X509TrustManager passed to us.
- for (int i = 0; tm != null && i < tm.length; i++) {
- if (tm[i] instanceof X509TrustManager) {
- if (SunJSSE.isFIPS() &&
- !(tm[i] instanceof X509TrustManagerImpl)) {
- throw new KeyManagementException
- ("FIPS mode: only SunJSSE TrustManagers may be used");
- }
-
- if (tm[i] instanceof X509ExtendedTrustManager) {
- return (X509TrustManager)tm[i];
- } else {
- return new AbstractTrustManagerWrapper(
- (X509TrustManager)tm[i]);
- }
- }
- }
-
- // nothing found, return a dummy X509TrustManager.
- return DummyX509TrustManager.INSTANCE;
- }
-
- private X509ExtendedKeyManager chooseKeyManager(KeyManager[] kms)
- throws KeyManagementException {
- for (int i = 0; kms != null && i < kms.length; i++) {
- KeyManager km = kms[i];
- if (!(km instanceof X509KeyManager)) {
- continue;
- }
- if (SunJSSE.isFIPS()) {
- // In FIPS mode, require that one of SunJSSE's own keymanagers
- // is used. Otherwise, we cannot be sure that only keys from
- // the FIPS token are used.
- if ((km instanceof X509KeyManagerImpl)
- || (km instanceof SunX509KeyManagerImpl)) {
- return (X509ExtendedKeyManager)km;
- } else {
- // throw exception, we don't want to silently use the
- // dummy keymanager without telling the user.
- throw new KeyManagementException
- ("FIPS mode: only SunJSSE KeyManagers may be used");
- }
- }
- if (km instanceof X509ExtendedKeyManager) {
- return (X509ExtendedKeyManager)km;
- }
- if (debug != null && Debug.isOn("sslctx")) {
- System.out.println(
- "X509KeyManager passed to " +
- "SSLContext.init(): need an " +
- "X509ExtendedKeyManager for SSLEngine use");
- }
- return new AbstractKeyManagerWrapper((X509KeyManager)km);
- }
-
- // nothing found, return a dummy X509ExtendedKeyManager
- return DummyX509KeyManager.INSTANCE;
- }
-
- protected SSLSocketFactory engineGetSocketFactory() {
- if (!isInitialized) {
- throw new IllegalStateException(
- "SSLContextImpl is not initialized");
- }
- return new SSLSocketFactoryImpl(this);
- }
-
- protected SSLServerSocketFactory engineGetServerSocketFactory() {
- if (!isInitialized) {
- throw new IllegalStateException("SSLContext is not initialized");
- }
- return new SSLServerSocketFactoryImpl(this);
- }
-
- protected SSLEngine engineCreateSSLEngine() {
- if (!isInitialized) {
- throw new IllegalStateException(
- "SSLContextImpl is not initialized");
- }
- return new SSLEngineImpl(this);
- }
-
- protected SSLEngine engineCreateSSLEngine(String host, int port) {
- if (!isInitialized) {
- throw new IllegalStateException(
- "SSLContextImpl is not initialized");
- }
- return new SSLEngineImpl(this, host, port);
- }
-
- protected SSLSessionContext engineGetClientSessionContext() {
- return clientCache;
- }
-
- protected SSLSessionContext engineGetServerSessionContext() {
- return serverCache;
- }
-
- SecureRandom getSecureRandom() {
- return secureRandom;
- }
-
- X509ExtendedKeyManager getX509KeyManager() {
- return keyManager;
- }
-
- X509TrustManager getX509TrustManager() {
- return trustManager;
- }
-
- EphemeralKeyManager getEphemeralKeyManager() {
- return ephemeralKeyManager;
- }
-
- abstract SSLParameters getDefaultServerSSLParams();
- abstract SSLParameters getDefaultClientSSLParams();
- abstract SSLParameters getSupportedSSLParams();
-
- // Get suported ProtoclList.
- ProtocolList getSuportedProtocolList() {
- if (supportedProtocolList == null) {
- supportedProtocolList =
- new ProtocolList(getSupportedSSLParams().getProtocols());
- }
-
- return supportedProtocolList;
- }
-
- // Get default ProtoclList.
- ProtocolList getDefaultProtocolList(boolean roleIsServer) {
- if (roleIsServer) {
- if (defaultServerProtocolList == null) {
- defaultServerProtocolList = new ProtocolList(
- getDefaultServerSSLParams().getProtocols());
- }
-
- return defaultServerProtocolList;
- } else {
- if (defaultClientProtocolList == null) {
- defaultClientProtocolList = new ProtocolList(
- getDefaultClientSSLParams().getProtocols());
- }
-
- return defaultClientProtocolList;
- }
- }
-
- // Get suported CipherSuiteList.
- CipherSuiteList getSupportedCipherSuiteList() {
- // The maintenance of cipher suites needs to be synchronized.
- synchronized (this) {
- // Clear cache of available ciphersuites.
- clearAvailableCache();
-
- if (supportedCipherSuiteList == null) {
- supportedCipherSuiteList = getApplicableCipherSuiteList(
- getSuportedProtocolList(), false);
- }
-
- return supportedCipherSuiteList;
- }
- }
-
- // Get default CipherSuiteList.
- CipherSuiteList getDefaultCipherSuiteList(boolean roleIsServer) {
- // The maintenance of cipher suites needs to be synchronized.
- synchronized (this) {
- // Clear cache of available ciphersuites.
- clearAvailableCache();
-
- if (roleIsServer) {
- if (defaultServerCipherSuiteList == null) {
- defaultServerCipherSuiteList = getApplicableCipherSuiteList(
- getDefaultProtocolList(true), true);
- }
-
- return defaultServerCipherSuiteList;
- } else {
- if (defaultClientCipherSuiteList == null) {
- defaultClientCipherSuiteList = getApplicableCipherSuiteList(
- getDefaultProtocolList(false), true);
- }
-
- return defaultClientCipherSuiteList;
- }
- }
- }
-
- /**
- * Return whether a protocol list is the original default enabled
- * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
- */
- boolean isDefaultProtocolList(ProtocolList protocols) {
- return (protocols == defaultServerProtocolList) ||
- (protocols == defaultClientProtocolList);
- }
-
-
- /*
- * Return the list of all available CipherSuites with a priority of
- * minPriority or above.
- */
- private CipherSuiteList getApplicableCipherSuiteList(
- ProtocolList protocols, boolean onlyEnabled) {
-
- int minPriority = CipherSuite.SUPPORTED_SUITES_PRIORITY;
- if (onlyEnabled) {
- minPriority = CipherSuite.DEFAULT_SUITES_PRIORITY;
- }
-
- Collection<CipherSuite> allowedCipherSuites =
- CipherSuite.allowedCipherSuites();
-
- TreeSet<CipherSuite> suites = new TreeSet<>();
- if (!(protocols.collection().isEmpty()) &&
- protocols.min.v != ProtocolVersion.NONE.v) {
- for (CipherSuite suite : allowedCipherSuites) {
- if (!suite.allowed || suite.priority < minPriority) {
- continue;
- }
-
- if (suite.isAvailable() &&
- suite.obsoleted > protocols.min.v &&
- suite.supported <= protocols.max.v) {
- if (defaultAlgorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- suite.name, null)) {
- suites.add(suite);
- }
- } else if (debug != null &&
- Debug.isOn("sslctx") && Debug.isOn("verbose")) {
- if (suite.obsoleted <= protocols.min.v) {
- System.out.println(
- "Ignoring obsoleted cipher suite: " + suite);
- } else if (suite.supported > protocols.max.v) {
- System.out.println(
- "Ignoring unsupported cipher suite: " + suite);
- } else {
- System.out.println(
- "Ignoring unavailable cipher suite: " + suite);
- }
- }
- }
- }
-
- return new CipherSuiteList(suites);
- }
-
- /**
- * Clear cache of available ciphersuites. If we support all ciphers
- * internally, there is no need to clear the cache and calling this
- * method has no effect.
- *
- * Note that every call to clearAvailableCache() and the maintenance of
- * cipher suites need to be synchronized with this instance.
- */
- private void clearAvailableCache() {
- if (CipherSuite.DYNAMIC_AVAILABILITY) {
- supportedCipherSuiteList = null;
- defaultServerCipherSuiteList = null;
- defaultClientCipherSuiteList = null;
- CipherSuite.BulkCipher.clearAvailableCache();
- JsseJce.clearEcAvailable();
- }
- }
-
- /*
- * The SSLContext implementation for TLS/SSL algorithm
- *
- * SSL/TLS protocols specify the forward compatibility and version
- * roll-back attack protections, however, a number of SSL/TLS server
- * vendors did not implement these aspects properly, and some current
- * SSL/TLS servers may refuse to talk to a TLS 1.1 or later client.
- *
- * Considering above interoperability issues, SunJSSE will not set
- * TLS 1.1 and TLS 1.2 as the enabled protocols for client by default.
- *
- * For SSL/TLS servers, there is no such interoperability issues as
- * SSL/TLS clients. In SunJSSE, TLS 1.1 or later version will be the
- * enabled protocols for server by default.
- *
- * We may change the behavior when popular TLS/SSL vendors support TLS
- * forward compatibility properly.
- *
- * SSLv2Hello is no longer necessary. This interoperability option was
- * put in place in the late 90's when SSLv3/TLS1.0 were relatively new
- * and there were a fair number of SSLv2-only servers deployed. Because
- * of the security issues in SSLv2, it is rarely (if ever) used, as
- * deployments should now be using SSLv3 and TLSv1.
- *
- * Considering the issues of SSLv2Hello, we should not enable SSLv2Hello
- * by default. Applications still can use it by enabling SSLv2Hello with
- * the series of setEnabledProtocols APIs.
- */
-
- /*
- * The conservative SSLContext implementation for TLS, SSL, SSLv3 and
- * TLS10 algorithm.
- *
- * This is a super class of DefaultSSLContext and TLS10Context.
- *
- * @see SSLContext
- */
- private static class ConservativeSSLContext extends SSLContextImpl {
- // parameters
- private static SSLParameters defaultServerSSLParams;
- private static SSLParameters defaultClientSSLParams;
- private static SSLParameters supportedSSLParams;
-
- static {
- if (SunJSSE.isFIPS()) {
- supportedSSLParams = new SSLParameters();
- supportedSSLParams.setProtocols(new String[] {
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
-
- defaultServerSSLParams = supportedSSLParams;
-
- defaultClientSSLParams = new SSLParameters();
- defaultClientSSLParams.setProtocols(new String[] {
- ProtocolVersion.TLS10.name
- });
-
- } else {
- supportedSSLParams = new SSLParameters();
- supportedSSLParams.setProtocols(new String[] {
- ProtocolVersion.SSL20Hello.name,
- ProtocolVersion.SSL30.name,
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
-
- defaultServerSSLParams = supportedSSLParams;
-
- defaultClientSSLParams = new SSLParameters();
- defaultClientSSLParams.setProtocols(new String[] {
- ProtocolVersion.SSL30.name,
- ProtocolVersion.TLS10.name
- });
- }
- }
-
- SSLParameters getDefaultServerSSLParams() {
- return defaultServerSSLParams;
- }
-
- SSLParameters getDefaultClientSSLParams() {
- return defaultClientSSLParams;
- }
-
- SSLParameters getSupportedSSLParams() {
- return supportedSSLParams;
- }
- }
-
- /*
- * The SSLContext implementation for default algorithm
- *
- * @see SSLContext
- */
- public static final class DefaultSSLContext extends ConservativeSSLContext {
- private static final String NONE = "NONE";
- private static final String P11KEYSTORE = "PKCS11";
-
- private static volatile SSLContextImpl defaultImpl;
-
- private static TrustManager[] defaultTrustManagers;
- private static KeyManager[] defaultKeyManagers;
-
- public DefaultSSLContext() throws Exception {
- try {
- super.engineInit(getDefaultKeyManager(),
- getDefaultTrustManager(), null);
- } catch (Exception e) {
- if (debug != null && Debug.isOn("defaultctx")) {
- System.out.println("default context init failed: " + e);
- }
- throw e;
- }
-
- if (defaultImpl == null) {
- defaultImpl = this;
- }
- }
-
- protected void engineInit(KeyManager[] km, TrustManager[] tm,
- SecureRandom sr) throws KeyManagementException {
- throw new KeyManagementException
- ("Default SSLContext is initialized automatically");
- }
-
- static synchronized SSLContextImpl getDefaultImpl() throws Exception {
- if (defaultImpl == null) {
- new DefaultSSLContext();
- }
- return defaultImpl;
- }
-
- private static synchronized TrustManager[] getDefaultTrustManager()
- throws Exception {
- if (defaultTrustManagers != null) {
- return defaultTrustManagers;
- }
-
- KeyStore ks =
- TrustManagerFactoryImpl.getCacertsKeyStore("defaultctx");
-
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(
- TrustManagerFactory.getDefaultAlgorithm());
- tmf.init(ks);
- defaultTrustManagers = tmf.getTrustManagers();
- return defaultTrustManagers;
- }
-
- private static synchronized KeyManager[] getDefaultKeyManager()
- throws Exception {
- if (defaultKeyManagers != null) {
- return defaultKeyManagers;
- }
-
- final Map<String,String> props = new HashMap<>();
- AccessController.doPrivileged(
- new PrivilegedExceptionAction<Object>() {
- public Object run() throws Exception {
- props.put("keyStore", System.getProperty(
- "javax.net.ssl.keyStore", ""));
- props.put("keyStoreType", System.getProperty(
- "javax.net.ssl.keyStoreType",
- KeyStore.getDefaultType()));
- props.put("keyStoreProvider", System.getProperty(
- "javax.net.ssl.keyStoreProvider", ""));
- props.put("keyStorePasswd", System.getProperty(
- "javax.net.ssl.keyStorePassword", ""));
- return null;
- }
- });
-
- final String defaultKeyStore = props.get("keyStore");
- String defaultKeyStoreType = props.get("keyStoreType");
- String defaultKeyStoreProvider = props.get("keyStoreProvider");
- if (debug != null && Debug.isOn("defaultctx")) {
- System.out.println("keyStore is : " + defaultKeyStore);
- System.out.println("keyStore type is : " +
- defaultKeyStoreType);
- System.out.println("keyStore provider is : " +
- defaultKeyStoreProvider);
- }
-
- if (P11KEYSTORE.equals(defaultKeyStoreType) &&
- !NONE.equals(defaultKeyStore)) {
- throw new IllegalArgumentException("if keyStoreType is "
- + P11KEYSTORE + ", then keyStore must be " + NONE);
- }
-
- FileInputStream fs = null;
- if (defaultKeyStore.length() != 0 && !NONE.equals(defaultKeyStore)) {
- fs = AccessController.doPrivileged(
- new PrivilegedExceptionAction<FileInputStream>() {
- public FileInputStream run() throws Exception {
- return new FileInputStream(defaultKeyStore);
- }
- });
- }
-
- String defaultKeyStorePassword = props.get("keyStorePasswd");
- char[] passwd = null;
- if (defaultKeyStorePassword.length() != 0) {
- passwd = defaultKeyStorePassword.toCharArray();
- }
-
- /**
- * Try to initialize key store.
- */
- KeyStore ks = null;
- if ((defaultKeyStoreType.length()) != 0) {
- if (debug != null && Debug.isOn("defaultctx")) {
- System.out.println("init keystore");
- }
- if (defaultKeyStoreProvider.length() == 0) {
- ks = KeyStore.getInstance(defaultKeyStoreType);
- } else {
- ks = KeyStore.getInstance(defaultKeyStoreType,
- defaultKeyStoreProvider);
- }
-
- // if defaultKeyStore is NONE, fs will be null
- ks.load(fs, passwd);
- }
- if (fs != null) {
- fs.close();
- fs = null;
- }
-
- /*
- * Try to initialize key manager.
- */
- if (debug != null && Debug.isOn("defaultctx")) {
- System.out.println("init keymanager of type " +
- KeyManagerFactory.getDefaultAlgorithm());
- }
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(
- KeyManagerFactory.getDefaultAlgorithm());
-
- if (P11KEYSTORE.equals(defaultKeyStoreType)) {
- kmf.init(ks, null); // do not pass key passwd if using token
- } else {
- kmf.init(ks, passwd);
- }
-
- defaultKeyManagers = kmf.getKeyManagers();
- return defaultKeyManagers;
- }
- }
-
- /*
- * The SSLContext implementation for TLS, SSL, SSLv3 and TLS10 algorithm
- *
- * @see SSLContext
- */
- public static final class TLS10Context extends ConservativeSSLContext {
- // use the default constructor and methods
- }
-
- /*
- * The SSLContext implementation for TLS11 algorithm
- *
- * @see SSLContext
- */
- public static final class TLS11Context extends SSLContextImpl {
- // parameters
- private static SSLParameters defaultServerSSLParams;
- private static SSLParameters defaultClientSSLParams;
- private static SSLParameters supportedSSLParams;
-
- static {
- if (SunJSSE.isFIPS()) {
- supportedSSLParams = new SSLParameters();
- supportedSSLParams.setProtocols(new String[] {
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
-
- defaultServerSSLParams = supportedSSLParams;
-
- defaultClientSSLParams = new SSLParameters();
- defaultClientSSLParams.setProtocols(new String[] {
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name
- });
-
- } else {
- supportedSSLParams = new SSLParameters();
- supportedSSLParams.setProtocols(new String[] {
- ProtocolVersion.SSL20Hello.name,
- ProtocolVersion.SSL30.name,
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
-
- defaultServerSSLParams = supportedSSLParams;
-
- defaultClientSSLParams = new SSLParameters();
- defaultClientSSLParams.setProtocols(new String[] {
- ProtocolVersion.SSL30.name,
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name
- });
- }
- }
-
- SSLParameters getDefaultServerSSLParams() {
- return defaultServerSSLParams;
- }
-
- SSLParameters getDefaultClientSSLParams() {
- return defaultClientSSLParams;
- }
-
- SSLParameters getSupportedSSLParams() {
- return supportedSSLParams;
- }
- }
-
- /*
- * The SSLContext implementation for TLS12 algorithm
- *
- * @see SSLContext
- */
- public static final class TLS12Context extends SSLContextImpl {
- // parameters
- private static SSLParameters defaultServerSSLParams;
- private static SSLParameters defaultClientSSLParams;
- private static SSLParameters supportedSSLParams;
-
- static {
- if (SunJSSE.isFIPS()) {
- supportedSSLParams = new SSLParameters();
- supportedSSLParams.setProtocols(new String[] {
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
-
- defaultServerSSLParams = supportedSSLParams;
-
- defaultClientSSLParams = new SSLParameters();
- defaultClientSSLParams.setProtocols(new String[] {
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
-
- } else {
- supportedSSLParams = new SSLParameters();
- supportedSSLParams.setProtocols(new String[] {
- ProtocolVersion.SSL20Hello.name,
- ProtocolVersion.SSL30.name,
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
-
- defaultServerSSLParams = supportedSSLParams;
-
- defaultClientSSLParams = new SSLParameters();
- defaultClientSSLParams.setProtocols(new String[] {
- ProtocolVersion.SSL30.name,
- ProtocolVersion.TLS10.name,
- ProtocolVersion.TLS11.name,
- ProtocolVersion.TLS12.name
- });
- }
- }
-
- SSLParameters getDefaultServerSSLParams() {
- return defaultServerSSLParams;
- }
-
- SSLParameters getDefaultClientSSLParams() {
- return defaultClientSSLParams;
- }
-
- SSLParameters getSupportedSSLParams() {
- return supportedSSLParams;
- }
- }
-
-}
-
-
-final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
- implements X509TrustManager {
-
- // the delegated trust manager
- private final X509TrustManager tm;
-
- AbstractTrustManagerWrapper(X509TrustManager tm) {
- this.tm = tm;
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- tm.checkClientTrusted(chain, authType);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- tm.checkServerTrusted(chain, authType);
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return tm.getAcceptedIssuers();
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- Socket socket) throws CertificateException {
- tm.checkClientTrusted(chain, authType);
- checkAdditionalTrust(chain, authType, socket, true);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- Socket socket) throws CertificateException {
- tm.checkServerTrusted(chain, authType);
- checkAdditionalTrust(chain, authType, socket, false);
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- SSLEngine engine) throws CertificateException {
- tm.checkClientTrusted(chain, authType);
- checkAdditionalTrust(chain, authType, engine, true);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- SSLEngine engine) throws CertificateException {
- tm.checkServerTrusted(chain, authType);
- checkAdditionalTrust(chain, authType, engine, false);
- }
-
- private void checkAdditionalTrust(X509Certificate[] chain, String authType,
- Socket socket, boolean isClient) throws CertificateException {
- if (socket != null && socket.isConnected() &&
- socket instanceof SSLSocket) {
-
- SSLSocket sslSocket = (SSLSocket)socket;
- SSLSession session = sslSocket.getHandshakeSession();
- if (session == null) {
- throw new CertificateException("No handshake session");
- }
-
- // check endpoint identity
- String identityAlg = sslSocket.getSSLParameters().
- getEndpointIdentificationAlgorithm();
- if (identityAlg != null && identityAlg.length() != 0) {
- String hostname = session.getPeerHost();
- X509TrustManagerImpl.checkIdentity(
- hostname, chain[0], identityAlg);
- }
-
- // try the best to check the algorithm constraints
- ProtocolVersion protocolVersion =
- ProtocolVersion.valueOf(session.getProtocol());
- AlgorithmConstraints constraints = null;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (session instanceof ExtendedSSLSession) {
- ExtendedSSLSession extSession =
- (ExtendedSSLSession)session;
- String[] peerSupportedSignAlgs =
- extSession.getLocalSupportedSignatureAlgorithms();
-
- constraints = new SSLAlgorithmConstraints(
- sslSocket, peerSupportedSignAlgs, true);
- } else {
- constraints =
- new SSLAlgorithmConstraints(sslSocket, true);
- }
- } else {
- constraints = new SSLAlgorithmConstraints(sslSocket, true);
- }
-
- checkAlgorithmConstraints(chain, constraints);
- }
- }
-
- private void checkAdditionalTrust(X509Certificate[] chain, String authType,
- SSLEngine engine, boolean isClient) throws CertificateException {
- if (engine != null) {
- SSLSession session = engine.getHandshakeSession();
- if (session == null) {
- throw new CertificateException("No handshake session");
- }
-
- // check endpoint identity
- String identityAlg = engine.getSSLParameters().
- getEndpointIdentificationAlgorithm();
- if (identityAlg != null && identityAlg.length() != 0) {
- String hostname = session.getPeerHost();
- X509TrustManagerImpl.checkIdentity(
- hostname, chain[0], identityAlg);
- }
-
- // try the best to check the algorithm constraints
- ProtocolVersion protocolVersion =
- ProtocolVersion.valueOf(session.getProtocol());
- AlgorithmConstraints constraints = null;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (session instanceof ExtendedSSLSession) {
- ExtendedSSLSession extSession =
- (ExtendedSSLSession)session;
- String[] peerSupportedSignAlgs =
- extSession.getLocalSupportedSignatureAlgorithms();
-
- constraints = new SSLAlgorithmConstraints(
- engine, peerSupportedSignAlgs, true);
- } else {
- constraints =
- new SSLAlgorithmConstraints(engine, true);
- }
- } else {
- constraints = new SSLAlgorithmConstraints(engine, true);
- }
-
- checkAlgorithmConstraints(chain, constraints);
- }
- }
-
- private void checkAlgorithmConstraints(X509Certificate[] chain,
- AlgorithmConstraints constraints) throws CertificateException {
-
- try {
- // Does the certificate chain end with a trusted certificate?
- int checkedLength = chain.length - 1;
-
- Collection<X509Certificate> trustedCerts = new HashSet<>();
- X509Certificate[] certs = tm.getAcceptedIssuers();
- if ((certs != null) && (certs.length > 0)){
- Collections.addAll(trustedCerts, certs);
- }
-
- if (trustedCerts.contains(chain[checkedLength])) {
- checkedLength--;
- }
-
- // A forward checker, need to check from trust to target
- if (checkedLength >= 0) {
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
- checker.init(false);
- for (int i = checkedLength; i >= 0; i--) {
- Certificate cert = chain[i];
- // We don't care about the unresolved critical extensions.
- checker.check(cert, Collections.<String>emptySet());
- }
- }
- } catch (CertPathValidatorException cpve) {
- throw new CertificateException(
- "Certificates does not conform to algorithm constraints");
- }
- }
-}
-
-// Dummy X509TrustManager implementation, rejects all peer certificates.
-// Used if the application did not specify a proper X509TrustManager.
-final class DummyX509TrustManager extends X509ExtendedTrustManager
- implements X509TrustManager {
-
- static final X509TrustManager INSTANCE = new DummyX509TrustManager();
-
- private DummyX509TrustManager() {
- // empty
- }
-
- /*
- * Given the partial or complete certificate chain
- * provided by the peer, build a certificate path
- * to a trusted root and return if it can be
- * validated and is trusted for client SSL authentication.
- * If not, it throws an exception.
- */
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- throw new CertificateException(
- "No X509TrustManager implementation avaiable");
- }
-
- /*
- * Given the partial or complete certificate chain
- * provided by the peer, build a certificate path
- * to a trusted root and return if it can be
- * validated and is trusted for server SSL authentication.
- * If not, it throws an exception.
- */
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType)
- throws CertificateException {
- throw new CertificateException(
- "No X509TrustManager implementation available");
- }
-
- /*
- * Return an array of issuer certificates which are trusted
- * for authenticating peers.
- */
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- Socket socket) throws CertificateException {
- throw new CertificateException(
- "No X509TrustManager implementation available");
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- Socket socket) throws CertificateException {
- throw new CertificateException(
- "No X509TrustManager implementation available");
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- SSLEngine engine) throws CertificateException {
- throw new CertificateException(
- "No X509TrustManager implementation available");
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- SSLEngine engine) throws CertificateException {
- throw new CertificateException(
- "No X509TrustManager implementation available");
- }
-}
-
-/*
- * A wrapper class to turn a X509KeyManager into an X509ExtendedKeyManager
- */
-final class AbstractKeyManagerWrapper extends X509ExtendedKeyManager {
-
- private final X509KeyManager km;
-
- AbstractKeyManagerWrapper(X509KeyManager km) {
- this.km = km;
- }
-
- public String[] getClientAliases(String keyType, Principal[] issuers) {
- return km.getClientAliases(keyType, issuers);
- }
-
- public String chooseClientAlias(String[] keyType, Principal[] issuers,
- Socket socket) {
- return km.chooseClientAlias(keyType, issuers, socket);
- }
-
- public String[] getServerAliases(String keyType, Principal[] issuers) {
- return km.getServerAliases(keyType, issuers);
- }
-
- public String chooseServerAlias(String keyType, Principal[] issuers,
- Socket socket) {
- return km.chooseServerAlias(keyType, issuers, socket);
- }
-
- public X509Certificate[] getCertificateChain(String alias) {
- return km.getCertificateChain(alias);
- }
-
- public PrivateKey getPrivateKey(String alias) {
- return km.getPrivateKey(alias);
- }
-
- // Inherit chooseEngineClientAlias() and chooseEngineServerAlias() from
- // X509ExtendedKeymanager. It defines them to return null;
-}
-
-
-// Dummy X509KeyManager implementation, never returns any certificates/keys.
-// Used if the application did not specify a proper X509TrustManager.
-final class DummyX509KeyManager extends X509ExtendedKeyManager {
-
- static final X509ExtendedKeyManager INSTANCE = new DummyX509KeyManager();
-
- private DummyX509KeyManager() {
- // empty
- }
-
- /*
- * Get the matching aliases for authenticating the client side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String[] getClientAliases(String keyType, Principal[] issuers) {
- return null;
- }
-
- /*
- * Choose an alias to authenticate the client side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
- Socket socket) {
- return null;
- }
-
- /*
- * Choose an alias to authenticate the client side of an
- * engine given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String chooseEngineClientAlias(
- String[] keyTypes, Principal[] issuers, SSLEngine engine) {
- return null;
- }
-
- /*
- * Get the matching aliases for authenticating the server side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String[] getServerAliases(String keyType, Principal[] issuers) {
- return null;
- }
-
- /*
- * Choose an alias to authenticate the server side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String chooseServerAlias(String keyType, Principal[] issuers,
- Socket socket) {
- return null;
- }
-
- /*
- * Choose an alias to authenticate the server side of an engine
- * given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String chooseEngineServerAlias(
- String keyType, Principal[] issuers, SSLEngine engine) {
- return null;
- }
-
- /**
- * Returns the certificate chain associated with the given alias.
- *
- * @param alias the alias name
- *
- * @return the certificate chain (ordered with the user's certificate first
- * and the root certificate authority last)
- */
- public X509Certificate[] getCertificateChain(String alias) {
- return null;
- }
-
- /*
- * Returns the key associated with the given alias, using the given
- * password to recover it.
- *
- * @param alias the alias name
- *
- * @return the requested key
- */
- public PrivateKey getPrivateKey(String alias) {
- return null;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLEngineImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLEngineImpl.java
deleted file mode 100755
index afcbd51..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLEngineImpl.java
+++ /dev/null
@@ -1,2087 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-import java.nio.ReadOnlyBufferException;
-import java.util.LinkedList;
-import java.security.*;
-
-import javax.crypto.BadPaddingException;
-
-import javax.net.ssl.*;
-import javax.net.ssl.SSLEngineResult.*;
-
-import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
-
-/**
- * Implementation of an non-blocking SSLEngine.
- *
- * *Currently*, the SSLEngine code exists in parallel with the current
- * SSLSocket. As such, the current implementation is using legacy code
- * with many of the same abstractions. However, it varies in many
- * areas, most dramatically in the IO handling.
- *
- * There are three main I/O threads that can be existing in parallel:
- * wrap(), unwrap(), and beginHandshake(). We are encouraging users to
- * not call multiple instances of wrap or unwrap, because the data could
- * appear to flow out of the SSLEngine in a non-sequential order. We
- * take all steps we can to at least make sure the ordering remains
- * consistent, but once the calls returns, anything can happen. For
- * example, thread1 and thread2 both call wrap, thread1 gets the first
- * packet, thread2 gets the second packet, but thread2 gets control back
- * before thread1, and sends the data. The receiving side would see an
- * out-of-order error.
- *
- * Handshaking is still done the same way as SSLSocket using the normal
- * InputStream/OutputStream abstactions. We create
- * ClientHandshakers/ServerHandshakers, which produce/consume the
- * handshaking data. The transfer of the data is largely handled by the
- * HandshakeInStream/HandshakeOutStreams. Lastly, the
- * InputRecord/OutputRecords still have the same functionality, except
- * that they are overridden with EngineInputRecord/EngineOutputRecord,
- * which provide SSLEngine-specific functionality.
- *
- * Some of the major differences are:
- *
- * EngineInputRecord/EngineOutputRecord/EngineWriter:
- *
- * In order to avoid writing whole new control flows for
- * handshaking, and to reuse most of the same code, we kept most
- * of the actual handshake code the same. As usual, reading
- * handshake data may trigger output of more handshake data, so
- * what we do is write this data to internal buffers, and wait for
- * wrap() to be called to give that data a ride.
- *
- * All data is routed through
- * EngineInputRecord/EngineOutputRecord. However, all handshake
- * data (ct_alert/ct_change_cipher_spec/ct_handshake) are passed
- * through to the the underlying InputRecord/OutputRecord, and
- * the data uses the internal buffers.
- *
- * Application data is handled slightly different, we copy the data
- * directly from the src to the dst buffers, and do all operations
- * on those buffers, saving the overhead of multiple copies.
- *
- * In the case of an inbound record, unwrap passes the inbound
- * ByteBuffer to the InputRecord. If the data is handshake data,
- * the data is read into the InputRecord's internal buffer. If
- * the data is application data, the data is decoded directly into
- * the dst buffer.
- *
- * In the case of an outbound record, when the write to the
- * "real" OutputStream's would normally take place, instead we
- * call back up to the EngineOutputRecord's version of
- * writeBuffer, at which time we capture the resulting output in a
- * ByteBuffer, and send that back to the EngineWriter for internal
- * storage.
- *
- * EngineWriter is responsible for "handling" all outbound
- * data, be it handshake or app data, and for returning the data
- * to wrap() in the proper order.
- *
- * ClientHandshaker/ServerHandshaker/Handshaker:
- * Methods which relied on SSLSocket now have work on either
- * SSLSockets or SSLEngines.
- *
- * @author Brad Wetmore
- */
-final public class SSLEngineImpl extends SSLEngine {
-
- //
- // Fields and global comments
- //
-
- /*
- * There's a state machine associated with each connection, which
- * among other roles serves to negotiate session changes.
- *
- * - START with constructor, until the TCP connection's around.
- * - HANDSHAKE picks session parameters before allowing traffic.
- * There are many substates due to sequencing requirements
- * for handshake messages.
- * - DATA may be transmitted.
- * - RENEGOTIATE state allows concurrent data and handshaking
- * traffic ("same" substates as HANDSHAKE), and terminates
- * in selection of new session (and connection) parameters
- * - ERROR state immediately precedes abortive disconnect.
- * - CLOSED when one side closes down, used to start the shutdown
- * process. SSL connection objects are not reused.
- *
- * State affects what SSL record types may legally be sent:
- *
- * - Handshake ... only in HANDSHAKE and RENEGOTIATE states
- * - App Data ... only in DATA and RENEGOTIATE states
- * - Alert ... in HANDSHAKE, DATA, RENEGOTIATE
- *
- * Re what may be received: same as what may be sent, except that
- * HandshakeRequest handshaking messages can come from servers even
- * in the application data state, to request entry to RENEGOTIATE.
- *
- * The state machine within HANDSHAKE and RENEGOTIATE states controls
- * the pending session, not the connection state, until the change
- * cipher spec and "Finished" handshake messages are processed and
- * make the "new" session become the current one.
- *
- * NOTE: details of the SMs always need to be nailed down better.
- * The text above illustrates the core ideas.
- *
- * +---->-------+------>--------->-------+
- * | | |
- * <-----< ^ ^ <-----< |
- *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE |
- * v v v |
- * | | | |
- * +------------+---------------+ |
- * | |
- * v |
- * ERROR>------>----->CLOSED<--------<----+
- *
- * ALSO, note that the the purpose of handshaking (renegotiation is
- * included) is to assign a different, and perhaps new, session to
- * the connection. The SSLv3 spec is a bit confusing on that new
- * protocol feature.
- */
- private int connectionState;
-
- private static final int cs_START = 0;
- private static final int cs_HANDSHAKE = 1;
- private static final int cs_DATA = 2;
- private static final int cs_RENEGOTIATE = 3;
- private static final int cs_ERROR = 4;
- private static final int cs_CLOSED = 6;
-
- /*
- * Once we're in state cs_CLOSED, we can continue to
- * wrap/unwrap until we finish sending/receiving the messages
- * for close_notify. EngineWriter handles outboundDone.
- */
- private boolean inboundDone = false;
-
- EngineWriter writer;
-
- /*
- * The authentication context holds all information used to establish
- * who this end of the connection is (certificate chains, private keys,
- * etc) and who is trusted (e.g. as CAs or websites).
- */
- private SSLContextImpl sslContext;
-
- /*
- * This connection is one of (potentially) many associated with
- * any given session. The output of the handshake protocol is a
- * new session ... although all the protocol description talks
- * about changing the cipher spec (and it does change), in fact
- * that's incidental since it's done by changing everything that
- * is associated with a session at the same time. (TLS/IETF may
- * change that to add client authentication w/o new key exchg.)
- */
- private Handshaker handshaker;
- private SSLSessionImpl sess;
- private volatile SSLSessionImpl handshakeSession;
-
-
- /*
- * Client authentication be off, requested, or required.
- *
- * This will be used by both this class and SSLSocket's variants.
- */
- static final byte clauth_none = 0;
- static final byte clauth_requested = 1;
- static final byte clauth_required = 2;
-
- /*
- * Flag indicating if the next record we receive MUST be a Finished
- * message. Temporarily set during the handshake to ensure that
- * a change cipher spec message is followed by a finished message.
- */
- private boolean expectingFinished;
-
-
- /*
- * If someone tries to closeInbound() (say at End-Of-Stream)
- * our engine having received a close_notify, we need to
- * notify the app that we may have a truncation attack underway.
- */
- private boolean recvCN;
-
- /*
- * For improved diagnostics, we detail connection closure
- * If the engine is closed (connectionState >= cs_ERROR),
- * closeReason != null indicates if the engine was closed
- * because of an error or because or normal shutdown.
- */
- private SSLException closeReason;
-
- /*
- * Per-connection private state that doesn't change when the
- * session is changed.
- */
- private byte doClientAuth;
- private boolean enableSessionCreation = true;
- EngineInputRecord inputRecord;
- EngineOutputRecord outputRecord;
- private AccessControlContext acc;
-
- // The cipher suites enabled for use on this connection.
- private CipherSuiteList enabledCipherSuites;
-
- // the endpoint identification protocol
- private String identificationProtocol = null;
-
- // The cryptographic algorithm constraints
- private AlgorithmConstraints algorithmConstraints = null;
-
- // Have we been told whether we're client or server?
- private boolean serverModeSet = false;
- private boolean roleIsServer;
-
- /*
- * The protocol versions enabled for use on this connection.
- *
- * Note: we support a pseudo protocol called SSLv2Hello which when
- * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
- * or TLS (version 3.1, 3.2, etc.) version info.
- */
- private ProtocolList enabledProtocols;
-
- /*
- * The SSL version associated with this connection.
- */
- private ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT;
-
- /*
- * Crypto state that's reinitialized when the session changes.
- */
- private MAC readMAC, writeMAC;
- private CipherBox readCipher, writeCipher;
- // NOTE: compression state would be saved here
-
- /*
- * security parameters for secure renegotiation.
- */
- private boolean secureRenegotiation;
- private byte[] clientVerifyData;
- private byte[] serverVerifyData;
-
- /*
- * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
- * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
- * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
- *
- * There are several locks here.
- *
- * The primary lock is the per-instance lock used by
- * synchronized(this) and the synchronized methods. It controls all
- * access to things such as the connection state and variables which
- * affect handshaking. If we are inside a synchronized method, we
- * can access the state directly, otherwise, we must use the
- * synchronized equivalents.
- *
- * Note that we must never acquire the <code>this</code> lock after
- * <code>writeLock</code> or run the risk of deadlock.
- *
- * Grab some coffee, and be careful with any code changes.
- */
- private Object wrapLock;
- private Object unwrapLock;
- Object writeLock;
-
- /*
- * Is it the first application record to write?
- */
- private boolean isFirstAppOutputRecord = true;
-
- /*
- * Class and subclass dynamic debugging support
- */
- private static final Debug debug = Debug.getInstance("ssl");
-
- //
- // Initialization/Constructors
- //
-
- /**
- * Constructor for an SSLEngine from SSLContext, without
- * host/port hints. This Engine will not be able to cache
- * sessions, but must renegotiate everything by hand.
- */
- SSLEngineImpl(SSLContextImpl ctx) {
- super();
- init(ctx);
- }
-
- /**
- * Constructor for an SSLEngine from SSLContext.
- */
- SSLEngineImpl(SSLContextImpl ctx, String host, int port) {
- super(host, port);
- init(ctx);
- }
-
- /**
- * Initializes the Engine
- */
- private void init(SSLContextImpl ctx) {
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println("Using SSLEngineImpl.");
- }
-
- sslContext = ctx;
- sess = SSLSessionImpl.nullSession;
- handshakeSession = null;
-
- /*
- * State is cs_START until we initialize the handshaker.
- *
- * Apps using SSLEngine are probably going to be server.
- * Somewhat arbitrary choice.
- */
- roleIsServer = true;
- connectionState = cs_START;
-
- /*
- * default read and write side cipher and MAC support
- *
- * Note: compression support would go here too
- */
- readCipher = CipherBox.NULL;
- readMAC = MAC.NULL;
- writeCipher = CipherBox.NULL;
- writeMAC = MAC.NULL;
-
- // default security parameters for secure renegotiation
- secureRenegotiation = false;
- clientVerifyData = new byte[0];
- serverVerifyData = new byte[0];
-
- enabledCipherSuites =
- sslContext.getDefaultCipherSuiteList(roleIsServer);
- enabledProtocols =
- sslContext.getDefaultProtocolList(roleIsServer);
-
- wrapLock = new Object();
- unwrapLock = new Object();
- writeLock = new Object();
-
- /*
- * Save the Access Control Context. This will be used later
- * for a couple of things, including providing a context to
- * run tasks in, and for determining which credentials
- * to use for Subject based (JAAS) decisions
- */
- acc = AccessController.getContext();
-
- /*
- * All outbound application data goes through this OutputRecord,
- * other data goes through their respective records created
- * elsewhere. All inbound data goes through this one
- * input record.
- */
- outputRecord =
- new EngineOutputRecord(Record.ct_application_data, this);
- inputRecord = new EngineInputRecord(this);
- inputRecord.enableFormatChecks();
-
- writer = new EngineWriter();
- }
-
- /**
- * Initialize the handshaker object. This means:
- *
- * . if a handshake is already in progress (state is cs_HANDSHAKE
- * or cs_RENEGOTIATE), do nothing and return
- *
- * . if the engine is already closed, throw an Exception (internal error)
- *
- * . otherwise (cs_START or cs_DATA), create the appropriate handshaker
- * object and advance the connection state (to cs_HANDSHAKE or
- * cs_RENEGOTIATE, respectively).
- *
- * This method is called right after a new engine is created, when
- * starting renegotiation, or when changing client/server mode of the
- * engine.
- */
- private void initHandshaker() {
- switch (connectionState) {
-
- //
- // Starting a new handshake.
- //
- case cs_START:
- case cs_DATA:
- break;
-
- //
- // We're already in the middle of a handshake.
- //
- case cs_HANDSHAKE:
- case cs_RENEGOTIATE:
- return;
-
- //
- // Anyone allowed to call this routine is required to
- // do so ONLY if the connection state is reasonable...
- //
- default:
- throw new IllegalStateException("Internal error");
- }
-
- // state is either cs_START or cs_DATA
- if (connectionState == cs_START) {
- connectionState = cs_HANDSHAKE;
- } else { // cs_DATA
- connectionState = cs_RENEGOTIATE;
- }
- if (roleIsServer) {
- handshaker = new ServerHandshaker(this, sslContext,
- enabledProtocols, doClientAuth,
- protocolVersion, connectionState == cs_HANDSHAKE,
- secureRenegotiation, clientVerifyData, serverVerifyData);
- } else {
- handshaker = new ClientHandshaker(this, sslContext,
- enabledProtocols,
- protocolVersion, connectionState == cs_HANDSHAKE,
- secureRenegotiation, clientVerifyData, serverVerifyData);
- }
- handshaker.setEnabledCipherSuites(enabledCipherSuites);
- handshaker.setEnableSessionCreation(enableSessionCreation);
- }
-
- /*
- * Report the current status of the Handshaker
- */
- private HandshakeStatus getHSStatus(HandshakeStatus hss) {
-
- if (hss != null) {
- return hss;
- }
-
- synchronized (this) {
- if (writer.hasOutboundData()) {
- return HandshakeStatus.NEED_WRAP;
- } else if (handshaker != null) {
- if (handshaker.taskOutstanding()) {
- return HandshakeStatus.NEED_TASK;
- } else {
- return HandshakeStatus.NEED_UNWRAP;
- }
- } else if (connectionState == cs_CLOSED) {
- /*
- * Special case where we're closing, but
- * still need the close_notify before we
- * can officially be closed.
- *
- * Note isOutboundDone is taken care of by
- * hasOutboundData() above.
- */
- if (!isInboundDone()) {
- return HandshakeStatus.NEED_UNWRAP;
- } // else not handshaking
- }
-
- return HandshakeStatus.NOT_HANDSHAKING;
- }
- }
-
- synchronized private void checkTaskThrown() throws SSLException {
- if (handshaker != null) {
- handshaker.checkThrown();
- }
- }
-
- //
- // Handshaking and connection state code
- //
-
- /*
- * Provides "this" synchronization for connection state.
- * Otherwise, you can access it directly.
- */
- synchronized private int getConnectionState() {
- return connectionState;
- }
-
- synchronized private void setConnectionState(int state) {
- connectionState = state;
- }
-
- /*
- * Get the Access Control Context.
- *
- * Used for a known context to
- * run tasks in, and for determining which credentials
- * to use for Subject-based (JAAS) decisions.
- */
- AccessControlContext getAcc() {
- return acc;
- }
-
- /*
- * Is a handshake currently underway?
- */
- public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
- return getHSStatus(null);
- }
-
- /*
- * When a connection finishes handshaking by enabling use of a newly
- * negotiated session, each end learns about it in two halves (read,
- * and write). When both read and write ciphers have changed, and the
- * last handshake message has been read, the connection has joined
- * (rejoined) the new session.
- *
- * NOTE: The SSLv3 spec is rather unclear on the concepts here.
- * Sessions don't change once they're established (including cipher
- * suite and master secret) but connections can join them (and leave
- * them). They're created by handshaking, though sometime handshaking
- * causes connections to join up with pre-established sessions.
- *
- * Synchronized on "this" from readRecord.
- */
- private void changeReadCiphers() throws SSLException {
- if (connectionState != cs_HANDSHAKE
- && connectionState != cs_RENEGOTIATE) {
- throw new SSLProtocolException(
- "State error, change cipher specs");
- }
-
- // ... create decompressor
-
- CipherBox oldCipher = readCipher;
-
- try {
- readCipher = handshaker.newReadCipher();
- readMAC = handshaker.newReadMAC();
- } catch (GeneralSecurityException e) {
- // "can't happen"
- throw (SSLException)new SSLException
- ("Algorithm missing: ").initCause(e);
- }
-
- /*
- * Dispose of any intermediate state in the underlying cipher.
- * For PKCS11 ciphers, this will release any attached sessions,
- * and thus make finalization faster.
- *
- * Since MAC's doFinal() is called for every SSL/TLS packet, it's
- * not necessary to do the same with MAC's.
- */
- oldCipher.dispose();
- }
-
- /*
- * used by Handshaker to change the active write cipher, follows
- * the output of the CCS message.
- *
- * Also synchronized on "this" from readRecord/delegatedTask.
- */
- void changeWriteCiphers() throws SSLException {
- if (connectionState != cs_HANDSHAKE
- && connectionState != cs_RENEGOTIATE) {
- throw new SSLProtocolException(
- "State error, change cipher specs");
- }
-
- // ... create compressor
-
- CipherBox oldCipher = writeCipher;
-
- try {
- writeCipher = handshaker.newWriteCipher();
- writeMAC = handshaker.newWriteMAC();
- } catch (GeneralSecurityException e) {
- // "can't happen"
- throw (SSLException)new SSLException
- ("Algorithm missing: ").initCause(e);
- }
-
- // See comment above.
- oldCipher.dispose();
-
- // reset the flag of the first application record
- isFirstAppOutputRecord = true;
- }
-
- /*
- * Updates the SSL version associated with this connection.
- * Called from Handshaker once it has determined the negotiated version.
- */
- synchronized void setVersion(ProtocolVersion protocolVersion) {
- this.protocolVersion = protocolVersion;
- outputRecord.setVersion(protocolVersion);
- }
-
-
- /**
- * Kickstart the handshake if it is not already in progress.
- * This means:
- *
- * . if handshaking is already underway, do nothing and return
- *
- * . if the engine is not connected or already closed, throw an
- * Exception.
- *
- * . otherwise, call initHandshake() to initialize the handshaker
- * object and progress the state. Then, send the initial
- * handshaking message if appropriate (always on clients and
- * on servers when renegotiating).
- */
- private synchronized void kickstartHandshake() throws IOException {
- switch (connectionState) {
-
- case cs_START:
- if (!serverModeSet) {
- throw new IllegalStateException(
- "Client/Server mode not yet set.");
- }
- initHandshaker();
- break;
-
- case cs_HANDSHAKE:
- // handshaker already setup, proceed
- break;
-
- case cs_DATA:
- if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) {
- throw new SSLHandshakeException(
- "Insecure renegotiation is not allowed");
- }
-
- if (!secureRenegotiation) {
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "Warning: Using insecure renegotiation");
- }
- }
-
- // initialize the handshaker, move to cs_RENEGOTIATE
- initHandshaker();
- break;
-
- case cs_RENEGOTIATE:
- // handshaking already in progress, return
- return;
-
- default:
- // cs_ERROR/cs_CLOSED
- throw new SSLException("SSLEngine is closing/closed");
- }
-
- //
- // Kickstart handshake state machine if we need to ...
- //
- // Note that handshaker.kickstart() writes the message
- // to its HandshakeOutStream, which calls back into
- // SSLSocketImpl.writeRecord() to send it.
- //
- if (!handshaker.activated()) {
- // prior to handshaking, activate the handshake
- if (connectionState == cs_RENEGOTIATE) {
- // don't use SSLv2Hello when renegotiating
- handshaker.activate(protocolVersion);
- } else {
- handshaker.activate(null);
- }
-
- if (handshaker instanceof ClientHandshaker) {
- // send client hello
- handshaker.kickstart();
- } else { // instanceof ServerHandshaker
- if (connectionState == cs_HANDSHAKE) {
- // initial handshake, no kickstart message to send
- } else {
- // we want to renegotiate, send hello request
- handshaker.kickstart();
-
- // hello request is not included in the handshake
- // hashes, reset them
- handshaker.handshakeHash.reset();
- }
- }
- }
- }
-
- /*
- * Start a SSLEngine handshake
- */
- public void beginHandshake() throws SSLException {
- try {
- kickstartHandshake();
- } catch (Exception e) {
- fatal(Alerts.alert_handshake_failure,
- "Couldn't kickstart handshaking", e);
- }
- }
-
-
- //
- // Read/unwrap side
- //
-
-
- /**
- * Unwraps a buffer. Does a variety of checks before grabbing
- * the unwrapLock, which blocks multiple unwraps from occuring.
- */
- public SSLEngineResult unwrap(ByteBuffer netData, ByteBuffer [] appData,
- int offset, int length) throws SSLException {
-
- EngineArgs ea = new EngineArgs(netData, appData, offset, length);
-
- try {
- synchronized (unwrapLock) {
- return readNetRecord(ea);
- }
- } catch (Exception e) {
- /*
- * Don't reset position so it looks like we didn't
- * consume anything. We did consume something, and it
- * got us into this situation, so report that much back.
- * Our days of consuming are now over anyway.
- */
- fatal(Alerts.alert_internal_error,
- "problem unwrapping net record", e);
- return null; // make compiler happy
- } finally {
- /*
- * Just in case something failed to reset limits properly.
- */
- ea.resetLim();
- }
- }
-
- /*
- * Makes additional checks for unwrap, but this time more
- * specific to this packet and the current state of the machine.
- */
- private SSLEngineResult readNetRecord(EngineArgs ea) throws IOException {
-
- Status status = null;
- HandshakeStatus hsStatus = null;
-
- /*
- * See if the handshaker needs to report back some SSLException.
- */
- checkTaskThrown();
-
- /*
- * Check if we are closing/closed.
- */
- if (isInboundDone()) {
- return new SSLEngineResult(Status.CLOSED, getHSStatus(null), 0, 0);
- }
-
- /*
- * If we're still in cs_HANDSHAKE, make sure it's been
- * started.
- */
- synchronized (this) {
- if ((connectionState == cs_HANDSHAKE) ||
- (connectionState == cs_START)) {
- kickstartHandshake();
-
- /*
- * If there's still outbound data to flush, we
- * can return without trying to unwrap anything.
- */
- hsStatus = getHSStatus(null);
-
- if (hsStatus == HandshakeStatus.NEED_WRAP) {
- return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
- }
- }
- }
-
- /*
- * Grab a copy of this if it doesn't already exist,
- * and we can use it several places before anything major
- * happens on this side. Races aren't critical
- * here.
- */
- if (hsStatus == null) {
- hsStatus = getHSStatus(null);
- }
-
- /*
- * If we have a task outstanding, this *MUST* be done before
- * doing any more unwrapping, because we could be in the middle
- * of receiving a handshake message, for example, a finished
- * message which would change the ciphers.
- */
- if (hsStatus == HandshakeStatus.NEED_TASK) {
- return new SSLEngineResult(
- Status.OK, hsStatus, 0, 0);
- }
-
- /*
- * Check the packet to make sure enough is here.
- * This will also indirectly check for 0 len packets.
- */
- int packetLen = inputRecord.bytesInCompletePacket(ea.netData);
-
- // Is this packet bigger than SSL/TLS normally allows?
- if (packetLen > sess.getPacketBufferSize()) {
- if (packetLen > Record.maxLargeRecordSize) {
- throw new SSLProtocolException(
- "Input SSL/TLS record too big: max = " +
- Record.maxLargeRecordSize +
- " len = " + packetLen);
- } else {
- // Expand the expected maximum packet/application buffer
- // sizes.
- sess.expandBufferSizes();
- }
- }
-
- /*
- * Check for OVERFLOW.
- *
- * To be considered: We could delay enforcing the application buffer
- * free space requirement until after the initial handshaking.
- */
- if ((packetLen - Record.headerSize) > ea.getAppRemaining()) {
- return new SSLEngineResult(Status.BUFFER_OVERFLOW, hsStatus, 0, 0);
- }
-
- // check for UNDERFLOW.
- if ((packetLen == -1) || (ea.netData.remaining() < packetLen)) {
- return new SSLEngineResult(
- Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
- }
-
- /*
- * We're now ready to actually do the read.
- * The only result code we really need to be exactly
- * right is the HS finished, for signaling to
- * HandshakeCompletedListeners.
- */
- try {
- hsStatus = readRecord(ea);
- } catch (SSLException e) {
- throw e;
- } catch (IOException e) {
- SSLException ex = new SSLException("readRecord");
- ex.initCause(e);
- throw ex;
- }
-
- /*
- * Check the various condition that we could be reporting.
- *
- * It's *possible* something might have happened between the
- * above and now, but it was better to minimally lock "this"
- * during the read process. We'll return the current
- * status, which is more representative of the current state.
- *
- * status above should cover: FINISHED, NEED_TASK
- */
- status = (isInboundDone() ? Status.CLOSED : Status.OK);
- hsStatus = getHSStatus(hsStatus);
-
- return new SSLEngineResult(status, hsStatus,
- ea.deltaNet(), ea.deltaApp());
- }
-
- /*
- * Actually do the read record processing.
- *
- * Returns a Status if it can make specific determinations
- * of the engine state. In particular, we need to signal
- * that a handshake just completed.
- *
- * It would be nice to be symmetrical with the write side and move
- * the majority of this to EngineInputRecord, but there's too much
- * SSLEngine state to do that cleanly. It must still live here.
- */
- private HandshakeStatus readRecord(EngineArgs ea) throws IOException {
-
- HandshakeStatus hsStatus = null;
-
- /*
- * The various operations will return new sliced BB's,
- * this will avoid having to worry about positions and
- * limits in the netBB.
- */
- ByteBuffer readBB = null;
- ByteBuffer decryptedBB = null;
-
- if (getConnectionState() != cs_ERROR) {
-
- /*
- * Read a record ... maybe emitting an alert if we get a
- * comprehensible but unsupported "hello" message during
- * format checking (e.g. V2).
- */
- try {
- readBB = inputRecord.read(ea.netData);
- } catch (IOException e) {
- fatal(Alerts.alert_unexpected_message, e);
- }
-
- /*
- * The basic SSLv3 record protection involves (optional)
- * encryption for privacy, and an integrity check ensuring
- * data origin authentication. We do them both here, and
- * throw a fatal alert if the integrity check fails.
- */
- try {
- decryptedBB = inputRecord.decrypt(readMAC, readCipher, readBB);
- } catch (BadPaddingException e) {
- byte alertType = (inputRecord.contentType() ==
- Record.ct_handshake) ?
- Alerts.alert_handshake_failure :
- Alerts.alert_bad_record_mac;
- fatal(alertType, e.getMessage(), e);
- }
-
-
- // if (!inputRecord.decompress(c))
- // fatal(Alerts.alert_decompression_failure,
- // "decompression failure");
-
-
- /*
- * Process the record.
- */
-
- synchronized (this) {
- switch (inputRecord.contentType()) {
- case Record.ct_handshake:
- /*
- * Handshake messages always go to a pending session
- * handshaker ... if there isn't one, create one. This
- * must work asynchronously, for renegotiation.
- *
- * NOTE that handshaking will either resume a session
- * which was in the cache (and which might have other
- * connections in it already), or else will start a new
- * session (new keys exchanged) with just this connection
- * in it.
- */
- initHandshaker();
- if (!handshaker.activated()) {
- // prior to handshaking, activate the handshake
- if (connectionState == cs_RENEGOTIATE) {
- // don't use SSLv2Hello when renegotiating
- handshaker.activate(protocolVersion);
- } else {
- handshaker.activate(null);
- }
- }
-
- /*
- * process the handshake record ... may contain just
- * a partial handshake message or multiple messages.
- *
- * The handshaker state machine will ensure that it's
- * a finished message.
- */
- handshaker.process_record(inputRecord, expectingFinished);
- expectingFinished = false;
-
- if (handshaker.invalidated) {
- handshaker = null;
- // if state is cs_RENEGOTIATE, revert it to cs_DATA
- if (connectionState == cs_RENEGOTIATE) {
- connectionState = cs_DATA;
- }
- } else if (handshaker.isDone()) {
- // reset the parameters for secure renegotiation.
- secureRenegotiation =
- handshaker.isSecureRenegotiation();
- clientVerifyData = handshaker.getClientVerifyData();
- serverVerifyData = handshaker.getServerVerifyData();
-
- sess = handshaker.getSession();
- handshakeSession = null;
- if (!writer.hasOutboundData()) {
- hsStatus = HandshakeStatus.FINISHED;
- }
- handshaker = null;
- connectionState = cs_DATA;
-
- // No handshakeListeners here. That's a
- // SSLSocket thing.
- } else if (handshaker.taskOutstanding()) {
- hsStatus = HandshakeStatus.NEED_TASK;
- }
- break;
-
- case Record.ct_application_data:
- // Pass this right back up to the application.
- if ((connectionState != cs_DATA)
- && (connectionState != cs_RENEGOTIATE)
- && (connectionState != cs_CLOSED)) {
- throw new SSLProtocolException(
- "Data received in non-data state: " +
- connectionState);
- }
-
- if (expectingFinished) {
- throw new SSLProtocolException
- ("Expecting finished message, received data");
- }
-
- /*
- * Don't return data once the inbound side is
- * closed.
- */
- if (!inboundDone) {
- ea.scatter(decryptedBB.slice());
- }
- break;
-
- case Record.ct_alert:
- recvAlert();
- break;
-
- case Record.ct_change_cipher_spec:
- if ((connectionState != cs_HANDSHAKE
- && connectionState != cs_RENEGOTIATE)
- || inputRecord.available() != 1
- || inputRecord.read() != 1) {
- fatal(Alerts.alert_unexpected_message,
- "illegal change cipher spec msg, state = "
- + connectionState);
- }
-
- //
- // The first message after a change_cipher_spec
- // record MUST be a "Finished" handshake record,
- // else it's a protocol violation. We force this
- // to be checked by a minor tweak to the state
- // machine.
- //
- changeReadCiphers();
- // next message MUST be a finished message
- expectingFinished = true;
- break;
-
- default:
- //
- // TLS requires that unrecognized records be ignored.
- //
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", Received record type: "
- + inputRecord.contentType());
- }
- break;
- } // switch
-
- /*
- * We only need to check the sequence number state for
- * non-handshaking record.
- *
- * Note that in order to maintain the handshake status
- * properly, we check the sequence number after the last
- * record reading process. As we request renegotiation
- * or close the connection for wrapped sequence number
- * when there is enough sequence number space left to
- * handle a few more records, so the sequence number
- * of the last record cannot be wrapped.
- */
- if (connectionState < cs_ERROR && !isInboundDone() &&
- (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
- if (checkSequenceNumber(readMAC,
- inputRecord.contentType())) {
- hsStatus = getHSStatus(null);
- }
- }
- } // synchronized (this)
- }
-
- return hsStatus;
- }
-
-
- //
- // write/wrap side
- //
-
-
- /**
- * Wraps a buffer. Does a variety of checks before grabbing
- * the wrapLock, which blocks multiple wraps from occuring.
- */
- public SSLEngineResult wrap(ByteBuffer [] appData,
- int offset, int length, ByteBuffer netData) throws SSLException {
-
- EngineArgs ea = new EngineArgs(appData, offset, length, netData);
-
- /*
- * We can be smarter about using smaller buffer sizes later.
- * For now, force it to be large enough to handle any
- * valid SSL/TLS record.
- */
- if (netData.remaining() < outputRecord.maxRecordSize) {
- return new SSLEngineResult(
- Status.BUFFER_OVERFLOW, getHSStatus(null), 0, 0);
- }
-
- try {
- synchronized (wrapLock) {
- return writeAppRecord(ea);
- }
- } catch (Exception e) {
- ea.resetPos();
-
- fatal(Alerts.alert_internal_error,
- "problem wrapping app data", e);
- return null; // make compiler happy
- } finally {
- /*
- * Just in case something didn't reset limits properly.
- */
- ea.resetLim();
- }
- }
-
- /*
- * Makes additional checks for unwrap, but this time more
- * specific to this packet and the current state of the machine.
- */
- private SSLEngineResult writeAppRecord(EngineArgs ea) throws IOException {
-
- Status status = null;
- HandshakeStatus hsStatus = null;
-
- /*
- * See if the handshaker needs to report back some SSLException.
- */
- checkTaskThrown();
-
- /*
- * short circuit if we're closed/closing.
- */
- if (writer.isOutboundDone()) {
- return new SSLEngineResult(Status.CLOSED, getHSStatus(null), 0, 0);
- }
-
- /*
- * If we're still in cs_HANDSHAKE, make sure it's been
- * started.
- */
- synchronized (this) {
- if ((connectionState == cs_HANDSHAKE) ||
- (connectionState == cs_START)) {
- kickstartHandshake();
-
- /*
- * If there's no HS data available to write, we can return
- * without trying to wrap anything.
- */
- hsStatus = getHSStatus(null);
-
- if (hsStatus == HandshakeStatus.NEED_UNWRAP) {
- return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
- }
- }
- }
-
- /*
- * Grab a copy of this if it doesn't already exist,
- * and we can use it several places before anything major
- * happens on this side. Races aren't critical
- * here.
- */
- if (hsStatus == null) {
- hsStatus = getHSStatus(null);
- }
-
- /*
- * If we have a task outstanding, this *MUST* be done before
- * doing any more wrapping, because we could be in the middle
- * of receiving a handshake message, for example, a finished
- * message which would change the ciphers.
- */
- if (hsStatus == HandshakeStatus.NEED_TASK) {
- return new SSLEngineResult(
- Status.OK, hsStatus, 0, 0);
- }
-
- /*
- * This will obtain any waiting outbound data, or will
- * process the outbound appData.
- */
- try {
- synchronized (writeLock) {
- hsStatus = writeRecord(outputRecord, ea);
- }
- } catch (SSLException e) {
- throw e;
- } catch (IOException e) {
- SSLException ex = new SSLException("Write problems");
- ex.initCause(e);
- throw ex;
- }
-
- /*
- * writeRecord might have reported some status.
- * Now check for the remaining cases.
- *
- * status above should cover: NEED_WRAP/FINISHED
- */
- status = (isOutboundDone() ? Status.CLOSED : Status.OK);
- hsStatus = getHSStatus(hsStatus);
-
- return new SSLEngineResult(status, hsStatus,
- ea.deltaApp(), ea.deltaNet());
- }
-
- /*
- * Central point to write/get all of the outgoing data.
- */
- private HandshakeStatus writeRecord(EngineOutputRecord eor,
- EngineArgs ea) throws IOException {
-
- // eventually compress as well.
- HandshakeStatus hsStatus =
- writer.writeRecord(eor, ea, writeMAC, writeCipher);
-
- /*
- * We only need to check the sequence number state for
- * non-handshaking record.
- *
- * Note that in order to maintain the handshake status
- * properly, we check the sequence number after the last
- * record writing process. As we request renegotiation
- * or close the connection for wrapped sequence number
- * when there is enough sequence number space left to
- * handle a few more records, so the sequence number
- * of the last record cannot be wrapped.
- */
- if (connectionState < cs_ERROR && !isOutboundDone() &&
- (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
- if (checkSequenceNumber(writeMAC, eor.contentType())) {
- hsStatus = getHSStatus(null);
- }
- }
-
- /*
- * turn off the flag of the first application record if we really
- * consumed at least byte.
- */
- if (isFirstAppOutputRecord && ea.deltaApp() > 0) {
- isFirstAppOutputRecord = false;
- }
-
- return hsStatus;
- }
-
- /*
- * Need to split the payload except the following cases:
- *
- * 1. protocol version is TLS 1.1 or later;
- * 2. bulk cipher does not use CBC mode, including null bulk cipher suites.
- * 3. the payload is the first application record of a freshly
- * negotiated TLS session.
- * 4. the CBC protection is disabled;
- *
- * More details, please refer to
- * EngineOutputRecord.write(EngineArgs, MAC, CipherBox).
- */
- boolean needToSplitPayload(CipherBox cipher, ProtocolVersion protocol) {
- return (protocol.v <= ProtocolVersion.TLS10.v) &&
- cipher.isCBCMode() && !isFirstAppOutputRecord &&
- Record.enableCBCProtection;
- }
-
- /*
- * Non-application OutputRecords go through here.
- */
- void writeRecord(EngineOutputRecord eor) throws IOException {
- // eventually compress as well.
- writer.writeRecord(eor, writeMAC, writeCipher);
-
- /*
- * Check the sequence number state
- *
- * Note that in order to maintain the connection I/O
- * properly, we check the sequence number after the last
- * record writing process. As we request renegotiation
- * or close the connection for wrapped sequence number
- * when there is enough sequence number space left to
- * handle a few more records, so the sequence number
- * of the last record cannot be wrapped.
- */
- if ((connectionState < cs_ERROR) && !isOutboundDone()) {
- checkSequenceNumber(writeMAC, eor.contentType());
- }
- }
-
- //
- // Close code
- //
-
- /**
- * Check the sequence number state
- *
- * RFC 4346 states that, "Sequence numbers are of type uint64 and
- * may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS
- * implementation would need to wrap a sequence number, it must
- * renegotiate instead."
- *
- * Return true if the handshake status may be changed.
- */
- private boolean checkSequenceNumber(MAC mac, byte type)
- throws IOException {
-
- /*
- * Don't bother to check the sequence number for error or
- * closed connections, or NULL MAC
- */
- if (connectionState >= cs_ERROR || mac == MAC.NULL) {
- return false;
- }
-
- /*
- * Conservatively, close the connection immediately when the
- * sequence number is close to overflow
- */
- if (mac.seqNumOverflow()) {
- /*
- * TLS protocols do not define a error alert for sequence
- * number overflow. We use handshake_failure error alert
- * for handshaking and bad_record_mac for other records.
- */
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", sequence number extremely close to overflow " +
- "(2^64-1 packets). Closing connection.");
- }
-
- fatal(Alerts.alert_handshake_failure, "sequence number overflow");
-
- return true; // make the compiler happy
- }
-
- /*
- * Ask for renegotiation when need to renew sequence number.
- *
- * Don't bother to kickstart the renegotiation when the local is
- * asking for it.
- */
- if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", request renegotiation " +
- "to avoid sequence number overflow");
- }
-
- beginHandshake();
- return true;
- }
-
- return false;
- }
-
- /**
- * Signals that no more outbound application data will be sent
- * on this <code>SSLEngine</code>.
- */
- private void closeOutboundInternal() {
-
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", closeOutboundInternal()");
- }
-
- /*
- * Already closed, ignore
- */
- if (writer.isOutboundDone()) {
- return;
- }
-
- switch (connectionState) {
-
- /*
- * If we haven't even started yet, don't bother reading inbound.
- */
- case cs_START:
- writer.closeOutbound();
- inboundDone = true;
- break;
-
- case cs_ERROR:
- case cs_CLOSED:
- break;
-
- /*
- * Otherwise we indicate clean termination.
- */
- // case cs_HANDSHAKE:
- // case cs_DATA:
- // case cs_RENEGOTIATE:
- default:
- warning(Alerts.alert_close_notify);
- writer.closeOutbound();
- break;
- }
-
- // See comment in changeReadCiphers()
- writeCipher.dispose();
-
- connectionState = cs_CLOSED;
- }
-
- synchronized public void closeOutbound() {
- /*
- * Dump out a close_notify to the remote side
- */
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called closeOutbound()");
- }
-
- closeOutboundInternal();
- }
-
- /**
- * Returns the outbound application data closure state
- */
- public boolean isOutboundDone() {
- return writer.isOutboundDone();
- }
-
- /**
- * Signals that no more inbound network data will be sent
- * to this <code>SSLEngine</code>.
- */
- private void closeInboundInternal() {
-
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", closeInboundInternal()");
- }
-
- /*
- * Already closed, ignore
- */
- if (inboundDone) {
- return;
- }
-
- closeOutboundInternal();
- inboundDone = true;
-
- // See comment in changeReadCiphers()
- readCipher.dispose();
-
- connectionState = cs_CLOSED;
- }
-
- /*
- * Close the inbound side of the connection. We grab the
- * lock here, and do the real work in the internal verison.
- * We do check for truncation attacks.
- */
- synchronized public void closeInbound() throws SSLException {
- /*
- * Currently closes the outbound side as well. The IETF TLS
- * working group has expressed the opinion that 1/2 open
- * connections are not allowed by the spec. May change
- * someday in the future.
- */
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called closeInbound()");
- }
-
- /*
- * No need to throw an Exception if we haven't even started yet.
- */
- if ((connectionState != cs_START) && !recvCN) {
- recvCN = true; // Only receive the Exception once
- fatal(Alerts.alert_internal_error,
- "Inbound closed before receiving peer's close_notify: " +
- "possible truncation attack?");
- } else {
- /*
- * Currently, this is a no-op, but in case we change
- * the close inbound code later.
- */
- closeInboundInternal();
- }
- }
-
- /**
- * Returns the network inbound data closure state
- */
- synchronized public boolean isInboundDone() {
- return inboundDone;
- }
-
-
- //
- // Misc stuff
- //
-
-
- /**
- * Returns the current <code>SSLSession</code> for this
- * <code>SSLEngine</code>
- * <P>
- * These can be long lived, and frequently correspond to an
- * entire login session for some user.
- */
- synchronized public SSLSession getSession() {
- return sess;
- }
-
- @Override
- synchronized public SSLSession getHandshakeSession() {
- return handshakeSession;
- }
-
- synchronized void setHandshakeSession(SSLSessionImpl session) {
- handshakeSession = session;
- }
-
- /**
- * Returns a delegated <code>Runnable</code> task for
- * this <code>SSLEngine</code>.
- */
- synchronized public Runnable getDelegatedTask() {
- if (handshaker != null) {
- return handshaker.getTask();
- }
- return null;
- }
-
-
- //
- // EXCEPTION AND ALERT HANDLING
- //
-
- /*
- * Send a warning alert.
- */
- void warning(byte description) {
- sendAlert(Alerts.alert_warning, description);
- }
-
- synchronized void fatal(byte description, String diagnostic)
- throws SSLException {
- fatal(description, diagnostic, null);
- }
-
- synchronized void fatal(byte description, Throwable cause)
- throws SSLException {
- fatal(description, null, cause);
- }
-
- /*
- * We've got a fatal error here, so start the shutdown process.
- *
- * Because of the way the code was written, we have some code
- * calling fatal directly when the "description" is known
- * and some throwing Exceptions which are then caught by higher
- * levels which then call here. This code needs to determine
- * if one of the lower levels has already started the process.
- *
- * We won't worry about Error's, if we have one of those,
- * we're in worse trouble. Note: the networking code doesn't
- * deal with Errors either.
- */
- synchronized void fatal(byte description, String diagnostic,
- Throwable cause) throws SSLException {
-
- /*
- * If we have no further information, make a general-purpose
- * message for folks to see. We generally have one or the other.
- */
- if (diagnostic == null) {
- diagnostic = "General SSLEngine problem";
- }
- if (cause == null) {
- cause = Alerts.getSSLException(description, cause, diagnostic);
- }
-
- /*
- * If we've already shutdown because of an error,
- * there is nothing we can do except rethrow the exception.
- *
- * Most exceptions seen here will be SSLExceptions.
- * We may find the occasional Exception which hasn't been
- * converted to a SSLException, so we'll do it here.
- */
- if (closeReason != null) {
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", fatal: engine already closed. Rethrowing " +
- cause.toString());
- }
- if (cause instanceof RuntimeException) {
- throw (RuntimeException)cause;
- } else if (cause instanceof SSLException) {
- throw (SSLException)cause;
- } else if (cause instanceof Exception) {
- SSLException ssle = new SSLException(
- "fatal SSLEngine condition");
- ssle.initCause(cause);
- throw ssle;
- }
- }
-
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName()
- + ", fatal error: " + description +
- ": " + diagnostic + "\n" + cause.toString());
- }
-
- /*
- * Ok, this engine's going down.
- */
- int oldState = connectionState;
- connectionState = cs_ERROR;
-
- inboundDone = true;
-
- sess.invalidate();
- if (handshakeSession != null) {
- handshakeSession.invalidate();
- }
-
- /*
- * If we haven't even started handshaking yet, no need
- * to generate the fatal close alert.
- */
- if (oldState != cs_START) {
- sendAlert(Alerts.alert_fatal, description);
- }
-
- if (cause instanceof SSLException) { // only true if != null
- closeReason = (SSLException)cause;
- } else {
- /*
- * Including RuntimeExceptions, but we'll throw those
- * down below. The closeReason isn't used again,
- * except for null checks.
- */
- closeReason =
- Alerts.getSSLException(description, cause, diagnostic);
- }
-
- writer.closeOutbound();
-
- connectionState = cs_CLOSED;
-
- // See comment in changeReadCiphers()
- readCipher.dispose();
- writeCipher.dispose();
-
- if (cause instanceof RuntimeException) {
- throw (RuntimeException)cause;
- } else {
- throw closeReason;
- }
- }
-
- /*
- * Process an incoming alert ... caller must already have synchronized
- * access to "this".
- */
- private void recvAlert() throws IOException {
- byte level = (byte)inputRecord.read();
- byte description = (byte)inputRecord.read();
- if (description == -1) { // check for short message
- fatal(Alerts.alert_illegal_parameter, "Short alert message");
- }
-
- if (debug != null && (Debug.isOn("record") ||
- Debug.isOn("handshake"))) {
- synchronized (System.out) {
- System.out.print(threadName());
- System.out.print(", RECV " + protocolVersion + " ALERT: ");
- if (level == Alerts.alert_fatal) {
- System.out.print("fatal, ");
- } else if (level == Alerts.alert_warning) {
- System.out.print("warning, ");
- } else {
- System.out.print("<level " + (0x0ff & level) + ">, ");
- }
- System.out.println(Alerts.alertDescription(description));
- }
- }
-
- if (level == Alerts.alert_warning) {
- if (description == Alerts.alert_close_notify) {
- if (connectionState == cs_HANDSHAKE) {
- fatal(Alerts.alert_unexpected_message,
- "Received close_notify during handshake");
- } else {
- recvCN = true;
- closeInboundInternal(); // reply to close
- }
- } else {
-
- //
- // The other legal warnings relate to certificates,
- // e.g. no_certificate, bad_certificate, etc; these
- // are important to the handshaking code, which can
- // also handle illegal protocol alerts if needed.
- //
- if (handshaker != null) {
- handshaker.handshakeAlert(description);
- }
- }
- } else { // fatal or unknown level
- String reason = "Received fatal alert: "
- + Alerts.alertDescription(description);
- if (closeReason == null) {
- closeReason = Alerts.getSSLException(description, reason);
- }
- fatal(Alerts.alert_unexpected_message, reason);
- }
- }
-
-
- /*
- * Emit alerts. Caller must have synchronized with "this".
- */
- private void sendAlert(byte level, byte description) {
- // the connectionState cannot be cs_START
- if (connectionState >= cs_CLOSED) {
- return;
- }
-
- // For initial handshaking, don't send alert message to peer if
- // handshaker has not started.
- if (connectionState == cs_HANDSHAKE &&
- (handshaker == null || !handshaker.started())) {
- return;
- }
-
- EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this);
- r.setVersion(protocolVersion);
-
- boolean useDebug = debug != null && Debug.isOn("ssl");
- if (useDebug) {
- synchronized (System.out) {
- System.out.print(threadName());
- System.out.print(", SEND " + protocolVersion + " ALERT: ");
- if (level == Alerts.alert_fatal) {
- System.out.print("fatal, ");
- } else if (level == Alerts.alert_warning) {
- System.out.print("warning, ");
- } else {
- System.out.print("<level = " + (0x0ff & level) + ">, ");
- }
- System.out.println("description = "
- + Alerts.alertDescription(description));
- }
- }
-
- r.write(level);
- r.write(description);
- try {
- writeRecord(r);
- } catch (IOException e) {
- if (useDebug) {
- System.out.println(threadName() +
- ", Exception sending alert: " + e);
- }
- }
- }
-
-
- //
- // VARIOUS OTHER METHODS (COMMON TO SSLSocket)
- //
-
-
- /**
- * Controls whether new connections may cause creation of new SSL
- * sessions.
- *
- * As long as handshaking has not started, we can change
- * whether we enable session creations. Otherwise,
- * we will need to wait for the next handshake.
- */
- synchronized public void setEnableSessionCreation(boolean flag) {
- enableSessionCreation = flag;
-
- if ((handshaker != null) && !handshaker.activated()) {
- handshaker.setEnableSessionCreation(enableSessionCreation);
- }
- }
-
- /**
- * Returns true if new connections may cause creation of new SSL
- * sessions.
- */
- synchronized public boolean getEnableSessionCreation() {
- return enableSessionCreation;
- }
-
-
- /**
- * Sets the flag controlling whether a server mode engine
- * *REQUIRES* SSL client authentication.
- *
- * As long as handshaking has not started, we can change
- * whether client authentication is needed. Otherwise,
- * we will need to wait for the next handshake.
- */
- synchronized public void setNeedClientAuth(boolean flag) {
- doClientAuth = (flag ?
- SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none);
-
- if ((handshaker != null) &&
- (handshaker instanceof ServerHandshaker) &&
- !handshaker.activated()) {
- ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
- }
- }
-
- synchronized public boolean getNeedClientAuth() {
- return (doClientAuth == SSLEngineImpl.clauth_required);
- }
-
- /**
- * Sets the flag controlling whether a server mode engine
- * *REQUESTS* SSL client authentication.
- *
- * As long as handshaking has not started, we can change
- * whether client authentication is requested. Otherwise,
- * we will need to wait for the next handshake.
- */
- synchronized public void setWantClientAuth(boolean flag) {
- doClientAuth = (flag ?
- SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none);
-
- if ((handshaker != null) &&
- (handshaker instanceof ServerHandshaker) &&
- !handshaker.activated()) {
- ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
- }
- }
-
- synchronized public boolean getWantClientAuth() {
- return (doClientAuth == SSLEngineImpl.clauth_requested);
- }
-
-
- /**
- * Sets the flag controlling whether the engine is in SSL
- * client or server mode. Must be called before any SSL
- * traffic has started.
- */
- synchronized public void setUseClientMode(boolean flag) {
- switch (connectionState) {
-
- case cs_START:
- /*
- * If we need to change the engine mode and the enabled
- * protocols haven't specifically been set by the user,
- * change them to the corresponding default ones.
- */
- if (roleIsServer != (!flag) &&
- sslContext.isDefaultProtocolList(enabledProtocols)) {
- enabledProtocols = sslContext.getDefaultProtocolList(!flag);
- }
-
- roleIsServer = !flag;
- serverModeSet = true;
- break;
-
- case cs_HANDSHAKE:
- /*
- * If we have a handshaker, but haven't started
- * SSL traffic, we can throw away our current
- * handshaker, and start from scratch. Don't
- * need to call doneConnect() again, we already
- * have the streams.
- */
- assert(handshaker != null);
- if (!handshaker.activated()) {
- /*
- * If we need to change the engine mode and the enabled
- * protocols haven't specifically been set by the user,
- * change them to the corresponding default ones.
- */
- if (roleIsServer != (!flag) &&
- sslContext.isDefaultProtocolList(enabledProtocols)) {
- enabledProtocols = sslContext.getDefaultProtocolList(!flag);
- }
-
- roleIsServer = !flag;
- connectionState = cs_START;
- initHandshaker();
- break;
- }
-
- // If handshake has started, that's an error. Fall through...
-
- default:
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", setUseClientMode() invoked in state = " +
- connectionState);
- }
-
- /*
- * We can let them continue if they catch this correctly,
- * we don't need to shut this down.
- */
- throw new IllegalArgumentException(
- "Cannot change mode after SSL traffic has started");
- }
- }
-
- synchronized public boolean getUseClientMode() {
- return !roleIsServer;
- }
-
-
- /**
- * Returns the names of the cipher suites which could be enabled for use
- * on an SSL connection. Normally, only a subset of these will actually
- * be enabled by default, since this list may include cipher suites which
- * do not support the mutual authentication of servers and clients, or
- * which do not protect data confidentiality. Servers may also need
- * certain kinds of certificates to use certain cipher suites.
- *
- * @return an array of cipher suite names
- */
- public String[] getSupportedCipherSuites() {
- return sslContext.getSupportedCipherSuiteList().toStringArray();
- }
-
- /**
- * Controls which particular cipher suites are enabled for use on
- * this connection. The cipher suites must have been listed by
- * getCipherSuites() as being supported. Even if a suite has been
- * enabled, it might never be used if no peer supports it or the
- * requisite certificates (and private keys) are not available.
- *
- * @param suites Names of all the cipher suites to enable.
- */
- synchronized public void setEnabledCipherSuites(String[] suites) {
- enabledCipherSuites = new CipherSuiteList(suites);
- if ((handshaker != null) && !handshaker.activated()) {
- handshaker.setEnabledCipherSuites(enabledCipherSuites);
- }
- }
-
- /**
- * Returns the names of the SSL cipher suites which are currently enabled
- * for use on this connection. When an SSL engine is first created,
- * all enabled cipher suites <em>(a)</em> protect data confidentiality,
- * by traffic encryption, and <em>(b)</em> can mutually authenticate
- * both clients and servers. Thus, in some environments, this value
- * might be empty.
- *
- * @return an array of cipher suite names
- */
- synchronized public String[] getEnabledCipherSuites() {
- return enabledCipherSuites.toStringArray();
- }
-
-
- /**
- * Returns the protocols that are supported by this implementation.
- * A subset of the supported protocols may be enabled for this connection
- * @return an array of protocol names.
- */
- public String[] getSupportedProtocols() {
- return sslContext.getSuportedProtocolList().toStringArray();
- }
-
- /**
- * Controls which protocols are enabled for use on
- * this connection. The protocols must have been listed by
- * getSupportedProtocols() as being supported.
- *
- * @param protocols protocols to enable.
- * @exception IllegalArgumentException when one of the protocols
- * named by the parameter is not supported.
- */
- synchronized public void setEnabledProtocols(String[] protocols) {
- enabledProtocols = new ProtocolList(protocols);
- if ((handshaker != null) && !handshaker.activated()) {
- handshaker.setEnabledProtocols(enabledProtocols);
- }
- }
-
- synchronized public String[] getEnabledProtocols() {
- return enabledProtocols.toStringArray();
- }
-
- /**
- * Returns the SSLParameters in effect for this SSLEngine.
- */
- synchronized public SSLParameters getSSLParameters() {
- SSLParameters params = super.getSSLParameters();
-
- // the super implementation does not handle the following parameters
- params.setEndpointIdentificationAlgorithm(identificationProtocol);
- params.setAlgorithmConstraints(algorithmConstraints);
-
- return params;
- }
-
- /**
- * Applies SSLParameters to this engine.
- */
- synchronized public void setSSLParameters(SSLParameters params) {
- super.setSSLParameters(params);
-
- // the super implementation does not handle the following parameters
- identificationProtocol = params.getEndpointIdentificationAlgorithm();
- algorithmConstraints = params.getAlgorithmConstraints();
- if ((handshaker != null) && !handshaker.started()) {
- handshaker.setIdentificationProtocol(identificationProtocol);
- handshaker.setAlgorithmConstraints(algorithmConstraints);
- }
- }
-
- /**
- * Return the name of the current thread. Utility method.
- */
- private static String threadName() {
- return Thread.currentThread().getName();
- }
-
- /**
- * Returns a printable representation of this end of the connection.
- */
- public String toString() {
- StringBuilder retval = new StringBuilder(80);
-
- retval.append(Integer.toHexString(hashCode()));
- retval.append("[");
- retval.append("SSLEngine[hostname=");
- String host = getPeerHost();
- retval.append((host == null) ? "null" : host);
- retval.append(" port=");
- retval.append(Integer.toString(getPeerPort()));
- retval.append("] ");
- retval.append(getSession().getCipherSuite());
- retval.append("]");
-
- return retval.toString();
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLServerSocketFactoryImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLServerSocketFactoryImpl.java
deleted file mode 100755
index 2b99129..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLServerSocketFactoryImpl.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.ServerSocket;
-
-import javax.net.ssl.SSLServerSocketFactory;
-
-/**
- * This class creates SSL server sockets.
- *
- * @author David Brownell
- */
-final
-public class SSLServerSocketFactoryImpl extends SSLServerSocketFactory
-{
- private static final int DEFAULT_BACKLOG = 50;
- private SSLContextImpl context;
-
-
- /**
- * Constructor used to instantiate the default factory. This method is
- * only called if the old "ssl.ServerSocketFactory.provider" property in the
- * java.security file is set.
- */
- public SSLServerSocketFactoryImpl() throws Exception {
- this.context = SSLContextImpl.DefaultSSLContext.getDefaultImpl();
- }
-
- /**
- * Called from SSLContextImpl's getSSLServerSocketFactory().
- */
- SSLServerSocketFactoryImpl (SSLContextImpl context)
- {
- this.context = context;
- }
-
- /**
- * Returns an unbound server socket.
- *
- * @return the unbound socket
- * @throws IOException if the socket cannot be created
- * @see java.net.Socket#bind(java.net.SocketAddress)
- */
- public ServerSocket createServerSocket() throws IOException {
- return new SSLServerSocketImpl(context);
- }
-
- public ServerSocket createServerSocket (int port)
- throws IOException
- {
- return new SSLServerSocketImpl (port, DEFAULT_BACKLOG, context);
- }
-
-
- public ServerSocket createServerSocket (int port, int backlog)
- throws IOException
- {
- return new SSLServerSocketImpl (port, backlog, context);
- }
-
- public ServerSocket
- createServerSocket (int port, int backlog, InetAddress ifAddress)
- throws IOException
- {
- return new SSLServerSocketImpl (port, backlog, ifAddress, context);
- }
-
- /**
- * Returns the subset of the supported cipher suites which are
- * enabled by default. These cipher suites all provide a minimum
- * quality of service whereby the server authenticates itself
- * (preventing person-in-the-middle attacks) and where traffic
- * is encrypted to provide confidentiality.
- */
- public String[] getDefaultCipherSuites() {
- return context.getDefaultCipherSuiteList(true).toStringArray();
- }
-
- /**
- * Returns the names of the cipher suites which could be enabled for use
- * on an SSL connection. Normally, only a subset of these will actually
- * be enabled by default, since this list may include cipher suites which
- * do not support the mutual authentication of servers and clients, or
- * which do not protect data confidentiality. Servers may also need
- * certain kinds of certificates to use certain cipher suites.
- *
- * @return an array of cipher suite names
- */
- public String[] getSupportedCipherSuites() {
- return context.getSupportedCipherSuiteList().toStringArray();
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLServerSocketImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLServerSocketImpl.java
deleted file mode 100755
index c2098c1..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLServerSocketImpl.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.ServerSocket;
-
-import java.security.AlgorithmConstraints;
-
-import java.util.*;
-
-import javax.net.ServerSocketFactory;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLParameters;
-
-
-/**
- * This class provides a simple way for servers to support conventional
- * use of the Secure Sockets Layer (SSL). Application code uses an
- * SSLServerSocketImpl exactly like it uses a regular TCP ServerSocket; the
- * difference is that the connections established are secured using SSL.
- *
- * <P> Also, the constructors take an explicit authentication context
- * parameter, giving flexibility with respect to how the server socket
- * authenticates itself. That policy flexibility is not exposed through
- * the standard SSLServerSocketFactory API.
- *
- * <P> System security defaults prevent server sockets from accepting
- * connections if they the authentication context has not been given
- * a certificate chain and its matching private key. If the clients
- * of your application support "anonymous" cipher suites, you may be
- * able to configure a server socket to accept those suites.
- *
- * @see SSLSocketImpl
- * @see SSLServerSocketFactoryImpl
- *
- * @author David Brownell
- */
-final
-class SSLServerSocketImpl extends SSLServerSocket
-{
- private SSLContextImpl sslContext;
-
- /* Do newly accepted connections require clients to authenticate? */
- private byte doClientAuth = SSLEngineImpl.clauth_none;
-
- /* Do new connections created here use the "server" mode of SSL? */
- private boolean useServerMode = true;
-
- /* Can new connections created establish new sessions? */
- private boolean enableSessionCreation = true;
-
- /* what cipher suites to use by default */
- private CipherSuiteList enabledCipherSuites = null;
-
- /* which protocol to use by default */
- private ProtocolList enabledProtocols = null;
-
- /* could enabledCipherSuites ever complete handshaking? */
- private boolean checkedEnabled = false;
-
- // the endpoint identification protocol to use by default
- private String identificationProtocol = null;
-
- // The cryptographic algorithm constraints
- private AlgorithmConstraints algorithmConstraints = null;
-
- /**
- * Create an SSL server socket on a port, using a non-default
- * authentication context and a specified connection backlog.
- *
- * @param port the port on which to listen
- * @param backlog how many connections may be pending before
- * the system should start rejecting new requests
- * @param context authentication context for this server
- */
- SSLServerSocketImpl(int port, int backlog, SSLContextImpl context)
- throws IOException, SSLException
- {
- super(port, backlog);
- initServer(context);
- }
-
-
- /**
- * Create an SSL server socket on a port, using a specified
- * authentication context and a specified backlog of connections
- * as well as a particular specified network interface. This
- * constructor is used on multihomed hosts, such as those used
- * for firewalls or as routers, to control through which interface
- * a network service is provided.
- *
- * @param port the port on which to listen
- * @param backlog how many connections may be pending before
- * the system should start rejecting new requests
- * @param address the address of the network interface through
- * which connections will be accepted
- * @param context authentication context for this server
- */
- SSLServerSocketImpl(
- int port,
- int backlog,
- InetAddress address,
- SSLContextImpl context)
- throws IOException
- {
- super(port, backlog, address);
- initServer(context);
- }
-
-
- /**
- * Creates an unbound server socket.
- */
- SSLServerSocketImpl(SSLContextImpl context) throws IOException {
- super();
- initServer(context);
- }
-
-
- /**
- * Initializes the server socket.
- */
- private void initServer(SSLContextImpl context) throws SSLException {
- if (context == null) {
- throw new SSLException("No Authentication context given");
- }
- sslContext = context;
- enabledCipherSuites = sslContext.getDefaultCipherSuiteList(true);
- enabledProtocols = sslContext.getDefaultProtocolList(true);
- }
-
- /**
- * Returns the names of the cipher suites which could be enabled for use
- * on an SSL connection. Normally, only a subset of these will actually
- * be enabled by default, since this list may include cipher suites which
- * do not support the mutual authentication of servers and clients, or
- * which do not protect data confidentiality. Servers may also need
- * certain kinds of certificates to use certain cipher suites.
- *
- * @return an array of cipher suite names
- */
- public String[] getSupportedCipherSuites() {
- return sslContext.getSupportedCipherSuiteList().toStringArray();
- }
-
- /**
- * Returns the list of cipher suites which are currently enabled
- * for use by newly accepted connections. A null return indicates
- * that the system defaults are in effect.
- */
- synchronized public String[] getEnabledCipherSuites() {
- return enabledCipherSuites.toStringArray();
- }
-
- /**
- * Controls which particular SSL cipher suites are enabled for use
- * by accepted connections.
- *
- * @param suites Names of all the cipher suites to enable; null
- * means to accept system defaults.
- */
- synchronized public void setEnabledCipherSuites(String[] suites) {
- enabledCipherSuites = new CipherSuiteList(suites);
- checkedEnabled = false;
- }
-
- public String[] getSupportedProtocols() {
- return sslContext.getSuportedProtocolList().toStringArray();
- }
-
- /**
- * Controls which protocols are enabled for use.
- * The protocols must have been listed by
- * getSupportedProtocols() as being supported.
- *
- * @param protocols protocols to enable.
- * @exception IllegalArgumentException when one of the protocols
- * named by the parameter is not supported.
- */
- synchronized public void setEnabledProtocols(String[] protocols) {
- enabledProtocols = new ProtocolList(protocols);
- }
-
- synchronized public String[] getEnabledProtocols() {
- return enabledProtocols.toStringArray();
- }
-
- /**
- * Controls whether the connections which are accepted must include
- * client authentication.
- */
- public void setNeedClientAuth(boolean flag) {
- doClientAuth = (flag ?
- SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none);
- }
-
- public boolean getNeedClientAuth() {
- return (doClientAuth == SSLEngineImpl.clauth_required);
- }
-
- /**
- * Controls whether the connections which are accepted should request
- * client authentication.
- */
- public void setWantClientAuth(boolean flag) {
- doClientAuth = (flag ?
- SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none);
- }
-
- public boolean getWantClientAuth() {
- return (doClientAuth == SSLEngineImpl.clauth_requested);
- }
-
- /**
- * Makes the returned sockets act in SSL "client" mode, not the usual
- * server mode. The canonical example of why this is needed is for
- * FTP clients, which accept connections from servers and should be
- * rejoining the already-negotiated SSL connection.
- */
- public void setUseClientMode(boolean flag) {
- /*
- * If we need to change the socket mode and the enabled
- * protocols haven't specifically been set by the user,
- * change them to the corresponding default ones.
- */
- if (useServerMode != (!flag) &&
- sslContext.isDefaultProtocolList(enabledProtocols)) {
- enabledProtocols = sslContext.getDefaultProtocolList(!flag);
- }
-
- useServerMode = !flag;
- }
-
- public boolean getUseClientMode() {
- return !useServerMode;
- }
-
-
- /**
- * Controls whether new connections may cause creation of new SSL
- * sessions.
- */
- public void setEnableSessionCreation(boolean flag) {
- enableSessionCreation = flag;
- }
-
- /**
- * Returns true if new connections may cause creation of new SSL
- * sessions.
- */
- public boolean getEnableSessionCreation() {
- return enableSessionCreation;
- }
-
- /**
- * Returns the SSLParameters in effect for newly accepted connections.
- */
- synchronized public SSLParameters getSSLParameters() {
- SSLParameters params = super.getSSLParameters();
-
- // the super implementation does not handle the following parameters
- params.setEndpointIdentificationAlgorithm(identificationProtocol);
- params.setAlgorithmConstraints(algorithmConstraints);
-
- return params;
- }
-
- /**
- * Applies SSLParameters to newly accepted connections.
- */
- synchronized public void setSSLParameters(SSLParameters params) {
- super.setSSLParameters(params);
-
- // the super implementation does not handle the following parameters
- identificationProtocol = params.getEndpointIdentificationAlgorithm();
- algorithmConstraints = params.getAlgorithmConstraints();
- }
-
- /**
- * Accept a new SSL connection. This server identifies itself with
- * information provided in the authentication context which was
- * presented during construction.
- */
- public Socket accept() throws IOException {
- SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
- enabledCipherSuites, doClientAuth, enableSessionCreation,
- enabledProtocols, identificationProtocol, algorithmConstraints);
-
- implAccept(s);
- s.doneConnect();
- return s;
- }
-
- /**
- * Provides a brief description of this SSL socket.
- */
- public String toString() {
- return "[SSL: "+ super.toString() + "]";
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
deleted file mode 100755
index 756a48e..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.util.Enumeration;
-import java.util.Vector;
-import java.util.Locale;
-
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-
-import sun.security.util.Cache;
-
-
-final class SSLSessionContextImpl implements SSLSessionContext {
- private Cache<SessionId, SSLSessionImpl> sessionCache;
- // session cache, session id as key
- private Cache<String, SSLSessionImpl> sessionHostPortCache;
- // session cache, "host:port" as key
- private int cacheLimit; // the max cache size
- private int timeout; // timeout in seconds
-
- // package private
- SSLSessionContextImpl() {
- cacheLimit = getDefaultCacheLimit(); // default cache size
- timeout = 86400; // default, 24 hours
-
- // use soft reference
- sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
- sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
- }
-
- /**
- * Returns the <code>SSLSession</code> bound to the specified session id.
- */
- @Override
- public SSLSession getSession(byte[] sessionId) {
- if (sessionId == null) {
- throw new NullPointerException("session id cannot be null");
- }
-
- SSLSessionImpl sess = sessionCache.get(new SessionId(sessionId));
- if (!isTimedout(sess)) {
- return sess;
- }
-
- return null;
- }
-
- /**
- * Returns an enumeration of the active SSL sessions.
- */
- @Override
- public Enumeration<byte[]> getIds() {
- SessionCacheVisitor scVisitor = new SessionCacheVisitor();
- sessionCache.accept(scVisitor);
-
- return scVisitor.getSessionIds();
- }
-
- /**
- * Sets the timeout limit for cached <code>SSLSession</code> objects
- *
- * Note that after reset the timeout, the cached session before
- * should be timed within the shorter one of the old timeout and the
- * new timeout.
- */
- @Override
- public void setSessionTimeout(int seconds)
- throws IllegalArgumentException {
- if (seconds < 0) {
- throw new IllegalArgumentException();
- }
-
- if (timeout != seconds) {
- sessionCache.setTimeout(seconds);
- sessionHostPortCache.setTimeout(seconds);
- timeout = seconds;
- }
- }
-
- /**
- * Gets the timeout limit for cached <code>SSLSession</code> objects
- */
- @Override
- public int getSessionTimeout() {
- return timeout;
- }
-
- /**
- * Sets the size of the cache used for storing
- * <code>SSLSession</code> objects.
- */
- @Override
- public void setSessionCacheSize(int size)
- throws IllegalArgumentException {
- if (size < 0)
- throw new IllegalArgumentException();
-
- if (cacheLimit != size) {
- sessionCache.setCapacity(size);
- sessionHostPortCache.setCapacity(size);
- cacheLimit = size;
- }
- }
-
- /**
- * Gets the size of the cache used for storing
- * <code>SSLSession</code> objects.
- */
- @Override
- public int getSessionCacheSize() {
- return cacheLimit;
- }
-
-
- // package-private method, used ONLY by ServerHandshaker
- SSLSessionImpl get(byte[] id) {
- return (SSLSessionImpl)getSession(id);
- }
-
- // package-private method, used ONLY by ClientHandshaker
- SSLSessionImpl get(String hostname, int port) {
- /*
- * If no session caching info is available, we won't
- * get one, so exit before doing a lookup.
- */
- if (hostname == null && port == -1) {
- return null;
- }
-
- SSLSessionImpl sess = sessionHostPortCache.get(getKey(hostname, port));
- if (!isTimedout(sess)) {
- return sess;
- }
-
- return null;
- }
-
- private String getKey(String hostname, int port) {
- return (hostname + ":" +
- String.valueOf(port)).toLowerCase(Locale.ENGLISH);
- }
-
- // cache a SSLSession
- //
- // In SunJSSE implementation, a session is created while getting a
- // client hello or a server hello message, and cached while the
- // handshaking finished.
- // Here we time the session from the time it cached instead of the
- // time it created, which is a little longer than the expected. So
- // please do check isTimedout() while getting entry from the cache.
- void put(SSLSessionImpl s) {
- sessionCache.put(s.getSessionId(), s);
-
- // If no hostname/port info is available, don't add this one.
- if ((s.getPeerHost() != null) && (s.getPeerPort() != -1)) {
- sessionHostPortCache.put(
- getKey(s.getPeerHost(), s.getPeerPort()), s);
- }
-
- s.setContext(this);
- }
-
- // package-private method, remove a cached SSLSession
- void remove(SessionId key) {
- SSLSessionImpl s = sessionCache.get(key);
- if (s != null) {
- sessionCache.remove(key);
- sessionHostPortCache.remove(
- getKey(s.getPeerHost(), s.getPeerPort()));
- }
- }
-
- private int getDefaultCacheLimit() {
- int cacheLimit = 0;
- try {
- String s = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<String>() {
- @Override
- public String run() {
- return System.getProperty(
- "javax.net.ssl.sessionCacheSize");
- }
- });
- cacheLimit = (s != null) ? Integer.parseInt(s) : 0;
- } catch (Exception e) {
- }
-
- return (cacheLimit > 0) ? cacheLimit : 0;
- }
-
- boolean isTimedout(SSLSession sess) {
- if (timeout == 0) {
- return false;
- }
-
- if ((sess != null) && ((sess.getCreationTime() + timeout * 1000L)
- <= (System.currentTimeMillis()))) {
- sess.invalidate();
- return true;
- }
-
- return false;
- }
-
- final class SessionCacheVisitor
- implements Cache.CacheVisitor<SessionId, SSLSessionImpl> {
- Vector<byte[]> ids = null;
-
- // public void visit(java.util.Map<K,V> map) {}
- @Override
- public void visit(java.util.Map<SessionId, SSLSessionImpl> map) {
- ids = new Vector<>(map.size());
-
- for (SessionId key : map.keySet()) {
- SSLSessionImpl value = map.get(key);
- if (!isTimedout(value)) {
- ids.addElement(key.getId());
- }
- }
- }
-
- public Enumeration<byte[]> getSessionIds() {
- return ids != null ? ids.elements() :
- new Vector<byte[]>().elements();
- }
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLSessionImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLSessionImpl.java
deleted file mode 100755
index 110fc9c..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLSessionImpl.java
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.net.*;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Vector;
-import java.util.Arrays;
-import java.util.Collection;
-
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
-import java.security.cert.CertificateEncodingException;
-
-import javax.crypto.SecretKey;
-
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.SSLSessionBindingListener;
-import javax.net.ssl.SSLSessionBindingEvent;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLPermission;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.ExtendedSSLSession;
-
-import javax.security.auth.x500.X500Principal;
-
-import static sun.security.ssl.CipherSuite.*;
-import static sun.security.ssl.CipherSuite.KeyExchange.*;
-
-/**
- * Implements the SSL session interface, and exposes the session context
- * which is maintained by SSL servers.
- *
- * <P> Servers have the ability to manage the sessions associated with
- * their authentication context(s). They can do this by enumerating the
- * IDs of the sessions which are cached, examining those sessions, and then
- * perhaps invalidating a given session so that it can't be used again.
- * If servers do not explicitly manage the cache, sessions will linger
- * until memory is low enough that the runtime environment purges cache
- * entries automatically to reclaim space.
- *
- * <P><em> The only reason this class is not package-private is that
- * there's no other public way to get at the server session context which
- * is associated with any given authentication context. </em>
- *
- * @author David Brownell
- */
-final class SSLSessionImpl extends ExtendedSSLSession {
-
- /*
- * we only really need a single null session
- */
- static final SSLSessionImpl nullSession = new SSLSessionImpl();
-
- // compression methods
- private static final byte compression_null = 0;
-
- /*
- * The state of a single session, as described in section 7.1
- * of the SSLv3 spec.
- */
- private final ProtocolVersion protocolVersion;
- private final SessionId sessionId;
- private X509Certificate[] peerCerts;
- private byte compressionMethod;
- private CipherSuite cipherSuite;
- private SecretKey masterSecret;
-
- /*
- * Information not part of the SSLv3 protocol spec, but used
- * to support session management policies.
- */
- private final long creationTime = System.currentTimeMillis();
- private long lastUsedTime = 0;
- private final String host;
- private final int port;
- private SSLSessionContextImpl context;
- private int sessionCount;
- private boolean invalidated;
- private X509Certificate[] localCerts;
- private PrivateKey localPrivateKey;
- private String[] localSupportedSignAlgs;
- private String[] peerSupportedSignAlgs;
-
- // Principals for non-certificate based cipher suites
- private Principal peerPrincipal;
- private Principal localPrincipal;
-
- /*
- * We count session creations, eventually for statistical data but
- * also since counters make shorter debugging IDs than the big ones
- * we use in the protocol for uniqueness-over-time.
- */
- private static volatile int counter = 0;
-
- /*
- * Use of session caches is globally enabled/disabled.
- */
- private static boolean defaultRejoinable = true;
-
- /* Class and subclass dynamic debugging support */
- private static final Debug debug = Debug.getInstance("ssl");
-
- /*
- * Create a new non-rejoinable session, using the default (null)
- * cipher spec. This constructor returns a session which could
- * be used either by a client or by a server, as a connection is
- * first opened and before handshaking begins.
- */
- private SSLSessionImpl() {
- this(ProtocolVersion.NONE, CipherSuite.C_NULL, null,
- new SessionId(false, null), null, -1);
- }
-
- /*
- * Create a new session, using a given cipher spec. This will
- * be rejoinable if session caching is enabled; the constructor
- * is intended mostly for use by serves.
- */
- SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
- Collection<SignatureAndHashAlgorithm> algorithms,
- SecureRandom generator, String host, int port) {
- this(protocolVersion, cipherSuite, algorithms,
- new SessionId(defaultRejoinable, generator), host, port);
- }
-
- /*
- * Record a new session, using a given cipher spec and session ID.
- */
- SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
- Collection<SignatureAndHashAlgorithm> algorithms,
- SessionId id, String host, int port) {
- this.protocolVersion = protocolVersion;
- sessionId = id;
- peerCerts = null;
- compressionMethod = compression_null;
- this.cipherSuite = cipherSuite;
- masterSecret = null;
- this.host = host;
- this.port = port;
- sessionCount = ++counter;
- localSupportedSignAlgs =
- SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
-
- if (debug != null && Debug.isOn("session")) {
- System.out.println("%% Initialized: " + this);
- }
- }
-
- void setMasterSecret(SecretKey secret) {
- if (masterSecret == null) {
- masterSecret = secret;
- } else {
- throw new RuntimeException("setMasterSecret() error");
- }
- }
-
- /**
- * Returns the master secret ... treat with extreme caution!
- */
- SecretKey getMasterSecret() {
- return masterSecret;
- }
-
- void setPeerCertificates(X509Certificate[] peer) {
- if (peerCerts == null) {
- peerCerts = peer;
- }
- }
-
- void setLocalCertificates(X509Certificate[] local) {
- localCerts = local;
- }
-
- void setLocalPrivateKey(PrivateKey privateKey) {
- localPrivateKey = privateKey;
- }
-
- void setPeerSupportedSignatureAlgorithms(
- Collection<SignatureAndHashAlgorithm> algorithms) {
- peerSupportedSignAlgs =
- SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
- }
-
- /**
- * Set the peer principal.
- */
- void setPeerPrincipal(Principal principal) {
- if (peerPrincipal == null) {
- peerPrincipal = principal;
- }
- }
-
- /**
- * Set the local principal.
- */
- void setLocalPrincipal(Principal principal) {
- localPrincipal = principal;
- }
-
- /**
- * Returns true iff this session may be resumed ... sessions are
- * usually resumable. Security policies may suggest otherwise,
- * for example sessions that haven't been used for a while (say,
- * a working day) won't be resumable, and sessions might have a
- * maximum lifetime in any case.
- */
- boolean isRejoinable() {
- return sessionId != null && sessionId.length() != 0 &&
- !invalidated && isLocalAuthenticationValid();
- }
-
- public synchronized boolean isValid() {
- return isRejoinable();
- }
-
- /**
- * Check if the authentication used when establishing this session
- * is still valid. Returns true if no authentication was used
- */
- boolean isLocalAuthenticationValid() {
- if (localPrivateKey != null) {
- try {
- // if the private key is no longer valid, getAlgorithm()
- // should throw an exception
- // (e.g. Smartcard has been removed from the reader)
- localPrivateKey.getAlgorithm();
- } catch (Exception e) {
- invalidate();
- return false;
- }
- }
- return true;
- }
-
- /**
- * Returns the ID for this session. The ID is fixed for the
- * duration of the session; neither it, nor its value, changes.
- */
- public byte[] getId() {
- return sessionId.getId();
- }
-
- /**
- * For server sessions, this returns the set of sessions which
- * are currently valid in this process. For client sessions,
- * this returns null.
- */
- public SSLSessionContext getSessionContext() {
- /*
- * An interim security policy until we can do something
- * more specific in 1.2. Only allow trusted code (code which
- * can set system properties) to get an
- * SSLSessionContext. This is to limit the ability of code to
- * look up specific sessions or enumerate over them. Otherwise,
- * code can only get session objects from successful SSL
- * connections which implies that they must have had permission
- * to make the network connection in the first place.
- */
- SecurityManager sm;
- if ((sm = System.getSecurityManager()) != null) {
- sm.checkPermission(new SSLPermission("getSSLSessionContext"));
- }
-
- return context;
- }
-
-
- SessionId getSessionId() {
- return sessionId;
- }
-
-
- /**
- * Returns the cipher spec in use on this session
- */
- CipherSuite getSuite() {
- return cipherSuite;
- }
-
- /**
- * Resets the cipher spec in use on this session
- */
- void setSuite(CipherSuite suite) {
- cipherSuite = suite;
-
- if (debug != null && Debug.isOn("session")) {
- System.out.println("%% Negotiating: " + this);
- }
- }
-
- /**
- * Returns the name of the cipher suite in use on this session
- */
- public String getCipherSuite() {
- return getSuite().name;
- }
-
- ProtocolVersion getProtocolVersion() {
- return protocolVersion;
- }
-
- /**
- * Returns the standard name of the protocol in use on this session
- */
- public String getProtocol() {
- return getProtocolVersion().name;
- }
-
- /**
- * Returns the compression technique used in this session
- */
- byte getCompression() {
- return compressionMethod;
- }
-
- /**
- * Returns the hashcode for this session
- */
- public int hashCode() {
- return sessionId.hashCode();
- }
-
-
- /**
- * Returns true if sessions have same ids, false otherwise.
- */
- public boolean equals(Object obj) {
-
- if (obj == this) {
- return true;
- }
-
- if (obj instanceof SSLSessionImpl) {
- SSLSessionImpl sess = (SSLSessionImpl) obj;
- return (sessionId != null) && (sessionId.equals(
- sess.getSessionId()));
- }
-
- return false;
- }
-
-
- /**
- * Return the cert chain presented by the peer in the
- * java.security.cert format.
- * Note: This method can be used only when using certificate-based
- * cipher suites; using it with non-certificate-based cipher suites,
- * such as Kerberos, will throw an SSLPeerUnverifiedException.
- *
- * @return array of peer X.509 certs, with the peer's own cert
- * first in the chain, and with the "root" CA last.
- */
- public java.security.cert.Certificate[] getPeerCertificates()
- throws SSLPeerUnverifiedException {
- //
- // clone to preserve integrity of session ... caller can't
- // change record of peer identity even by accident, much
- // less do it intentionally.
- //
- if ((cipherSuite.keyExchange == K_KRB5) ||
- (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
- throw new SSLPeerUnverifiedException("no certificates expected"
- + " for Kerberos cipher suites");
- }
- if (peerCerts == null) {
- throw new SSLPeerUnverifiedException("peer not authenticated");
- }
- // Certs are immutable objects, therefore we don't clone them.
- // But do need to clone the array, so that nothing is inserted
- // into peerCerts.
- return (java.security.cert.Certificate[])peerCerts.clone();
- }
-
- /**
- * Return the cert chain presented to the peer in the
- * java.security.cert format.
- * Note: This method is useful only when using certificate-based
- * cipher suites.
- *
- * @return array of peer X.509 certs, with the peer's own cert
- * first in the chain, and with the "root" CA last.
- */
- public java.security.cert.Certificate[] getLocalCertificates() {
- //
- // clone to preserve integrity of session ... caller can't
- // change record of peer identity even by accident, much
- // less do it intentionally.
- return (localCerts == null ? null :
- (java.security.cert.Certificate[])localCerts.clone());
- }
-
- /**
- * Return the cert chain presented by the peer in the
- * javax.security.cert format.
- * Note: This method can be used only when using certificate-based
- * cipher suites; using it with non-certificate-based cipher suites,
- * such as Kerberos, will throw an SSLPeerUnverifiedException.
- *
- * @return array of peer X.509 certs, with the peer's own cert
- * first in the chain, and with the "root" CA last.
- */
- public javax.security.cert.X509Certificate[] getPeerCertificateChain()
- throws SSLPeerUnverifiedException {
- //
- // clone to preserve integrity of session ... caller can't
- // change record of peer identity even by accident, much
- // less do it intentionally.
- //
- if ((cipherSuite.keyExchange == K_KRB5) ||
- (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
- throw new SSLPeerUnverifiedException("no certificates expected"
- + " for Kerberos cipher suites");
- }
- if (peerCerts == null) {
- throw new SSLPeerUnverifiedException("peer not authenticated");
- }
- javax.security.cert.X509Certificate[] certs;
- certs = new javax.security.cert.X509Certificate[peerCerts.length];
- for (int i = 0; i < peerCerts.length; i++) {
- byte[] der = null;
- try {
- der = peerCerts[i].getEncoded();
- certs[i] = javax.security.cert.X509Certificate.getInstance(der);
- } catch (CertificateEncodingException e) {
- throw new SSLPeerUnverifiedException(e.getMessage());
- } catch (javax.security.cert.CertificateException e) {
- throw new SSLPeerUnverifiedException(e.getMessage());
- }
- }
-
- return certs;
- }
-
- /**
- * Return the cert chain presented by the peer.
- * Note: This method can be used only when using certificate-based
- * cipher suites; using it with non-certificate-based cipher suites,
- * such as Kerberos, will throw an SSLPeerUnverifiedException.
- *
- * @return array of peer X.509 certs, with the peer's own cert
- * first in the chain, and with the "root" CA last.
- */
- public X509Certificate[] getCertificateChain()
- throws SSLPeerUnverifiedException {
- /*
- * clone to preserve integrity of session ... caller can't
- * change record of peer identity even by accident, much
- * less do it intentionally.
- */
- if ((cipherSuite.keyExchange == K_KRB5) ||
- (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
- throw new SSLPeerUnverifiedException("no certificates expected"
- + " for Kerberos cipher suites");
- }
- if (peerCerts != null) {
- return peerCerts.clone();
- } else {
- throw new SSLPeerUnverifiedException("peer not authenticated");
- }
- }
-
- /**
- * Returns the identity of the peer which was established as part of
- * defining the session.
- *
- * @return the peer's principal. Returns an X500Principal of the
- * end-entity certificate for X509-based cipher suites, and
- * Principal for Kerberos cipher suites.
- *
- * @throws SSLPeerUnverifiedException if the peer's identity has not
- * been verified
- */
- public Principal getPeerPrincipal()
- throws SSLPeerUnverifiedException
- {
- if ((cipherSuite.keyExchange == K_KRB5) ||
- (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
- if (peerPrincipal == null) {
- throw new SSLPeerUnverifiedException("peer not authenticated");
- } else {
- // Eliminate dependency on KerberosPrincipal
- return peerPrincipal;
- }
- }
- if (peerCerts == null) {
- throw new SSLPeerUnverifiedException("peer not authenticated");
- }
- return peerCerts[0].getSubjectX500Principal();
- }
-
- /**
- * Returns the principal that was sent to the peer during handshaking.
- *
- * @return the principal sent to the peer. Returns an X500Principal
- * of the end-entity certificate for X509-based cipher suites, and
- * Principal for Kerberos cipher suites. If no principal was
- * sent, then null is returned.
- */
- public Principal getLocalPrincipal() {
-
- if ((cipherSuite.keyExchange == K_KRB5) ||
- (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
- // Eliminate dependency on KerberosPrincipal
- return (localPrincipal == null ? null : localPrincipal);
- }
- return (localCerts == null ? null :
- localCerts[0].getSubjectX500Principal());
- }
-
- /**
- * Returns the time this session was created.
- */
- public long getCreationTime() {
- return creationTime;
- }
-
- /**
- * Returns the last time this session was used to initialize
- * a connection.
- */
- public long getLastAccessedTime() {
- return (lastUsedTime != 0) ? lastUsedTime : creationTime;
- }
-
- void setLastAccessedTime(long time) {
- lastUsedTime = time;
- }
-
-
- /**
- * Returns the network address of the session's peer. This
- * implementation does not insist that connections between
- * different ports on the same host must necessarily belong
- * to different sessions, though that is of course allowed.
- */
- public InetAddress getPeerAddress() {
- try {
- return InetAddress.getByName(host);
- } catch (java.net.UnknownHostException e) {
- return null;
- }
- }
-
- public String getPeerHost() {
- return host;
- }
-
- /**
- * Need to provide the port info for caching sessions based on
- * host and port. Accessed by SSLSessionContextImpl
- */
- public int getPeerPort() {
- return port;
- }
-
- void setContext(SSLSessionContextImpl ctx) {
- if (context == null) {
- context = ctx;
- }
- }
-
- /**
- * Invalidate a session. Active connections may still exist, but
- * no connections will be able to rejoin this session.
- */
- synchronized public void invalidate() {
- //
- // Can't invalidate the NULL session -- this would be
- // attempted when we get a handshaking error on a brand
- // new connection, with no "real" session yet.
- //
- if (this == nullSession) {
- return;
- }
- invalidated = true;
- if (debug != null && Debug.isOn("session")) {
- System.out.println("%% Invalidated: " + this);
- }
- if (context != null) {
- context.remove(sessionId);
- context = null;
- }
- }
-
- /*
- * Table of application-specific session data indexed by an application
- * key and the calling security context. This is important since
- * sessions can be shared across different protection domains.
- */
- private Hashtable<SecureKey, Object> table = new Hashtable<>();
-
- /**
- * Assigns a session value. Session change events are given if
- * appropriate, to any original value as well as the new value.
- */
- public void putValue(String key, Object value) {
- if ((key == null) || (value == null)) {
- throw new IllegalArgumentException("arguments can not be null");
- }
-
- SecureKey secureKey = new SecureKey(key);
- Object oldValue = table.put(secureKey, value);
-
- if (oldValue instanceof SSLSessionBindingListener) {
- SSLSessionBindingEvent e;
-
- e = new SSLSessionBindingEvent(this, key);
- ((SSLSessionBindingListener)oldValue).valueUnbound(e);
- }
- if (value instanceof SSLSessionBindingListener) {
- SSLSessionBindingEvent e;
-
- e = new SSLSessionBindingEvent(this, key);
- ((SSLSessionBindingListener)value).valueBound(e);
- }
- }
-
-
- /**
- * Returns the specified session value.
- */
- public Object getValue(String key) {
- if (key == null) {
- throw new IllegalArgumentException("argument can not be null");
- }
-
- SecureKey secureKey = new SecureKey(key);
- return table.get(secureKey);
- }
-
-
- /**
- * Removes the specified session value, delivering a session changed
- * event as appropriate.
- */
- public void removeValue(String key) {
- if (key == null) {
- throw new IllegalArgumentException("argument can not be null");
- }
-
- SecureKey secureKey = new SecureKey(key);
- Object value = table.remove(secureKey);
-
- if (value instanceof SSLSessionBindingListener) {
- SSLSessionBindingEvent e;
-
- e = new SSLSessionBindingEvent(this, key);
- ((SSLSessionBindingListener)value).valueUnbound(e);
- }
- }
-
-
- /**
- * Lists the names of the session values.
- */
- public String[] getValueNames() {
- Enumeration<SecureKey> e;
- Vector<Object> v = new Vector<>();
- SecureKey key;
- Object securityCtx = SecureKey.getCurrentSecurityContext();
-
- for (e = table.keys(); e.hasMoreElements(); ) {
- key = e.nextElement();
-
- if (securityCtx.equals(key.getSecurityContext())) {
- v.addElement(key.getAppKey());
- }
- }
- String[] names = new String[v.size()];
- v.copyInto(names);
-
- return names;
- }
-
- /**
- * Use large packet sizes now or follow RFC 2246 packet sizes (2^14)
- * until changed.
- *
- * In the TLS specification (section 6.2.1, RFC2246), it is not
- * recommended that the plaintext has more than 2^14 bytes.
- * However, some TLS implementations violate the specification.
- * This is a workaround for interoperability with these stacks.
- *
- * Application could accept large fragments up to 2^15 bytes by
- * setting the system property jsse.SSLEngine.acceptLargeFragments
- * to "true".
- */
- private boolean acceptLargeFragments =
- Debug.getBooleanProperty("jsse.SSLEngine.acceptLargeFragments", false);
-
- /**
- * Expand the buffer size of both SSL/TLS network packet and
- * application data.
- */
- protected synchronized void expandBufferSizes() {
- acceptLargeFragments = true;
- }
-
- /**
- * Gets the current size of the largest SSL/TLS packet that is expected
- * when using this session.
- */
- public synchronized int getPacketBufferSize() {
- return acceptLargeFragments ?
- Record.maxLargeRecordSize : Record.maxRecordSize;
- }
-
- /**
- * Gets the current size of the largest application data that is
- * expected when using this session.
- */
- public synchronized int getApplicationBufferSize() {
- return getPacketBufferSize() - Record.headerSize;
- }
-
- /**
- * Gets an array of supported signature algorithms that the local side is
- * willing to verify.
- */
- public String[] getLocalSupportedSignatureAlgorithms() {
- if (localSupportedSignAlgs != null) {
- return localSupportedSignAlgs.clone();
- }
-
- return new String[0];
- }
-
- /**
- * Gets an array of supported signature algorithms that the peer is
- * able to verify.
- */
- public String[] getPeerSupportedSignatureAlgorithms() {
- if (peerSupportedSignAlgs != null) {
- return peerSupportedSignAlgs.clone();
- }
-
- return new String[0];
- }
-
- /** Returns a string representation of this SSL session */
- public String toString() {
- return "[Session-" + sessionCount
- + ", " + getCipherSuite()
- + "]";
- }
-
- /**
- * When SSL sessions are finalized, all values bound to
- * them are removed.
- */
- public void finalize() {
- String[] names = getValueNames();
- for (int i = 0; i < names.length; i++) {
- removeValue(names[i]);
- }
- }
-}
-
-
-/**
- * This "struct" class serves as a Hash Key that combines an
- * application-specific key and a security context.
- */
-class SecureKey {
- private static Object nullObject = new Object();
- private Object appKey;
- private Object securityCtx;
-
- static Object getCurrentSecurityContext() {
- SecurityManager sm = System.getSecurityManager();
- Object context = null;
-
- if (sm != null)
- context = sm.getSecurityContext();
- if (context == null)
- context = nullObject;
- return context;
- }
-
- SecureKey(Object key) {
- this.appKey = key;
- this.securityCtx = getCurrentSecurityContext();
- }
-
- Object getAppKey() {
- return appKey;
- }
-
- Object getSecurityContext() {
- return securityCtx;
- }
-
- public int hashCode() {
- return appKey.hashCode() ^ securityCtx.hashCode();
- }
-
- public boolean equals(Object o) {
- return o instanceof SecureKey && ((SecureKey)o).appKey.equals(appKey)
- && ((SecureKey)o).securityCtx.equals(securityCtx);
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLSocketFactoryImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLSocketFactoryImpl.java
deleted file mode 100755
index 135b462..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLSocketFactoryImpl.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.net.*;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.SSLSocket;
-
-
-/**
- * Implementation of an SSL socket factory. This provides the public
- * hooks to create SSL sockets, using a "high level" programming
- * interface which encapsulates system security policy defaults rather than
- * offering application flexibility. In particular, it uses a configurable
- * authentication context (and the keys held there) rather than offering
- * any flexibility about which keys to use; that context defaults to the
- * process-default context, but may be explicitly specified.
- *
- * @author David Brownell
- */
-final public class SSLSocketFactoryImpl extends SSLSocketFactory {
-
- private static SSLContextImpl defaultContext;
- private SSLContextImpl context;
-
- /**
- * Constructor used to instantiate the default factory. This method is
- * only called if the old "ssl.SocketFactory.provider" property in the
- * java.security file is set.
- */
- public SSLSocketFactoryImpl() throws Exception {
- this.context = SSLContextImpl.DefaultSSLContext.getDefaultImpl();
- }
-
- /**
- * Constructs an SSL socket factory.
- */
- SSLSocketFactoryImpl(SSLContextImpl context) {
- this.context = context;
- }
-
- /**
- * Creates an unconnected socket.
- *
- * @return the unconnected socket
- * @see java.net.Socket#connect(java.net.SocketAddress, int)
- */
- public Socket createSocket() {
- return new SSLSocketImpl(context);
- }
-
- /**
- * Constructs an SSL connection to a named host at a specified port.
- * This acts as the SSL client, and may authenticate itself or rejoin
- * existing SSL sessions allowed by the authentication context which
- * has been configured.
- *
- * @param host name of the host with which to connect
- * @param port number of the server's port
- */
- public Socket createSocket(String host, int port)
- throws IOException, UnknownHostException
- {
- return new SSLSocketImpl(context, host, port);
- }
-
- /**
- * Returns a socket layered over an existing socket to a
- * ServerSocket on the named host, at the given port. This
- * constructor can be used when tunneling SSL through a proxy. The
- * host and port refer to the logical destination server. This
- * socket is configured using the socket options established for
- * this factory.
- *
- * @param s the existing socket
- * @param host the server host
- * @param port the server port
- * @param autoClose close the underlying socket when this socket is closed
- *
- * @exception IOException if the connection can't be established
- * @exception UnknownHostException if the host is not known
- */
- public Socket createSocket(Socket s, String host, int port,
- boolean autoClose) throws IOException {
- return new SSLSocketImpl(context, s, host, port, autoClose);
- }
-
-
- /**
- * Constructs an SSL connection to a server at a specified address
- * and TCP port. This acts as the SSL client, and may authenticate
- * itself or rejoin existing SSL sessions allowed by the authentication
- * context which has been configured.
- *
- * @param address the server's host
- * @param port its port
- */
- public Socket createSocket(InetAddress address, int port)
- throws IOException
- {
- return new SSLSocketImpl(context, address, port);
- }
-
-
- /**
- * Constructs an SSL connection to a named host at a specified port.
- * This acts as the SSL client, and may authenticate itself or rejoin
- * existing SSL sessions allowed by the authentication context which
- * has been configured. The socket will also bind() to the local
- * address and port supplied.
- */
- public Socket createSocket(String host, int port,
- InetAddress clientAddress, int clientPort)
- throws IOException
- {
- return new SSLSocketImpl(context, host, port,
- clientAddress, clientPort);
- }
-
- /**
- * Constructs an SSL connection to a server at a specified address
- * and TCP port. This acts as the SSL client, and may authenticate
- * itself or rejoin existing SSL sessions allowed by the authentication
- * context which has been configured. The socket will also bind() to
- * the local address and port supplied.
- */
- public Socket createSocket(InetAddress address, int port,
- InetAddress clientAddress, int clientPort)
- throws IOException
- {
- return new SSLSocketImpl(context, address, port,
- clientAddress, clientPort);
- }
-
-
- /**
- * Returns the subset of the supported cipher suites which are
- * enabled by default. These cipher suites all provide a minimum
- * quality of service whereby the server authenticates itself
- * (preventing person-in-the-middle attacks) and where traffic
- * is encrypted to provide confidentiality.
- */
- public String[] getDefaultCipherSuites() {
- return context.getDefaultCipherSuiteList(false).toStringArray();
- }
-
- /**
- * Returns the names of the cipher suites which could be enabled for use
- * on an SSL connection. Normally, only a subset of these will actually
- * be enabled by default, since this list may include cipher suites which
- * do not support the mutual authentication of servers and clients, or
- * which do not protect data confidentiality. Servers may also need
- * certain kinds of certificates to use certain cipher suites.
- */
- public String[] getSupportedCipherSuites() {
- return context.getSupportedCipherSuiteList().toStringArray();
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLSocketImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLSocketImpl.java
deleted file mode 100755
index 37158fb..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SSLSocketImpl.java
+++ /dev/null
@@ -1,2545 +0,0 @@
-/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.net.*;
-import java.security.GeneralSecurityException;
-import java.security.AccessController;
-import java.security.AccessControlContext;
-import java.security.PrivilegedAction;
-import java.security.AlgorithmConstraints;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantLock;
-
-import javax.crypto.BadPaddingException;
-
-import javax.net.ssl.*;
-
-import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
-
-/**
- * Implementation of an SSL socket. This is a normal connection type
- * socket, implementing SSL over some lower level socket, such as TCP.
- * Because it is layered over some lower level socket, it MUST override
- * all default socket methods.
- *
- * <P> This API offers a non-traditional option for establishing SSL
- * connections. You may first establish the connection directly, then pass
- * that connection to the SSL socket constructor with a flag saying which
- * role should be taken in the handshake protocol. (The two ends of the
- * connection must not choose the same role!) This allows setup of SSL
- * proxying or tunneling, and also allows the kind of "role reversal"
- * that is required for most FTP data transfers.
- *
- * @see javax.net.ssl.SSLSocket
- * @see SSLServerSocket
- *
- * @author David Brownell
- */
-final public class SSLSocketImpl extends BaseSSLSocketImpl {
-
- /*
- * ERROR HANDLING GUIDELINES
- * (which exceptions to throw and catch and which not to throw and catch)
- *
- * . if there is an IOException (SocketException) when accessing the
- * underlying Socket, pass it through
- *
- * . do not throw IOExceptions, throw SSLExceptions (or a subclass)
- *
- * . for internal errors (things that indicate a bug in JSSE or a
- * grossly misconfigured J2RE), throw either an SSLException or
- * a RuntimeException at your convenience.
- *
- * . handshaking code (Handshaker or HandshakeMessage) should generally
- * pass through exceptions, but can handle them if they know what to
- * do.
- *
- * . exception chaining should be used for all new code. If you happen
- * to touch old code that does not use chaining, you should change it.
- *
- * . there is a top level exception handler that sits at all entry
- * points from application code to SSLSocket read/write code. It
- * makes sure that all errors are handled (see handleException()).
- *
- * . JSSE internal code should generally not call close(), call
- * closeInternal().
- */
-
- /*
- * There's a state machine associated with each connection, which
- * among other roles serves to negotiate session changes.
- *
- * - START with constructor, until the TCP connection's around.
- * - HANDSHAKE picks session parameters before allowing traffic.
- * There are many substates due to sequencing requirements
- * for handshake messages.
- * - DATA may be transmitted.
- * - RENEGOTIATE state allows concurrent data and handshaking
- * traffic ("same" substates as HANDSHAKE), and terminates
- * in selection of new session (and connection) parameters
- * - ERROR state immediately precedes abortive disconnect.
- * - SENT_CLOSE sent a close_notify to the peer. For layered,
- * non-autoclose socket, must now read close_notify
- * from peer before closing the connection. For nonlayered or
- * non-autoclose socket, close connection and go onto
- * cs_CLOSED state.
- * - CLOSED after sending close_notify alert, & socket is closed.
- * SSL connection objects are not reused.
- * - APP_CLOSED once the application calls close(). Then it behaves like
- * a closed socket, e.g.. getInputStream() throws an Exception.
- *
- * State affects what SSL record types may legally be sent:
- *
- * - Handshake ... only in HANDSHAKE and RENEGOTIATE states
- * - App Data ... only in DATA and RENEGOTIATE states
- * - Alert ... in HANDSHAKE, DATA, RENEGOTIATE
- *
- * Re what may be received: same as what may be sent, except that
- * HandshakeRequest handshaking messages can come from servers even
- * in the application data state, to request entry to RENEGOTIATE.
- *
- * The state machine within HANDSHAKE and RENEGOTIATE states controls
- * the pending session, not the connection state, until the change
- * cipher spec and "Finished" handshake messages are processed and
- * make the "new" session become the current one.
- *
- * NOTE: details of the SMs always need to be nailed down better.
- * The text above illustrates the core ideas.
- *
- * +---->-------+------>--------->-------+
- * | | |
- * <-----< ^ ^ <-----< v
- *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE SENT_CLOSE
- * v v v | |
- * | | | | v
- * +------------+---------------+ v ERROR
- * | | |
- * v | |
- * ERROR>------>----->CLOSED<--------<----+-- +
- * |
- * v
- * APP_CLOSED
- *
- * ALSO, note that the the purpose of handshaking (renegotiation is
- * included) is to assign a different, and perhaps new, session to
- * the connection. The SSLv3 spec is a bit confusing on that new
- * protocol feature.
- */
- private static final int cs_START = 0;
- private static final int cs_HANDSHAKE = 1;
- private static final int cs_DATA = 2;
- private static final int cs_RENEGOTIATE = 3;
- private static final int cs_ERROR = 4;
- private static final int cs_SENT_CLOSE = 5;
- private static final int cs_CLOSED = 6;
- private static final int cs_APP_CLOSED = 7;
-
-
- /*
- * Client authentication be off, requested, or required.
- *
- * Migrated to SSLEngineImpl:
- * clauth_none/cl_auth_requested/clauth_required
- */
-
- /*
- * Drives the protocol state machine.
- */
- private int connectionState;
-
- /*
- * Flag indicating if the next record we receive MUST be a Finished
- * message. Temporarily set during the handshake to ensure that
- * a change cipher spec message is followed by a finished message.
- */
- private boolean expectingFinished;
-
- /*
- * For improved diagnostics, we detail connection closure
- * If the socket is closed (connectionState >= cs_ERROR),
- * closeReason != null indicates if the socket was closed
- * because of an error or because or normal shutdown.
- */
- private SSLException closeReason;
-
- /*
- * Per-connection private state that doesn't change when the
- * session is changed.
- */
- private byte doClientAuth;
- private boolean roleIsServer;
- private boolean enableSessionCreation = true;
- private String host;
- private boolean autoClose = true;
- private AccessControlContext acc;
-
- /*
- * We cannot use the hostname resolved from name services. For
- * virtual hosting, multiple hostnames may be bound to the same IP
- * address, so the hostname resolved from name services is not
- * reliable.
- */
- private String rawHostname;
-
- // The cipher suites enabled for use on this connection.
- private CipherSuiteList enabledCipherSuites;
-
- // The endpoint identification protocol
- private String identificationProtocol = null;
-
- // The cryptographic algorithm constraints
- private AlgorithmConstraints algorithmConstraints = null;
-
- /*
- * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
- * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.
- * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *
- *
- * There are several locks here.
- *
- * The primary lock is the per-instance lock used by
- * synchronized(this) and the synchronized methods. It controls all
- * access to things such as the connection state and variables which
- * affect handshaking. If we are inside a synchronized method, we
- * can access the state directly, otherwise, we must use the
- * synchronized equivalents.
- *
- * The handshakeLock is used to ensure that only one thread performs
- * the *complete initial* handshake. If someone is handshaking, any
- * stray application or startHandshake() requests who find the
- * connection state is cs_HANDSHAKE will stall on handshakeLock
- * until handshaking is done. Once the handshake is done, we either
- * succeeded or failed, but we can never go back to the cs_HANDSHAKE
- * or cs_START state again.
- *
- * Note that the read/write() calls here in SSLSocketImpl are not
- * obviously synchronized. In fact, it's very nonintuitive, and
- * requires careful examination of code paths. Grab some coffee,
- * and be careful with any code changes.
- *
- * There can be only three threads active at a time in the I/O
- * subsection of this class.
- * 1. startHandshake
- * 2. AppInputStream
- * 3. AppOutputStream
- * One thread could call startHandshake().
- * AppInputStream/AppOutputStream read() and write() calls are each
- * synchronized on 'this' in their respective classes, so only one
- * app. thread will be doing a SSLSocketImpl.read() or .write()'s at
- * a time.
- *
- * If handshaking is required (state cs_HANDSHAKE), and
- * getConnectionState() for some/all threads returns cs_HANDSHAKE,
- * only one can grab the handshakeLock, and the rest will stall
- * either on getConnectionState(), or on the handshakeLock if they
- * happen to successfully race through the getConnectionState().
- *
- * If a writer is doing the initial handshaking, it must create a
- * temporary reader to read the responses from the other side. As a
- * side-effect, the writer's reader will have priority over any
- * other reader. However, the writer's reader is not allowed to
- * consume any application data. When handshakeLock is finally
- * released, we either have a cs_DATA connection, or a
- * cs_CLOSED/cs_ERROR socket.
- *
- * The writeLock is held while writing on a socket connection and
- * also to protect the MAC and cipher for their direction. The
- * writeLock is package private for Handshaker which holds it while
- * writing the ChangeCipherSpec message.
- *
- * To avoid the problem of a thread trying to change operational
- * modes on a socket while handshaking is going on, we synchronize
- * on 'this'. If handshaking has not started yet, we tell the
- * handshaker to change its mode. If handshaking has started,
- * we simply store that request until the next pending session
- * is created, at which time the new handshaker's state is set.
- *
- * The readLock is held during readRecord(), which is responsible
- * for reading an InputRecord, decrypting it, and processing it.
- * The readLock ensures that these three steps are done atomically
- * and that once started, no other thread can block on InputRecord.read.
- * This is necessary so that processing of close_notify alerts
- * from the peer are handled properly.
- */
- final private Object handshakeLock = new Object();
- final ReentrantLock writeLock = new ReentrantLock();
- final private Object readLock = new Object();
-
- private InputRecord inrec;
-
- /*
- * Crypto state that's reinitialized when the session changes.
- */
- private MAC readMAC, writeMAC;
- private CipherBox readCipher, writeCipher;
- // NOTE: compression state would be saved here
-
- /*
- * security parameters for secure renegotiation.
- */
- private boolean secureRenegotiation;
- private byte[] clientVerifyData;
- private byte[] serverVerifyData;
-
- /*
- * The authentication context holds all information used to establish
- * who this end of the connection is (certificate chains, private keys,
- * etc) and who is trusted (e.g. as CAs or websites).
- */
- private SSLContextImpl sslContext;
-
-
- /*
- * This connection is one of (potentially) many associated with
- * any given session. The output of the handshake protocol is a
- * new session ... although all the protocol description talks
- * about changing the cipher spec (and it does change), in fact
- * that's incidental since it's done by changing everything that
- * is associated with a session at the same time. (TLS/IETF may
- * change that to add client authentication w/o new key exchg.)
- */
- private Handshaker handshaker;
- private SSLSessionImpl sess;
- private volatile SSLSessionImpl handshakeSession;
-
-
- /*
- * If anyone wants to get notified about handshake completions,
- * they'll show up on this list.
- */
- private HashMap<HandshakeCompletedListener, AccessControlContext>
- handshakeListeners;
-
- /*
- * Reuse the same internal input/output streams.
- */
- private InputStream sockInput;
- private OutputStream sockOutput;
-
-
- /*
- * These input and output streams block their data in SSL records,
- * and usually arrange integrity and privacy protection for those
- * records. The guts of the SSL protocol are wrapped up in these
- * streams, and in the handshaking that establishes the details of
- * that integrity and privacy protection.
- */
- private AppInputStream input;
- private AppOutputStream output;
-
- /*
- * The protocol versions enabled for use on this connection.
- *
- * Note: we support a pseudo protocol called SSLv2Hello which when
- * set will result in an SSL v2 Hello being sent with SSL (version 3.0)
- * or TLS (version 3.1, 3.2, etc.) version info.
- */
- private ProtocolList enabledProtocols;
-
- /*
- * The SSL version associated with this connection.
- */
- private ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT;
-
- /* Class and subclass dynamic debugging support */
- private static final Debug debug = Debug.getInstance("ssl");
-
- /*
- * Is it the first application record to write?
- */
- private boolean isFirstAppOutputRecord = true;
-
- /*
- * If AppOutputStream needs to delay writes of small packets, we
- * will use this to store the data until we actually do the write.
- */
- private ByteArrayOutputStream heldRecordBuffer = null;
-
- //
- // CONSTRUCTORS AND INITIALIZATION CODE
- //
-
- /**
- * Constructs an SSL connection to a named host at a specified port,
- * using the authentication context provided. This endpoint acts as
- * the client, and may rejoin an existing SSL session if appropriate.
- *
- * @param context authentication context to use
- * @param host name of the host with which to connect
- * @param port number of the server's port
- */
- SSLSocketImpl(SSLContextImpl context, String host, int port)
- throws IOException, UnknownHostException {
- super();
- this.host = host;
- this.rawHostname = host;
- init(context, false);
- SocketAddress socketAddress =
- host != null ? new InetSocketAddress(host, port) :
- new InetSocketAddress(InetAddress.getByName(null), port);
- connect(socketAddress, 0);
- }
-
-
- /**
- * Constructs an SSL connection to a server at a specified address.
- * and TCP port, using the authentication context provided. This
- * endpoint acts as the client, and may rejoin an existing SSL session
- * if appropriate.
- *
- * @param context authentication context to use
- * @param address the server's host
- * @param port its port
- */
- SSLSocketImpl(SSLContextImpl context, InetAddress host, int port)
- throws IOException {
- super();
- init(context, false);
- SocketAddress socketAddress = new InetSocketAddress(host, port);
- connect(socketAddress, 0);
- }
-
- /**
- * Constructs an SSL connection to a named host at a specified port,
- * using the authentication context provided. This endpoint acts as
- * the client, and may rejoin an existing SSL session if appropriate.
- *
- * @param context authentication context to use
- * @param host name of the host with which to connect
- * @param port number of the server's port
- * @param localAddr the local address the socket is bound to
- * @param localPort the local port the socket is bound to
- */
- SSLSocketImpl(SSLContextImpl context, String host, int port,
- InetAddress localAddr, int localPort)
- throws IOException, UnknownHostException {
- super();
- this.host = host;
- this.rawHostname = host;
- init(context, false);
- bind(new InetSocketAddress(localAddr, localPort));
- SocketAddress socketAddress =
- host != null ? new InetSocketAddress(host, port) :
- new InetSocketAddress(InetAddress.getByName(null), port);
- connect(socketAddress, 0);
- }
-
-
- /**
- * Constructs an SSL connection to a server at a specified address.
- * and TCP port, using the authentication context provided. This
- * endpoint acts as the client, and may rejoin an existing SSL session
- * if appropriate.
- *
- * @param context authentication context to use
- * @param address the server's host
- * @param port its port
- * @param localAddr the local address the socket is bound to
- * @param localPort the local port the socket is bound to
- */
- SSLSocketImpl(SSLContextImpl context, InetAddress host, int port,
- InetAddress localAddr, int localPort)
- throws IOException {
- super();
- init(context, false);
- bind(new InetSocketAddress(localAddr, localPort));
- SocketAddress socketAddress = new InetSocketAddress(host, port);
- connect(socketAddress, 0);
- }
-
- /*
- * Package-private constructor used ONLY by SSLServerSocket. The
- * java.net package accepts the TCP connection after this call is
- * made. This just initializes handshake state to use "server mode",
- * giving control over the use of SSL client authentication.
- */
- SSLSocketImpl(SSLContextImpl context, boolean serverMode,
- CipherSuiteList suites, byte clientAuth,
- boolean sessionCreation, ProtocolList protocols,
- String identificationProtocol,
- AlgorithmConstraints algorithmConstraints) throws IOException {
-
- super();
- doClientAuth = clientAuth;
- enableSessionCreation = sessionCreation;
- this.identificationProtocol = identificationProtocol;
- this.algorithmConstraints = algorithmConstraints;
- init(context, serverMode);
-
- /*
- * Override what was picked out for us.
- */
- enabledCipherSuites = suites;
- enabledProtocols = protocols;
- }
-
-
- /**
- * Package-private constructor used to instantiate an unconnected
- * socket. The java.net package will connect it, either when the
- * connect() call is made by the application. This instance is
- * meant to set handshake state to use "client mode".
- */
- SSLSocketImpl(SSLContextImpl context) {
- super();
- init(context, false);
- }
-
-
- /**
- * Layer SSL traffic over an existing connection, rather than creating
- * a new connection. The existing connection may be used only for SSL
- * traffic (using this SSLSocket) until the SSLSocket.close() call
- * returns. However, if a protocol error is detected, that existing
- * connection is automatically closed.
- *
- * <P> This particular constructor always uses the socket in the
- * role of an SSL client. It may be useful in cases which start
- * using SSL after some initial data transfers, for example in some
- * SSL tunneling applications or as part of some kinds of application
- * protocols which negotiate use of a SSL based security.
- *
- * @param sock the existing connection
- * @param context the authentication context to use
- */
- SSLSocketImpl(SSLContextImpl context, Socket sock, String host,
- int port, boolean autoClose) throws IOException {
- super(sock);
- // We always layer over a connected socket
- if (!sock.isConnected()) {
- throw new SocketException("Underlying socket is not connected");
- }
- this.host = host;
- this.rawHostname = host;
- init(context, false);
- this.autoClose = autoClose;
- doneConnect();
- }
-
- /**
- * Initializes the client socket.
- */
- private void init(SSLContextImpl context, boolean isServer) {
- sslContext = context;
- sess = SSLSessionImpl.nullSession;
- handshakeSession = null;
-
- /*
- * role is as specified, state is START until after
- * the low level connection's established.
- */
- roleIsServer = isServer;
- connectionState = cs_START;
-
- /*
- * default read and write side cipher and MAC support
- *
- * Note: compression support would go here too
- */
- readCipher = CipherBox.NULL;
- readMAC = MAC.NULL;
- writeCipher = CipherBox.NULL;
- writeMAC = MAC.NULL;
-
- // initial security parameters for secure renegotiation
- secureRenegotiation = false;
- clientVerifyData = new byte[0];
- serverVerifyData = new byte[0];
-
- enabledCipherSuites =
- sslContext.getDefaultCipherSuiteList(roleIsServer);
- enabledProtocols =
- sslContext.getDefaultProtocolList(roleIsServer);
-
- inrec = null;
-
- // save the acc
- acc = AccessController.getContext();
-
- input = new AppInputStream(this);
- output = new AppOutputStream(this);
- }
-
- /**
- * Connects this socket to the server with a specified timeout
- * value.
- *
- * This method is either called on an unconnected SSLSocketImpl by the
- * application, or it is called in the constructor of a regular
- * SSLSocketImpl. If we are layering on top on another socket, then
- * this method should not be called, because we assume that the
- * underlying socket is already connected by the time it is passed to
- * us.
- *
- * @param endpoint the <code>SocketAddress</code>
- * @param timeout the timeout value to be used, 0 is no timeout
- * @throws IOException if an error occurs during the connection
- * @throws SocketTimeoutException if timeout expires before connecting
- */
- public void connect(SocketAddress endpoint, int timeout)
- throws IOException {
-
- if (self != this) {
- throw new SocketException("Already connected");
- }
-
- if (!(endpoint instanceof InetSocketAddress)) {
- throw new SocketException(
- "Cannot handle non-Inet socket addresses.");
- }
-
- super.connect(endpoint, timeout);
- doneConnect();
- }
-
- /**
- * Initialize the handshaker and socket streams.
- *
- * Called by connect, the layered constructor, and SSLServerSocket.
- */
- void doneConnect() throws IOException {
- /*
- * Save the input and output streams. May be done only after
- * java.net actually connects using the socket "self", else
- * we get some pretty bizarre failure modes.
- */
- if (self == this) {
- sockInput = super.getInputStream();
- sockOutput = super.getOutputStream();
- } else {
- sockInput = self.getInputStream();
- sockOutput = self.getOutputStream();
- }
-
- /*
- * Move to handshaking state, with pending session initialized
- * to defaults and the appropriate kind of handshaker set up.
- */
- initHandshaker();
- }
-
- synchronized private int getConnectionState() {
- return connectionState;
- }
-
- synchronized private void setConnectionState(int state) {
- connectionState = state;
- }
-
- AccessControlContext getAcc() {
- return acc;
- }
-
- //
- // READING AND WRITING RECORDS
- //
-
- /*
- * AppOutputStream calls may need to buffer multiple outbound
- * application packets.
- *
- * All other writeRecord() calls will not buffer, so do not hold
- * these records.
- */
- void writeRecord(OutputRecord r) throws IOException {
- writeRecord(r, false);
- }
-
- /*
- * Record Output. Application data can't be sent until the first
- * handshake establishes a session.
- *
- * NOTE: we let empty records be written as a hook to force some
- * TCP-level activity, notably handshaking, to occur.
- */
- void writeRecord(OutputRecord r, boolean holdRecord) throws IOException {
- /*
- * The loop is in case of HANDSHAKE --> ERROR transitions, etc
- */
- loop:
- while (r.contentType() == Record.ct_application_data) {
- /*
- * Not all states support passing application data. We
- * synchronize access to the connection state, so that
- * synchronous handshakes can complete cleanly.
- */
- switch (getConnectionState()) {
-
- /*
- * We've deferred the initial handshaking till just now,
- * when presumably a thread's decided it's OK to block for
- * longish periods of time for I/O purposes (as well as
- * configured the cipher suites it wants to use).
- */
- case cs_HANDSHAKE:
- performInitialHandshake();
- break;
-
- case cs_DATA:
- case cs_RENEGOTIATE:
- break loop;
-
- case cs_ERROR:
- fatal(Alerts.alert_close_notify,
- "error while writing to socket");
- break; // dummy
-
- case cs_SENT_CLOSE:
- case cs_CLOSED:
- case cs_APP_CLOSED:
- // we should never get here (check in AppOutputStream)
- // this is just a fallback
- if (closeReason != null) {
- throw closeReason;
- } else {
- throw new SocketException("Socket closed");
- }
-
- /*
- * Else something's goofy in this state machine's use.
- */
- default:
- throw new SSLProtocolException("State error, send app data");
- }
- }
-
- //
- // Don't bother to really write empty records. We went this
- // far to drive the handshake machinery, for correctness; not
- // writing empty records improves performance by cutting CPU
- // time and network resource usage. However, some protocol
- // implementations are fragile and don't like to see empty
- // records, so this also increases robustness.
- //
- if (!r.isEmpty()) {
-
- // If the record is a close notify alert, we need to honor
- // socket option SO_LINGER. Note that we will try to send
- // the close notify even if the SO_LINGER set to zero.
- if (r.isAlert(Alerts.alert_close_notify) && getSoLinger() >= 0) {
-
- // keep and clear the current thread interruption status.
- boolean interrupted = Thread.interrupted();
- try {
- if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) {
- try {
- writeRecordInternal(r, holdRecord);
- } finally {
- writeLock.unlock();
- }
- } else {
- SSLException ssle = new SSLException(
- "SO_LINGER timeout," +
- " close_notify message cannot be sent.");
-
-
- // For layered, non-autoclose sockets, we are not
- // able to bring them into a usable state, so we
- // treat it as fatal error.
- if (self != this && !autoClose) {
- // Note that the alert description is
- // specified as -1, so no message will be send
- // to peer anymore.
- fatal((byte)(-1), ssle);
- } else if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", received Exception: " + ssle);
- }
-
- // RFC2246 requires that the session becomes
- // unresumable if any connection is terminated
- // without proper close_notify messages with
- // level equal to warning.
- //
- // RFC4346 no longer requires that a session not be
- // resumed if failure to properly close a connection.
- //
- // We choose to make the session unresumable if
- // failed to send the close_notify message.
- //
- sess.invalidate();
- }
- } catch (InterruptedException ie) {
- // keep interrupted status
- interrupted = true;
- }
-
- // restore the interrupted status
- if (interrupted) {
- Thread.currentThread().interrupt();
- }
- } else {
- writeLock.lock();
- try {
- writeRecordInternal(r, holdRecord);
- } finally {
- writeLock.unlock();
- }
- }
- }
- }
-
- private void writeRecordInternal(OutputRecord r,
- boolean holdRecord) throws IOException {
- // r.compress(c);
- r.addMAC(writeMAC);
- r.encrypt(writeCipher);
-
- if (holdRecord) {
- // If we were requested to delay the record due to possibility
- // of Nagle's being active when finally got to writing, and
- // it's actually not, we don't really need to delay it.
- if (getTcpNoDelay()) {
- holdRecord = false;
- } else {
- // We need to hold the record, so let's provide
- // a per-socket place to do it.
- if (heldRecordBuffer == null) {
- // Likely only need 37 bytes.
- heldRecordBuffer = new ByteArrayOutputStream(40);
- }
- }
- }
- r.write(sockOutput, holdRecord, heldRecordBuffer);
-
- /*
- * Check the sequence number state
- *
- * Note that in order to maintain the connection I/O
- * properly, we check the sequence number after the last
- * record writing process. As we request renegotiation
- * or close the connection for wrapped sequence number
- * when there is enough sequence number space left to
- * handle a few more records, so the sequence number
- * of the last record cannot be wrapped.
- */
- if (connectionState < cs_ERROR) {
- checkSequenceNumber(writeMAC, r.contentType());
- }
-
- // turn off the flag of the first application record
- if (isFirstAppOutputRecord &&
- r.contentType() == Record.ct_application_data) {
- isFirstAppOutputRecord = false;
- }
- }
-
- /*
- * Need to split the payload except the following cases:
- *
- * 1. protocol version is TLS 1.1 or later;
- * 2. bulk cipher does not use CBC mode, including null bulk cipher suites.
- * 3. the payload is the first application record of a freshly
- * negotiated TLS session.
- * 4. the CBC protection is disabled;
- *
- * More details, please refer to AppOutputStream.write(byte[], int, int).
- */
- boolean needToSplitPayload() {
- writeLock.lock();
- try {
- return (protocolVersion.v <= ProtocolVersion.TLS10.v) &&
- writeCipher.isCBCMode() && !isFirstAppOutputRecord &&
- Record.enableCBCProtection;
- } finally {
- writeLock.unlock();
- }
- }
-
- /*
- * Read an application data record. Alerts and handshake
- * messages are handled directly.
- */
- void readDataRecord(InputRecord r) throws IOException {
- if (getConnectionState() == cs_HANDSHAKE) {
- performInitialHandshake();
- }
- readRecord(r, true);
- }
-
-
- /*
- * Clear the pipeline of records from the peer, optionally returning
- * application data. Caller is responsible for knowing that it's
- * possible to do this kind of clearing, if they don't want app
- * data -- e.g. since it's the initial SSL handshake.
- *
- * Don't synchronize (this) during a blocking read() since it
- * protects data which is accessed on the write side as well.
- */
- private void readRecord(InputRecord r, boolean needAppData)
- throws IOException {
- int state;
-
- // readLock protects reading and processing of an InputRecord.
- // It keeps the reading from sockInput and processing of the record
- // atomic so that no two threads can be blocked on the
- // read from the same input stream at the same time.
- // This is required for example when a reader thread is
- // blocked on the read and another thread is trying to
- // close the socket. For a non-autoclose, layered socket,
- // the thread performing the close needs to read the close_notify.
- //
- // Use readLock instead of 'this' for locking because
- // 'this' also protects data accessed during writing.
- synchronized (readLock) {
- /*
- * Read and handle records ... return application data
- * ONLY if it's needed.
- */
-
- while (((state = getConnectionState()) != cs_CLOSED) &&
- (state != cs_ERROR) && (state != cs_APP_CLOSED)) {
- /*
- * Read a record ... maybe emitting an alert if we get a
- * comprehensible but unsupported "hello" message during
- * format checking (e.g. V2).
- */
- try {
- r.setAppDataValid(false);
- r.read(sockInput, sockOutput);
- } catch (SSLProtocolException e) {
- try {
- fatal(Alerts.alert_unexpected_message, e);
- } catch (IOException x) {
- // discard this exception
- }
- throw e;
- } catch (EOFException eof) {
- boolean handshaking = (getConnectionState() <= cs_HANDSHAKE);
- boolean rethrow = requireCloseNotify || handshaking;
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", received EOFException: "
- + (rethrow ? "error" : "ignored"));
- }
- if (rethrow) {
- SSLException e;
- if (handshaking) {
- e = new SSLHandshakeException
- ("Remote host closed connection during handshake");
- } else {
- e = new SSLProtocolException
- ("Remote host closed connection incorrectly");
- }
- e.initCause(eof);
- throw e;
- } else {
- // treat as if we had received a close_notify
- closeInternal(false);
- continue;
- }
- }
-
-
- /*
- * The basic SSLv3 record protection involves (optional)
- * encryption for privacy, and an integrity check ensuring
- * data origin authentication. We do them both here, and
- * throw a fatal alert if the integrity check fails.
- */
- try {
- r.decrypt(readMAC, readCipher);
- } catch (BadPaddingException e) {
- byte alertType = (r.contentType() == Record.ct_handshake)
- ? Alerts.alert_handshake_failure
- : Alerts.alert_bad_record_mac;
- fatal(alertType, e.getMessage(), e);
- }
-
- // if (!r.decompress(c))
- // fatal(Alerts.alert_decompression_failure,
- // "decompression failure");
-
- /*
- * Process the record.
- */
- synchronized (this) {
- switch (r.contentType()) {
- case Record.ct_handshake:
- /*
- * Handshake messages always go to a pending session
- * handshaker ... if there isn't one, create one. This
- * must work asynchronously, for renegotiation.
- *
- * NOTE that handshaking will either resume a session
- * which was in the cache (and which might have other
- * connections in it already), or else will start a new
- * session (new keys exchanged) with just this connection
- * in it.
- */
- initHandshaker();
- if (!handshaker.activated()) {
- // prior to handshaking, activate the handshake
- if (connectionState == cs_RENEGOTIATE) {
- // don't use SSLv2Hello when renegotiating
- handshaker.activate(protocolVersion);
- } else {
- handshaker.activate(null);
- }
- }
-
- /*
- * process the handshake record ... may contain just
- * a partial handshake message or multiple messages.
- *
- * The handshaker state machine will ensure that it's
- * a finished message.
- */
- handshaker.process_record(r, expectingFinished);
- expectingFinished = false;
-
- if (handshaker.invalidated) {
- handshaker = null;
- // if state is cs_RENEGOTIATE, revert it to cs_DATA
- if (connectionState == cs_RENEGOTIATE) {
- connectionState = cs_DATA;
- }
- } else if (handshaker.isDone()) {
- // reset the parameters for secure renegotiation.
- secureRenegotiation =
- handshaker.isSecureRenegotiation();
- clientVerifyData = handshaker.getClientVerifyData();
- serverVerifyData = handshaker.getServerVerifyData();
-
- sess = handshaker.getSession();
- handshakeSession = null;
- handshaker = null;
- connectionState = cs_DATA;
-
- //
- // Tell folk about handshake completion, but do
- // it in a separate thread.
- //
- if (handshakeListeners != null) {
- HandshakeCompletedEvent event =
- new HandshakeCompletedEvent(this, sess);
-
- Thread t = new NotifyHandshakeThread(
- handshakeListeners.entrySet(), event);
- t.start();
- }
- }
-
- if (needAppData || connectionState != cs_DATA) {
- continue;
- }
- break;
-
- case Record.ct_application_data:
- // Pass this right back up to the application.
- if (connectionState != cs_DATA
- && connectionState != cs_RENEGOTIATE
- && connectionState != cs_SENT_CLOSE) {
- throw new SSLProtocolException(
- "Data received in non-data state: " +
- connectionState);
- }
- if (expectingFinished) {
- throw new SSLProtocolException
- ("Expecting finished message, received data");
- }
- if (!needAppData) {
- throw new SSLException("Discarding app data");
- }
-
- r.setAppDataValid(true);
- break;
-
- case Record.ct_alert:
- recvAlert(r);
- continue;
-
- case Record.ct_change_cipher_spec:
- if ((connectionState != cs_HANDSHAKE
- && connectionState != cs_RENEGOTIATE)
- || r.available() != 1
- || r.read() != 1) {
- fatal(Alerts.alert_unexpected_message,
- "illegal change cipher spec msg, state = "
- + connectionState);
- }
-
- //
- // The first message after a change_cipher_spec
- // record MUST be a "Finished" handshake record,
- // else it's a protocol violation. We force this
- // to be checked by a minor tweak to the state
- // machine.
- //
- changeReadCiphers();
- // next message MUST be a finished message
- expectingFinished = true;
- continue;
-
- default:
- //
- // TLS requires that unrecognized records be ignored.
- //
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", Received record type: "
- + r.contentType());
- }
- continue;
- } // switch
-
- /*
- * Check the sequence number state
- *
- * Note that in order to maintain the connection I/O
- * properly, we check the sequence number after the last
- * record reading process. As we request renegotiation
- * or close the connection for wrapped sequence number
- * when there is enough sequence number space left to
- * handle a few more records, so the sequence number
- * of the last record cannot be wrapped.
- */
- if (connectionState < cs_ERROR) {
- checkSequenceNumber(readMAC, r.contentType());
- }
-
- return;
- } // synchronized (this)
- }
-
- //
- // couldn't read, due to some kind of error
- //
- r.close();
- return;
- } // synchronized (readLock)
- }
-
- /**
- * Check the sequence number state
- *
- * RFC 4346 states that, "Sequence numbers are of type uint64 and
- * may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS
- * implementation would need to wrap a sequence number, it must
- * renegotiate instead."
- */
- private void checkSequenceNumber(MAC mac, byte type)
- throws IOException {
-
- /*
- * Don't bother to check the sequence number for error or
- * closed connections, or NULL MAC.
- */
- if (connectionState >= cs_ERROR || mac == MAC.NULL) {
- return;
- }
-
- /*
- * Conservatively, close the connection immediately when the
- * sequence number is close to overflow
- */
- if (mac.seqNumOverflow()) {
- /*
- * TLS protocols do not define a error alert for sequence
- * number overflow. We use handshake_failure error alert
- * for handshaking and bad_record_mac for other records.
- */
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", sequence number extremely close to overflow " +
- "(2^64-1 packets). Closing connection.");
-
- }
-
- fatal(Alerts.alert_handshake_failure, "sequence number overflow");
- }
-
- /*
- * Ask for renegotiation when need to renew sequence number.
- *
- * Don't bother to kickstart the renegotiation when the local is
- * asking for it.
- */
- if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", request renegotiation " +
- "to avoid sequence number overflow");
- }
-
- startHandshake();
- }
- }
-
- //
- // HANDSHAKE RELATED CODE
- //
-
- /**
- * Return the AppInputStream. For use by Handshaker only.
- */
- AppInputStream getAppInputStream() {
- return input;
- }
-
- /**
- * Return the AppOutputStream. For use by Handshaker only.
- */
- AppOutputStream getAppOutputStream() {
- return output;
- }
-
- /**
- * Initialize the handshaker object. This means:
- *
- * . if a handshake is already in progress (state is cs_HANDSHAKE
- * or cs_RENEGOTIATE), do nothing and return
- *
- * . if the socket is already closed, throw an Exception (internal error)
- *
- * . otherwise (cs_START or cs_DATA), create the appropriate handshaker
- * object, and advance the connection state (to cs_HANDSHAKE or
- * cs_RENEGOTIATE, respectively).
- *
- * This method is called right after a new socket is created, when
- * starting renegotiation, or when changing client/ server mode of the
- * socket.
- */
- private void initHandshaker() {
- switch (connectionState) {
-
- //
- // Starting a new handshake.
- //
- case cs_START:
- case cs_DATA:
- break;
-
- //
- // We're already in the middle of a handshake.
- //
- case cs_HANDSHAKE:
- case cs_RENEGOTIATE:
- return;
-
- //
- // Anyone allowed to call this routine is required to
- // do so ONLY if the connection state is reasonable...
- //
- default:
- throw new IllegalStateException("Internal error");
- }
-
- // state is either cs_START or cs_DATA
- if (connectionState == cs_START) {
- connectionState = cs_HANDSHAKE;
- } else { // cs_DATA
- connectionState = cs_RENEGOTIATE;
- }
- if (roleIsServer) {
- handshaker = new ServerHandshaker(this, sslContext,
- enabledProtocols, doClientAuth,
- protocolVersion, connectionState == cs_HANDSHAKE,
- secureRenegotiation, clientVerifyData, serverVerifyData);
- } else {
- handshaker = new ClientHandshaker(this, sslContext,
- enabledProtocols,
- protocolVersion, connectionState == cs_HANDSHAKE,
- secureRenegotiation, clientVerifyData, serverVerifyData);
- }
- handshaker.setEnabledCipherSuites(enabledCipherSuites);
- handshaker.setEnableSessionCreation(enableSessionCreation);
- }
-
- /**
- * Synchronously perform the initial handshake.
- *
- * If the handshake is already in progress, this method blocks until it
- * is completed. If the initial handshake has already been completed,
- * it returns immediately.
- */
- private void performInitialHandshake() throws IOException {
- // use handshakeLock and the state check to make sure only
- // one thread performs the handshake
- synchronized (handshakeLock) {
- if (getConnectionState() == cs_HANDSHAKE) {
- kickstartHandshake();
-
- /*
- * All initial handshaking goes through this
- * InputRecord until we have a valid SSL connection.
- * Once initial handshaking is finished, AppInputStream's
- * InputRecord can handle any future renegotiation.
- *
- * Keep this local so that it goes out of scope and is
- * eventually GC'd.
- */
- if (inrec == null) {
- inrec = new InputRecord();
-
- /*
- * Grab the characteristics already assigned to
- * AppInputStream's InputRecord. Enable checking for
- * SSLv2 hellos on this first handshake.
- */
- inrec.setHandshakeHash(input.r.getHandshakeHash());
- inrec.setHelloVersion(input.r.getHelloVersion());
- inrec.enableFormatChecks();
- }
-
- readRecord(inrec, false);
- inrec = null;
- }
- }
- }
-
- /**
- * Starts an SSL handshake on this connection.
- */
- public void startHandshake() throws IOException {
- // start an ssl handshake that could be resumed from timeout exception
- startHandshake(true);
- }
-
- /**
- * Starts an ssl handshake on this connection.
- *
- * @param resumable indicates the handshake process is resumable from a
- * certain exception. If <code>resumable</code>, the socket will
- * be reserved for exceptions like timeout; otherwise, the socket
- * will be closed, no further communications could be done.
- */
- private void startHandshake(boolean resumable) throws IOException {
- checkWrite();
- try {
- if (getConnectionState() == cs_HANDSHAKE) {
- // do initial handshake
- performInitialHandshake();
- } else {
- // start renegotiation
- kickstartHandshake();
- }
- } catch (Exception e) {
- // shutdown and rethrow (wrapped) exception as appropriate
- handleException(e, resumable);
- }
- }
-
- /**
- * Kickstart the handshake if it is not already in progress.
- * This means:
- *
- * . if handshaking is already underway, do nothing and return
- *
- * . if the socket is not connected or already closed, throw an
- * Exception.
- *
- * . otherwise, call initHandshake() to initialize the handshaker
- * object and progress the state. Then, send the initial
- * handshaking message if appropriate (always on clients and
- * on servers when renegotiating).
- */
- private synchronized void kickstartHandshake() throws IOException {
-
- switch (connectionState) {
-
- case cs_HANDSHAKE:
- // handshaker already setup, proceed
- break;
-
- case cs_DATA:
- if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) {
- throw new SSLHandshakeException(
- "Insecure renegotiation is not allowed");
- }
-
- if (!secureRenegotiation) {
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "Warning: Using insecure renegotiation");
- }
- }
-
- // initialize the handshaker, move to cs_RENEGOTIATE
- initHandshaker();
- break;
-
- case cs_RENEGOTIATE:
- // handshaking already in progress, return
- return;
-
- /*
- * The only way to get a socket in the state is when
- * you have an unconnected socket.
- */
- case cs_START:
- throw new SocketException(
- "handshaking attempted on unconnected socket");
-
- default:
- throw new SocketException("connection is closed");
- }
-
- //
- // Kickstart handshake state machine if we need to ...
- //
- // Note that handshaker.kickstart() writes the message
- // to its HandshakeOutStream, which calls back into
- // SSLSocketImpl.writeRecord() to send it.
- //
- if (!handshaker.activated()) {
- // prior to handshaking, activate the handshake
- if (connectionState == cs_RENEGOTIATE) {
- // don't use SSLv2Hello when renegotiating
- handshaker.activate(protocolVersion);
- } else {
- handshaker.activate(null);
- }
-
- if (handshaker instanceof ClientHandshaker) {
- // send client hello
- handshaker.kickstart();
- } else {
- if (connectionState == cs_HANDSHAKE) {
- // initial handshake, no kickstart message to send
- } else {
- // we want to renegotiate, send hello request
- handshaker.kickstart();
- // hello request is not included in the handshake
- // hashes, reset them
- handshaker.handshakeHash.reset();
- }
- }
- }
- }
-
- //
- // CLOSURE RELATED CALLS
- //
-
- /**
- * Return whether the socket has been explicitly closed by the application.
- */
- public boolean isClosed() {
- return getConnectionState() == cs_APP_CLOSED;
- }
-
- /**
- * Return whether we have reached end-of-file.
- *
- * If the socket is not connected, has been shutdown because of an error
- * or has been closed, throw an Exception.
- */
- boolean checkEOF() throws IOException {
- switch (getConnectionState()) {
- case cs_START:
- throw new SocketException("Socket is not connected");
-
- case cs_HANDSHAKE:
- case cs_DATA:
- case cs_RENEGOTIATE:
- case cs_SENT_CLOSE:
- return false;
-
- case cs_APP_CLOSED:
- throw new SocketException("Socket is closed");
-
- case cs_ERROR:
- case cs_CLOSED:
- default:
- // either closed because of error, or normal EOF
- if (closeReason == null) {
- return true;
- }
- IOException e = new SSLException
- ("Connection has been shutdown: " + closeReason);
- e.initCause(closeReason);
- throw e;
-
- }
- }
-
- /**
- * Check if we can write data to this socket. If not, throw an IOException.
- */
- void checkWrite() throws IOException {
- if (checkEOF() || (getConnectionState() == cs_SENT_CLOSE)) {
- // we are at EOF, write must throw Exception
- throw new SocketException("Connection closed by remote host");
- }
- }
-
- protected void closeSocket() throws IOException {
-
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called closeSocket()");
- }
- if (self == this) {
- super.close();
- } else {
- self.close();
- }
- }
-
- private void closeSocket(boolean selfInitiated) throws IOException {
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called closeSocket(selfInitiated)");
- }
- if (self == this) {
- super.close();
- } else if (autoClose) {
- self.close();
- } else if (selfInitiated) {
- // layered && non-autoclose
- // read close_notify alert to clear input stream
- waitForClose(false);
- }
- }
-
- /*
- * Closing the connection is tricky ... we can't officially close the
- * connection until we know the other end is ready to go away too,
- * and if ever the connection gets aborted we must forget session
- * state (it becomes invalid).
- */
-
- /**
- * Closes the SSL connection. SSL includes an application level
- * shutdown handshake; you should close SSL sockets explicitly
- * rather than leaving it for finalization, so that your remote
- * peer does not experience a protocol error.
- */
- public void close() throws IOException {
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called close()");
- }
- closeInternal(true); // caller is initiating close
- setConnectionState(cs_APP_CLOSED);
- }
-
- /**
- * Don't synchronize the whole method because waitForClose()
- * (which calls readRecord()) might be called.
- *
- * @param selfInitiated Indicates which party initiated the close.
- * If selfInitiated, this side is initiating a close; for layered and
- * non-autoclose socket, wait for close_notify response.
- * If !selfInitiated, peer sent close_notify; we reciprocate but
- * no need to wait for response.
- */
- private void closeInternal(boolean selfInitiated) throws IOException {
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() + ", called closeInternal("
- + selfInitiated + ")");
- }
-
- int state = getConnectionState();
- boolean closeSocketCalled = false;
- Throwable cachedThrowable = null;
- try {
- switch (state) {
- case cs_START:
- // unconnected socket or handshaking has not been initialized
- closeSocket(selfInitiated);
- break;
-
- /*
- * If we're closing down due to error, we already sent (or else
- * received) the fatal alert ... no niceties, blow the connection
- * away as quickly as possible (even if we didn't allocate the
- * socket ourselves; it's unusable, regardless).
- */
- case cs_ERROR:
- closeSocket();
- break;
-
- /*
- * Sometimes close() gets called more than once.
- */
- case cs_CLOSED:
- case cs_APP_CLOSED:
- break;
-
- /*
- * Otherwise we indicate clean termination.
- */
- // case cs_HANDSHAKE:
- // case cs_DATA:
- // case cs_RENEGOTIATE:
- // case cs_SENT_CLOSE:
- default:
- synchronized (this) {
- if (((state = getConnectionState()) == cs_CLOSED) ||
- (state == cs_ERROR) || (state == cs_APP_CLOSED)) {
- return; // connection was closed while we waited
- }
- if (state != cs_SENT_CLOSE) {
- try {
- warning(Alerts.alert_close_notify);
- connectionState = cs_SENT_CLOSE;
- } catch (Throwable th) {
- // we need to ensure socket is closed out
- // if we encounter any errors.
- connectionState = cs_ERROR;
- // cache this for later use
- cachedThrowable = th;
- closeSocketCalled = true;
- closeSocket(selfInitiated);
- }
- }
- }
- // If state was cs_SENT_CLOSE before, we don't do the actual
- // closing since it is already in progress.
- if (state == cs_SENT_CLOSE) {
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", close invoked again; state = " +
- getConnectionState());
- }
- if (selfInitiated == false) {
- // We were called because a close_notify message was
- // received. This may be due to another thread calling
- // read() or due to our call to waitForClose() below.
- // In either case, just return.
- return;
- }
- // Another thread explicitly called close(). We need to
- // wait for the closing to complete before returning.
- synchronized (this) {
- while (connectionState < cs_CLOSED) {
- try {
- this.wait();
- } catch (InterruptedException e) {
- // ignore
- }
- }
- }
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", after primary close; state = " +
- getConnectionState());
- }
- return;
- }
-
- if (!closeSocketCalled) {
- closeSocketCalled = true;
- closeSocket(selfInitiated);
- }
-
- break;
- }
- } finally {
- synchronized (this) {
- // Upon exit from this method, the state is always >= cs_CLOSED
- connectionState = (connectionState == cs_APP_CLOSED)
- ? cs_APP_CLOSED : cs_CLOSED;
- // notify any threads waiting for the closing to finish
- this.notifyAll();
- }
- if (closeSocketCalled) {
- // Dispose of ciphers since we've closed socket
- disposeCiphers();
- }
- if (cachedThrowable != null) {
- /*
- * Rethrow the error to the calling method
- * The Throwable caught can only be an Error or RuntimeException
- */
- if (cachedThrowable instanceof Error)
- throw (Error) cachedThrowable;
- if (cachedThrowable instanceof RuntimeException)
- throw (RuntimeException) cachedThrowable;
- }
- }
- }
-
- /**
- * Reads a close_notify or a fatal alert from the input stream.
- * Keep reading records until we get a close_notify or until
- * the connection is otherwise closed. The close_notify or alert
- * might be read by another reader,
- * which will then process the close and set the connection state.
- */
- void waitForClose(boolean rethrow) throws IOException {
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", waiting for close_notify or alert: state "
- + getConnectionState());
- }
-
- try {
- int state;
-
- while (((state = getConnectionState()) != cs_CLOSED) &&
- (state != cs_ERROR) && (state != cs_APP_CLOSED)) {
- // create the InputRecord if it isn't intialized.
- if (inrec == null) {
- inrec = new InputRecord();
- }
-
- // Ask for app data and then throw it away
- try {
- readRecord(inrec, true);
- } catch (SocketTimeoutException e) {
- // if time out, ignore the exception and continue
- }
- }
- inrec = null;
- } catch (IOException e) {
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", Exception while waiting for close " +e);
- }
- if (rethrow) {
- throw e; // pass exception up
- }
- }
- }
-
- /**
- * Called by closeInternal() only. Be sure to consider the
- * synchronization locks carefully before calling it elsewhere.
- */
- private void disposeCiphers() {
- // See comment in changeReadCiphers()
- synchronized (readLock) {
- readCipher.dispose();
- }
- // See comment in changeReadCiphers()
- writeLock.lock();
- try {
- writeCipher.dispose();
- } finally {
- writeLock.unlock();
- }
- }
-
- //
- // EXCEPTION AND ALERT HANDLING
- //
-
- /**
- * Handle an exception. This method is called by top level exception
- * handlers (in read(), write()) to make sure we always shutdown the
- * connection correctly and do not pass runtime exception to the
- * application.
- */
- void handleException(Exception e) throws IOException {
- handleException(e, true);
- }
-
- /**
- * Handle an exception. This method is called by top level exception
- * handlers (in read(), write(), startHandshake()) to make sure we
- * always shutdown the connection correctly and do not pass runtime
- * exception to the application.
- *
- * This method never returns normally, it always throws an IOException.
- *
- * We first check if the socket has already been shutdown because of an
- * error. If so, we just rethrow the exception. If the socket has not
- * been shutdown, we sent a fatal alert and remember the exception.
- *
- * @param e the Exception
- * @param resumable indicates the caller process is resumable from the
- * exception. If <code>resumable</code>, the socket will be
- * reserved for exceptions like timeout; otherwise, the socket
- * will be closed, no further communications could be done.
- */
- synchronized private void handleException(Exception e, boolean resumable)
- throws IOException {
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName()
- + ", handling exception: " + e.toString());
- }
-
- // don't close the Socket in case of timeouts or interrupts if
- // the process is resumable.
- if (e instanceof InterruptedIOException && resumable) {
- throw (IOException)e;
- }
-
- // if we've already shutdown because of an error,
- // there is nothing to do except rethrow the exception
- if (closeReason != null) {
- if (e instanceof IOException) { // includes SSLException
- throw (IOException)e;
- } else {
- // this is odd, not an IOException.
- // normally, this should not happen
- // if closeReason has been already been set
- throw Alerts.getSSLException(Alerts.alert_internal_error, e,
- "Unexpected exception");
- }
- }
-
- // need to perform error shutdown
- boolean isSSLException = (e instanceof SSLException);
- if ((isSSLException == false) && (e instanceof IOException)) {
- // IOException from the socket
- // this means the TCP connection is already dead
- // we call fatal just to set the error status
- try {
- fatal(Alerts.alert_unexpected_message, e);
- } catch (IOException ee) {
- // ignore (IOException wrapped in SSLException)
- }
- // rethrow original IOException
- throw (IOException)e;
- }
-
- // must be SSLException or RuntimeException
- byte alertType;
- if (isSSLException) {
- if (e instanceof SSLHandshakeException) {
- alertType = Alerts.alert_handshake_failure;
- } else {
- alertType = Alerts.alert_unexpected_message;
- }
- } else {
- alertType = Alerts.alert_internal_error;
- }
- fatal(alertType, e);
- }
-
- /*
- * Send a warning alert.
- */
- void warning(byte description) {
- sendAlert(Alerts.alert_warning, description);
- }
-
- synchronized void fatal(byte description, String diagnostic)
- throws IOException {
- fatal(description, diagnostic, null);
- }
-
- synchronized void fatal(byte description, Throwable cause)
- throws IOException {
- fatal(description, null, cause);
- }
-
- /*
- * Send a fatal alert, and throw an exception so that callers will
- * need to stand on their heads to accidentally continue processing.
- */
- synchronized void fatal(byte description, String diagnostic,
- Throwable cause) throws IOException {
- if ((input != null) && (input.r != null)) {
- input.r.close();
- }
- sess.invalidate();
- if (handshakeSession != null) {
- handshakeSession.invalidate();
- }
-
- int oldState = connectionState;
- if (connectionState < cs_ERROR) {
- connectionState = cs_ERROR;
- }
-
- /*
- * Has there been an error received yet? If not, remember it.
- * By RFC 2246, we don't bother waiting for a response.
- * Fatal errors require immediate shutdown.
- */
- if (closeReason == null) {
- /*
- * Try to clear the kernel buffer to avoid TCP connection resets.
- */
- if (oldState == cs_HANDSHAKE) {
- sockInput.skip(sockInput.available());
- }
-
- // If the description equals -1, the alert won't be sent to peer.
- if (description != -1) {
- sendAlert(Alerts.alert_fatal, description);
- }
- if (cause instanceof SSLException) { // only true if != null
- closeReason = (SSLException)cause;
- } else {
- closeReason =
- Alerts.getSSLException(description, cause, diagnostic);
- }
- }
-
- /*
- * Clean up our side.
- */
- closeSocket();
- // Another thread may have disposed the ciphers during closing
- if (connectionState < cs_CLOSED) {
- connectionState = (oldState == cs_APP_CLOSED) ? cs_APP_CLOSED
- : cs_CLOSED;
-
- // We should lock readLock and writeLock if no deadlock risks.
- // See comment in changeReadCiphers()
- readCipher.dispose();
- writeCipher.dispose();
- }
-
- throw closeReason;
- }
-
-
- /*
- * Process an incoming alert ... caller must already have synchronized
- * access to "this".
- */
- private void recvAlert(InputRecord r) throws IOException {
- byte level = (byte)r.read();
- byte description = (byte)r.read();
- if (description == -1) { // check for short message
- fatal(Alerts.alert_illegal_parameter, "Short alert message");
- }
-
- if (debug != null && (Debug.isOn("record") ||
- Debug.isOn("handshake"))) {
- synchronized (System.out) {
- System.out.print(threadName());
- System.out.print(", RECV " + protocolVersion + " ALERT: ");
- if (level == Alerts.alert_fatal) {
- System.out.print("fatal, ");
- } else if (level == Alerts.alert_warning) {
- System.out.print("warning, ");
- } else {
- System.out.print("<level " + (0x0ff & level) + ">, ");
- }
- System.out.println(Alerts.alertDescription(description));
- }
- }
-
- if (level == Alerts.alert_warning) {
- if (description == Alerts.alert_close_notify) {
- if (connectionState == cs_HANDSHAKE) {
- fatal(Alerts.alert_unexpected_message,
- "Received close_notify during handshake");
- } else {
- closeInternal(false); // reply to close
- }
- } else {
-
- //
- // The other legal warnings relate to certificates,
- // e.g. no_certificate, bad_certificate, etc; these
- // are important to the handshaking code, which can
- // also handle illegal protocol alerts if needed.
- //
- if (handshaker != null) {
- handshaker.handshakeAlert(description);
- }
- }
- } else { // fatal or unknown level
- String reason = "Received fatal alert: "
- + Alerts.alertDescription(description);
- if (closeReason == null) {
- closeReason = Alerts.getSSLException(description, reason);
- }
- fatal(Alerts.alert_unexpected_message, reason);
- }
- }
-
-
- /*
- * Emit alerts. Caller must have synchronized with "this".
- */
- private void sendAlert(byte level, byte description) {
- // the connectionState cannot be cs_START
- if (connectionState >= cs_SENT_CLOSE) {
- return;
- }
-
- // For initial handshaking, don't send alert message to peer if
- // handshaker has not started.
- if (connectionState == cs_HANDSHAKE &&
- (handshaker == null || !handshaker.started())) {
- return;
- }
-
- OutputRecord r = new OutputRecord(Record.ct_alert);
- r.setVersion(protocolVersion);
-
- boolean useDebug = debug != null && Debug.isOn("ssl");
- if (useDebug) {
- synchronized (System.out) {
- System.out.print(threadName());
- System.out.print(", SEND " + protocolVersion + " ALERT: ");
- if (level == Alerts.alert_fatal) {
- System.out.print("fatal, ");
- } else if (level == Alerts.alert_warning) {
- System.out.print("warning, ");
- } else {
- System.out.print("<level = " + (0x0ff & level) + ">, ");
- }
- System.out.println("description = "
- + Alerts.alertDescription(description));
- }
- }
-
- r.write(level);
- r.write(description);
- try {
- writeRecord(r);
- } catch (IOException e) {
- if (useDebug) {
- System.out.println(threadName() +
- ", Exception sending alert: " + e);
- }
- }
- }
-
- //
- // VARIOUS OTHER METHODS
- //
-
- /*
- * When a connection finishes handshaking by enabling use of a newly
- * negotiated session, each end learns about it in two halves (read,
- * and write). When both read and write ciphers have changed, and the
- * last handshake message has been read, the connection has joined
- * (rejoined) the new session.
- *
- * NOTE: The SSLv3 spec is rather unclear on the concepts here.
- * Sessions don't change once they're established (including cipher
- * suite and master secret) but connections can join them (and leave
- * them). They're created by handshaking, though sometime handshaking
- * causes connections to join up with pre-established sessions.
- */
- private void changeReadCiphers() throws SSLException {
- if (connectionState != cs_HANDSHAKE
- && connectionState != cs_RENEGOTIATE) {
- throw new SSLProtocolException(
- "State error, change cipher specs");
- }
-
- // ... create decompressor
-
- CipherBox oldCipher = readCipher;
-
- try {
- readCipher = handshaker.newReadCipher();
- readMAC = handshaker.newReadMAC();
- } catch (GeneralSecurityException e) {
- // "can't happen"
- throw (SSLException)new SSLException
- ("Algorithm missing: ").initCause(e);
- }
-
- /*
- * Dispose of any intermediate state in the underlying cipher.
- * For PKCS11 ciphers, this will release any attached sessions,
- * and thus make finalization faster.
- *
- * Since MAC's doFinal() is called for every SSL/TLS packet, it's
- * not necessary to do the same with MAC's.
- */
- oldCipher.dispose();
- }
-
- // used by Handshaker
- void changeWriteCiphers() throws SSLException {
- if (connectionState != cs_HANDSHAKE
- && connectionState != cs_RENEGOTIATE) {
- throw new SSLProtocolException(
- "State error, change cipher specs");
- }
-
- // ... create compressor
-
- CipherBox oldCipher = writeCipher;
-
- try {
- writeCipher = handshaker.newWriteCipher();
- writeMAC = handshaker.newWriteMAC();
- } catch (GeneralSecurityException e) {
- // "can't happen"
- throw (SSLException)new SSLException
- ("Algorithm missing: ").initCause(e);
- }
-
- // See comment above.
- oldCipher.dispose();
-
- // reset the flag of the first application record
- isFirstAppOutputRecord = true;
- }
-
- /*
- * Updates the SSL version associated with this connection.
- * Called from Handshaker once it has determined the negotiated version.
- */
- synchronized void setVersion(ProtocolVersion protocolVersion) {
- this.protocolVersion = protocolVersion;
- output.r.setVersion(protocolVersion);
- }
-
- synchronized String getHost() {
- // Note that the host may be null or empty for localhost.
- if (host == null || host.length() == 0) {
- host = getInetAddress().getHostName();
- }
- return host;
- }
-
- synchronized String getRawHostname() {
- return rawHostname;
- }
-
- // ONLY used by HttpsClient to setup the URI specified hostname
- synchronized public void setHost(String host) {
- this.host = host;
- this.rawHostname = host;
- }
-
- /**
- * Gets an input stream to read from the peer on the other side.
- * Data read from this stream was always integrity protected in
- * transit, and will usually have been confidentiality protected.
- */
- synchronized public InputStream getInputStream() throws IOException {
- if (isClosed()) {
- throw new SocketException("Socket is closed");
- }
-
- /*
- * Can't call isConnected() here, because the Handshakers
- * do some initialization before we actually connect.
- */
- if (connectionState == cs_START) {
- throw new SocketException("Socket is not connected");
- }
-
- return input;
- }
-
- /**
- * Gets an output stream to write to the peer on the other side.
- * Data written on this stream is always integrity protected, and
- * will usually be confidentiality protected.
- */
- synchronized public OutputStream getOutputStream() throws IOException {
- if (isClosed()) {
- throw new SocketException("Socket is closed");
- }
-
- /*
- * Can't call isConnected() here, because the Handshakers
- * do some initialization before we actually connect.
- */
- if (connectionState == cs_START) {
- throw new SocketException("Socket is not connected");
- }
-
- return output;
- }
-
- /**
- * Returns the the SSL Session in use by this connection. These can
- * be long lived, and frequently correspond to an entire login session
- * for some user.
- */
- public SSLSession getSession() {
- /*
- * Force a synchronous handshake, if appropriate.
- */
- if (getConnectionState() == cs_HANDSHAKE) {
- try {
- // start handshaking, if failed, the connection will be closed.
- startHandshake(false);
- } catch (IOException e) {
- // handshake failed. log and return a nullSession
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(threadName() +
- ", IOException in getSession(): " + e);
- }
- }
- }
- synchronized (this) {
- return sess;
- }
- }
-
- @Override
- synchronized public SSLSession getHandshakeSession() {
- return handshakeSession;
- }
-
- synchronized void setHandshakeSession(SSLSessionImpl session) {
- handshakeSession = session;
- }
-
- /**
- * Controls whether new connections may cause creation of new SSL
- * sessions.
- *
- * As long as handshaking has not started, we can change
- * whether we enable session creations. Otherwise,
- * we will need to wait for the next handshake.
- */
- synchronized public void setEnableSessionCreation(boolean flag) {
- enableSessionCreation = flag;
-
- if ((handshaker != null) && !handshaker.activated()) {
- handshaker.setEnableSessionCreation(enableSessionCreation);
- }
- }
-
- /**
- * Returns true if new connections may cause creation of new SSL
- * sessions.
- */
- synchronized public boolean getEnableSessionCreation() {
- return enableSessionCreation;
- }
-
-
- /**
- * Sets the flag controlling whether a server mode socket
- * *REQUIRES* SSL client authentication.
- *
- * As long as handshaking has not started, we can change
- * whether client authentication is needed. Otherwise,
- * we will need to wait for the next handshake.
- */
- synchronized public void setNeedClientAuth(boolean flag) {
- doClientAuth = (flag ?
- SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none);
-
- if ((handshaker != null) &&
- (handshaker instanceof ServerHandshaker) &&
- !handshaker.activated()) {
- ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
- }
- }
-
- synchronized public boolean getNeedClientAuth() {
- return (doClientAuth == SSLEngineImpl.clauth_required);
- }
-
- /**
- * Sets the flag controlling whether a server mode socket
- * *REQUESTS* SSL client authentication.
- *
- * As long as handshaking has not started, we can change
- * whether client authentication is requested. Otherwise,
- * we will need to wait for the next handshake.
- */
- synchronized public void setWantClientAuth(boolean flag) {
- doClientAuth = (flag ?
- SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none);
-
- if ((handshaker != null) &&
- (handshaker instanceof ServerHandshaker) &&
- !handshaker.activated()) {
- ((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
- }
- }
-
- synchronized public boolean getWantClientAuth() {
- return (doClientAuth == SSLEngineImpl.clauth_requested);
- }
-
-
- /**
- * Sets the flag controlling whether the socket is in SSL
- * client or server mode. Must be called before any SSL
- * traffic has started.
- */
- synchronized public void setUseClientMode(boolean flag) {
- switch (connectionState) {
-
- case cs_START:
- /*
- * If we need to change the socket mode and the enabled
- * protocols haven't specifically been set by the user,
- * change them to the corresponding default ones.
- */
- if (roleIsServer != (!flag) &&
- sslContext.isDefaultProtocolList(enabledProtocols)) {
- enabledProtocols = sslContext.getDefaultProtocolList(!flag);
- }
- roleIsServer = !flag;
- break;
-
- case cs_HANDSHAKE:
- /*
- * If we have a handshaker, but haven't started
- * SSL traffic, we can throw away our current
- * handshaker, and start from scratch. Don't
- * need to call doneConnect() again, we already
- * have the streams.
- */
- assert(handshaker != null);
- if (!handshaker.activated()) {
- /*
- * If we need to change the socket mode and the enabled
- * protocols haven't specifically been set by the user,
- * change them to the corresponding default ones.
- */
- if (roleIsServer != (!flag) &&
- sslContext.isDefaultProtocolList(enabledProtocols)) {
- enabledProtocols = sslContext.getDefaultProtocolList(!flag);
- }
- roleIsServer = !flag;
- connectionState = cs_START;
- initHandshaker();
- break;
- }
-
- // If handshake has started, that's an error. Fall through...
-
- default:
- if (debug != null && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", setUseClientMode() invoked in state = " +
- connectionState);
- }
- throw new IllegalArgumentException(
- "Cannot change mode after SSL traffic has started");
- }
- }
-
- synchronized public boolean getUseClientMode() {
- return !roleIsServer;
- }
-
-
- /**
- * Returns the names of the cipher suites which could be enabled for use
- * on an SSL connection. Normally, only a subset of these will actually
- * be enabled by default, since this list may include cipher suites which
- * do not support the mutual authentication of servers and clients, or
- * which do not protect data confidentiality. Servers may also need
- * certain kinds of certificates to use certain cipher suites.
- *
- * @return an array of cipher suite names
- */
- public String[] getSupportedCipherSuites() {
- return sslContext.getSupportedCipherSuiteList().toStringArray();
- }
-
- /**
- * Controls which particular cipher suites are enabled for use on
- * this connection. The cipher suites must have been listed by
- * getCipherSuites() as being supported. Even if a suite has been
- * enabled, it might never be used if no peer supports it or the
- * requisite certificates (and private keys) are not available.
- *
- * @param suites Names of all the cipher suites to enable.
- */
- synchronized public void setEnabledCipherSuites(String[] suites) {
- enabledCipherSuites = new CipherSuiteList(suites);
- if ((handshaker != null) && !handshaker.activated()) {
- handshaker.setEnabledCipherSuites(enabledCipherSuites);
- }
- }
-
- /**
- * Returns the names of the SSL cipher suites which are currently enabled
- * for use on this connection. When an SSL socket is first created,
- * all enabled cipher suites <em>(a)</em> protect data confidentiality,
- * by traffic encryption, and <em>(b)</em> can mutually authenticate
- * both clients and servers. Thus, in some environments, this value
- * might be empty.
- *
- * @return an array of cipher suite names
- */
- synchronized public String[] getEnabledCipherSuites() {
- return enabledCipherSuites.toStringArray();
- }
-
-
- /**
- * Returns the protocols that are supported by this implementation.
- * A subset of the supported protocols may be enabled for this connection
- * @return an array of protocol names.
- */
- public String[] getSupportedProtocols() {
- return sslContext.getSuportedProtocolList().toStringArray();
- }
-
- /**
- * Controls which protocols are enabled for use on
- * this connection. The protocols must have been listed by
- * getSupportedProtocols() as being supported.
- *
- * @param protocols protocols to enable.
- * @exception IllegalArgumentException when one of the protocols
- * named by the parameter is not supported.
- */
- synchronized public void setEnabledProtocols(String[] protocols) {
- enabledProtocols = new ProtocolList(protocols);
- if ((handshaker != null) && !handshaker.activated()) {
- handshaker.setEnabledProtocols(enabledProtocols);
- }
- }
-
- synchronized public String[] getEnabledProtocols() {
- return enabledProtocols.toStringArray();
- }
-
- /**
- * Assigns the socket timeout.
- * @see java.net.Socket#setSoTimeout
- */
- public void setSoTimeout(int timeout) throws SocketException {
- if ((debug != null) && Debug.isOn("ssl")) {
- System.out.println(threadName() +
- ", setSoTimeout(" + timeout + ") called");
- }
- if (self == this) {
- super.setSoTimeout(timeout);
- } else {
- self.setSoTimeout(timeout);
- }
- }
-
- /**
- * Registers an event listener to receive notifications that an
- * SSL handshake has completed on this connection.
- */
- public synchronized void addHandshakeCompletedListener(
- HandshakeCompletedListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("listener is null");
- }
- if (handshakeListeners == null) {
- handshakeListeners = new
- HashMap<HandshakeCompletedListener, AccessControlContext>(4);
- }
- handshakeListeners.put(listener, AccessController.getContext());
- }
-
-
- /**
- * Removes a previously registered handshake completion listener.
- */
- public synchronized void removeHandshakeCompletedListener(
- HandshakeCompletedListener listener) {
- if (handshakeListeners == null) {
- throw new IllegalArgumentException("no listeners");
- }
- if (handshakeListeners.remove(listener) == null) {
- throw new IllegalArgumentException("listener not registered");
- }
- if (handshakeListeners.isEmpty()) {
- handshakeListeners = null;
- }
- }
-
- /**
- * Returns the SSLParameters in effect for this SSLSocket.
- */
- synchronized public SSLParameters getSSLParameters() {
- SSLParameters params = super.getSSLParameters();
-
- // the super implementation does not handle the following parameters
- params.setEndpointIdentificationAlgorithm(identificationProtocol);
- params.setAlgorithmConstraints(algorithmConstraints);
-
- return params;
- }
-
- /**
- * Applies SSLParameters to this socket.
- */
- synchronized public void setSSLParameters(SSLParameters params) {
- super.setSSLParameters(params);
-
- // the super implementation does not handle the following parameters
- identificationProtocol = params.getEndpointIdentificationAlgorithm();
- algorithmConstraints = params.getAlgorithmConstraints();
- if ((handshaker != null) && !handshaker.started()) {
- handshaker.setIdentificationProtocol(identificationProtocol);
- handshaker.setAlgorithmConstraints(algorithmConstraints);
- }
- }
-
- //
- // We allocate a separate thread to deliver handshake completion
- // events. This ensures that the notifications don't block the
- // protocol state machine.
- //
- private static class NotifyHandshakeThread extends Thread {
-
- private Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>>
- targets; // who gets notified
- private HandshakeCompletedEvent event; // the notification
-
- NotifyHandshakeThread(
- Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>>
- entrySet, HandshakeCompletedEvent e) {
-
- super("HandshakeCompletedNotify-Thread");
- targets = new HashSet<>(entrySet); // clone the entry set
- event = e;
- }
-
- public void run() {
- // Don't need to synchronize, as it only runs in one thread.
- for (Map.Entry<HandshakeCompletedListener,AccessControlContext>
- entry : targets) {
-
- final HandshakeCompletedListener l = entry.getKey();
- AccessControlContext acc = entry.getValue();
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- l.handshakeCompleted(event);
- return null;
- }
- }, acc);
- }
- }
- }
-
- /**
- * Return the name of the current thread. Utility method.
- */
- private static String threadName() {
- return Thread.currentThread().getName();
- }
-
- /**
- * Returns a printable representation of this end of the connection.
- */
- public String toString() {
- StringBuffer retval = new StringBuffer(80);
-
- retval.append(Integer.toHexString(hashCode()));
- retval.append("[");
- retval.append(sess.getCipherSuite());
- retval.append(": ");
-
- if (self == this) {
- retval.append(super.toString());
- } else {
- retval.append(self.toString());
- }
- retval.append("]");
-
- return retval.toString();
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/ServerHandshaker.java b/ojluni/src/main/java/sun/security/ssl/ServerHandshaker.java
deleted file mode 100755
index c651b44..0000000
--- a/ojluni/src/main/java/sun/security/ssl/ServerHandshaker.java
+++ /dev/null
@@ -1,1682 +0,0 @@
-/*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.util.*;
-import java.security.*;
-import java.security.cert.*;
-import java.security.interfaces.*;
-import java.security.spec.ECParameterSpec;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-
-import javax.net.ssl.*;
-
-import javax.security.auth.Subject;
-
-import sun.security.ssl.HandshakeMessage.*;
-import sun.security.ssl.CipherSuite.*;
-import sun.security.ssl.SignatureAndHashAlgorithm.*;
-import static sun.security.ssl.CipherSuite.*;
-import static sun.security.ssl.CipherSuite.KeyExchange.*;
-
-/**
- * ServerHandshaker does the protocol handshaking from the point
- * of view of a server. It is driven asychronously by handshake messages
- * as delivered by the parent Handshaker class, and also uses
- * common functionality (e.g. key generation) that is provided there.
- *
- * @author David Brownell
- */
-final class ServerHandshaker extends Handshaker {
-
- // is the server going to require the client to authenticate?
- private byte doClientAuth;
-
- // our authentication info
- private X509Certificate[] certs;
- private PrivateKey privateKey;
-
- private SecretKey[] kerberosKeys;
-
- // flag to check for clientCertificateVerify message
- private boolean needClientVerify = false;
-
- /*
- * For exportable ciphersuites using non-exportable key sizes, we use
- * ephemeral RSA keys. We could also do anonymous RSA in the same way
- * but there are no such ciphersuites currently defined.
- */
- private PrivateKey tempPrivateKey;
- private PublicKey tempPublicKey;
-
- /*
- * For anonymous and ephemeral Diffie-Hellman key exchange, we use
- * ephemeral Diffie-Hellman keys.
- */
- private DHCrypt dh;
-
- // Helper for ECDH based key exchanges
- private ECDHCrypt ecdh;
-
- // version request by the client in its ClientHello
- // we remember it for the RSA premaster secret version check
- private ProtocolVersion clientRequestedVersion;
-
- private SupportedEllipticCurvesExtension supportedCurves;
-
- // the preferable signature algorithm used by ServerKeyExchange message
- SignatureAndHashAlgorithm preferableSignatureAlgorithm;
-
- /*
- * Constructor ... use the keys found in the auth context.
- */
- ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context,
- ProtocolList enabledProtocols, byte clientAuth,
- ProtocolVersion activeProtocolVersion, boolean isInitialHandshake,
- boolean secureRenegotiation,
- byte[] clientVerifyData, byte[] serverVerifyData) {
-
- super(socket, context, enabledProtocols,
- (clientAuth != SSLEngineImpl.clauth_none), false,
- activeProtocolVersion, isInitialHandshake, secureRenegotiation,
- clientVerifyData, serverVerifyData);
- doClientAuth = clientAuth;
- }
-
- /*
- * Constructor ... use the keys found in the auth context.
- */
- ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context,
- ProtocolList enabledProtocols, byte clientAuth,
- ProtocolVersion activeProtocolVersion,
- boolean isInitialHandshake, boolean secureRenegotiation,
- byte[] clientVerifyData, byte[] serverVerifyData) {
-
- super(engine, context, enabledProtocols,
- (clientAuth != SSLEngineImpl.clauth_none), false,
- activeProtocolVersion, isInitialHandshake, secureRenegotiation,
- clientVerifyData, serverVerifyData);
- doClientAuth = clientAuth;
- }
-
- /*
- * As long as handshaking has not started, we can change
- * whether client authentication is required. Otherwise,
- * we will need to wait for the next handshake.
- */
- void setClientAuth(byte clientAuth) {
- doClientAuth = clientAuth;
- }
-
- /*
- * This routine handles all the server side handshake messages, one at
- * a time. Given the message type (and in some cases the pending cipher
- * spec) it parses the type-specific message. Then it calls a function
- * that handles that specific message.
- *
- * It updates the state machine as each message is processed, and writes
- * responses as needed using the connection in the constructor.
- */
- void processMessage(byte type, int message_len)
- throws IOException {
- //
- // In SSLv3 and TLS, messages follow strictly increasing
- // numerical order _except_ for one annoying special case.
- //
- if ((state >= type)
- && (state != HandshakeMessage.ht_client_key_exchange
- && type != HandshakeMessage.ht_certificate_verify)) {
- throw new SSLProtocolException(
- "Handshake message sequence violation, state = " + state
- + ", type = " + type);
- }
-
- switch (type) {
- case HandshakeMessage.ht_client_hello:
- ClientHello ch = new ClientHello(input, message_len);
- /*
- * send it off for processing.
- */
- this.clientHello(ch);
- break;
-
- case HandshakeMessage.ht_certificate:
- if (doClientAuth == SSLEngineImpl.clauth_none) {
- fatalSE(Alerts.alert_unexpected_message,
- "client sent unsolicited cert chain");
- // NOTREACHED
- }
- this.clientCertificate(new CertificateMsg(input));
- break;
-
- case HandshakeMessage.ht_client_key_exchange:
- SecretKey preMasterSecret;
- switch (keyExchange) {
- case K_RSA:
- case K_RSA_EXPORT:
- /*
- * The client's pre-master secret is decrypted using
- * either the server's normal private RSA key, or the
- * temporary one used for non-export or signing-only
- * certificates/keys.
- */
- RSAClientKeyExchange pms = new RSAClientKeyExchange(
- protocolVersion, clientRequestedVersion,
- sslContext.getSecureRandom(), input,
- message_len, privateKey);
- preMasterSecret = this.clientKeyExchange(pms);
- break;
- case K_KRB5:
- case K_KRB5_EXPORT:
- preMasterSecret = this.clientKeyExchange(
- new KerberosClientKeyExchange(protocolVersion,
- clientRequestedVersion,
- sslContext.getSecureRandom(),
- input,
- kerberosKeys));
- break;
- case K_DHE_RSA:
- case K_DHE_DSS:
- case K_DH_ANON:
- /*
- * The pre-master secret is derived using the normal
- * Diffie-Hellman calculation. Note that the main
- * protocol difference in these five flavors is in how
- * the ServerKeyExchange message was constructed!
- */
- preMasterSecret = this.clientKeyExchange(
- new DHClientKeyExchange(input));
- break;
- case K_ECDH_RSA:
- case K_ECDH_ECDSA:
- case K_ECDHE_RSA:
- case K_ECDHE_ECDSA:
- case K_ECDH_ANON:
- preMasterSecret = this.clientKeyExchange
- (new ECDHClientKeyExchange(input));
- break;
- default:
- throw new SSLProtocolException
- ("Unrecognized key exchange: " + keyExchange);
- }
-
- //
- // All keys are calculated from the premaster secret
- // and the exchanged nonces in the same way.
- //
- calculateKeys(preMasterSecret, clientRequestedVersion);
- break;
-
- case HandshakeMessage.ht_certificate_verify:
- this.clientCertificateVerify(new CertificateVerify(input,
- localSupportedSignAlgs, protocolVersion));
- break;
-
- case HandshakeMessage.ht_finished:
- this.clientFinished(
- new Finished(protocolVersion, input, cipherSuite));
- break;
-
- default:
- throw new SSLProtocolException(
- "Illegal server handshake msg, " + type);
- }
-
- //
- // Move state machine forward if the message handling
- // code didn't already do so
- //
- if (state < type) {
- if(type == HandshakeMessage.ht_certificate_verify) {
- state = type + 2; // an annoying special case
- } else {
- state = type;
- }
- }
- }
-
-
- /*
- * ClientHello presents the server with a bunch of options, to which the
- * server replies with a ServerHello listing the ones which this session
- * will use. If needed, it also writes its Certificate plus in some cases
- * a ServerKeyExchange message. It may also write a CertificateRequest,
- * to elicit a client certificate.
- *
- * All these messages are terminated by a ServerHelloDone message. In
- * most cases, all this can be sent in a single Record.
- */
- private void clientHello(ClientHello mesg) throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- // Does the message include security renegotiation indication?
- boolean renegotiationIndicated = false;
-
- // check the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
- CipherSuiteList cipherSuites = mesg.getCipherSuites();
- if (cipherSuites.contains(CipherSuite.C_SCSV)) {
- renegotiationIndicated = true;
- if (isInitialHandshake) {
- secureRenegotiation = true;
- } else {
- // abort the handshake with a fatal handshake_failure alert
- if (secureRenegotiation) {
- fatalSE(Alerts.alert_handshake_failure,
- "The SCSV is present in a secure renegotiation");
- } else {
- fatalSE(Alerts.alert_handshake_failure,
- "The SCSV is present in a insecure renegotiation");
- }
- }
- }
-
- // check the "renegotiation_info" extension
- RenegotiationInfoExtension clientHelloRI = (RenegotiationInfoExtension)
- mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO);
- if (clientHelloRI != null) {
- renegotiationIndicated = true;
- if (isInitialHandshake) {
- // verify the length of the "renegotiated_connection" field
- if (!clientHelloRI.isEmpty()) {
- // abort the handshake with a fatal handshake_failure alert
- fatalSE(Alerts.alert_handshake_failure,
- "The renegotiation_info field is not empty");
- }
-
- secureRenegotiation = true;
- } else {
- if (!secureRenegotiation) {
- // unexpected RI extension for insecure renegotiation,
- // abort the handshake with a fatal handshake_failure alert
- fatalSE(Alerts.alert_handshake_failure,
- "The renegotiation_info is present in a insecure " +
- "renegotiation");
- }
-
- // verify the client_verify_data value
- if (!Arrays.equals(clientVerifyData,
- clientHelloRI.getRenegotiatedConnection())) {
- fatalSE(Alerts.alert_handshake_failure,
- "Incorrect verify data in ClientHello " +
- "renegotiation_info message");
- }
- }
- } else if (!isInitialHandshake && secureRenegotiation) {
- // if the connection's "secure_renegotiation" flag is set to TRUE
- // and the "renegotiation_info" extension is not present, abort
- // the handshake.
- fatalSE(Alerts.alert_handshake_failure,
- "Inconsistent secure renegotiation indication");
- }
-
- // if there is no security renegotiation indication or the previous
- // handshake is insecure.
- if (!renegotiationIndicated || !secureRenegotiation) {
- if (isInitialHandshake) {
- if (!allowLegacyHelloMessages) {
- // abort the handshake with a fatal handshake_failure alert
- fatalSE(Alerts.alert_handshake_failure,
- "Failed to negotiate the use of secure renegotiation");
- }
-
- // continue with legacy ClientHello
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("Warning: No renegotiation " +
- "indication in ClientHello, allow legacy ClientHello");
- }
- } else if (!allowUnsafeRenegotiation) {
- // abort the handshake
- if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
- // response with a no_renegotiation warning,
- warningSE(Alerts.alert_no_renegotiation);
-
- // invalidate the handshake so that the caller can
- // dispose this object.
- invalidated = true;
-
- // If there is still unread block in the handshake
- // input stream, it would be truncated with the disposal
- // and the next handshake message will become incomplete.
- //
- // However, according to SSL/TLS specifications, no more
- // handshake message could immediately follow ClientHello
- // or HelloRequest. But in case of any improper messages,
- // we'd better check to ensure there is no remaining bytes
- // in the handshake input stream.
- if (input.available() > 0) {
- fatalSE(Alerts.alert_unexpected_message,
- "ClientHello followed by an unexpected " +
- "handshake message");
- }
-
- return;
- } else {
- // For SSLv3, send the handshake_failure fatal error.
- // Note that SSLv3 does not define a no_renegotiation
- // alert like TLSv1. However we cannot ignore the message
- // simply, otherwise the other side was waiting for a
- // response that would never come.
- fatalSE(Alerts.alert_handshake_failure,
- "Renegotiation is not allowed");
- }
- } else { // !isInitialHandshake && allowUnsafeRenegotiation
- // continue with unsafe renegotiation.
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println(
- "Warning: continue with insecure renegotiation");
- }
- }
- }
-
- /*
- * Always make sure this entire record has been digested before we
- * start emitting output, to ensure correct digesting order.
- */
- input.digestNow();
-
- /*
- * FIRST, construct the ServerHello using the options and priorities
- * from the ClientHello. Update the (pending) cipher spec as we do
- * so, and save the client's version to protect against rollback
- * attacks.
- *
- * There are a bunch of minor tasks here, and one major one: deciding
- * if the short or the full handshake sequence will be used.
- */
- ServerHello m1 = new ServerHello();
-
- clientRequestedVersion = mesg.protocolVersion;
-
- // select a proper protocol version.
- ProtocolVersion selectedVersion =
- selectProtocolVersion(clientRequestedVersion);
- if (selectedVersion == null ||
- selectedVersion.v == ProtocolVersion.SSL20Hello.v) {
- fatalSE(Alerts.alert_handshake_failure,
- "Client requested protocol " + clientRequestedVersion +
- " not enabled or not supported");
- }
-
- handshakeHash.protocolDetermined(selectedVersion);
- setVersion(selectedVersion);
-
- m1.protocolVersion = protocolVersion;
-
- //
- // random ... save client and server values for later use
- // in computing the master secret (from pre-master secret)
- // and thence the other crypto keys.
- //
- // NOTE: this use of three inputs to generating _each_ set
- // of ciphers slows things down, but it does increase the
- // security since each connection in the session can hold
- // its own authenticated (and strong) keys. One could make
- // creation of a session a rare thing...
- //
- clnt_random = mesg.clnt_random;
- svr_random = new RandomCookie(sslContext.getSecureRandom());
- m1.svr_random = svr_random;
-
- session = null; // forget about the current session
- //
- // Here we go down either of two paths: (a) the fast one, where
- // the client's asked to rejoin an existing session, and the server
- // permits this; (b) the other one, where a new session is created.
- //
- if (mesg.sessionId.length() != 0) {
- // client is trying to resume a session, let's see...
-
- SSLSessionImpl previous = ((SSLSessionContextImpl)sslContext
- .engineGetServerSessionContext())
- .get(mesg.sessionId.getId());
- //
- // Check if we can use the fast path, resuming a session. We
- // can do so iff we have a valid record for that session, and
- // the cipher suite for that session was on the list which the
- // client requested, and if we're not forgetting any needed
- // authentication on the part of the client.
- //
- if (previous != null) {
- resumingSession = previous.isRejoinable();
-
- if (resumingSession) {
- ProtocolVersion oldVersion = previous.getProtocolVersion();
- // cannot resume session with different version
- if (oldVersion != protocolVersion) {
- resumingSession = false;
- }
- }
-
- if (resumingSession &&
- (doClientAuth == SSLEngineImpl.clauth_required)) {
- try {
- previous.getPeerPrincipal();
- } catch (SSLPeerUnverifiedException e) {
- resumingSession = false;
- }
- }
-
- // validate subject identity
- if (resumingSession) {
- CipherSuite suite = previous.getSuite();
- if (suite.keyExchange == K_KRB5 ||
- suite.keyExchange == K_KRB5_EXPORT) {
- Principal localPrincipal = previous.getLocalPrincipal();
-
- Subject subject = null;
- try {
- subject = AccessController.doPrivileged(
- new PrivilegedExceptionAction<Subject>() {
- public Subject run() throws Exception {
- return
- Krb5Helper.getServerSubject(getAccSE());
- }});
- } catch (PrivilegedActionException e) {
- subject = null;
- if (debug != null && Debug.isOn("session")) {
- System.out.println("Attempt to obtain" +
- " subject failed!");
- }
- }
-
- if (subject != null) {
- // Eliminate dependency on KerberosPrincipal
- Set<Principal> principals =
- subject.getPrincipals(Principal.class);
- if (!principals.contains(localPrincipal)) {
- resumingSession = false;
- if (debug != null && Debug.isOn("session")) {
- System.out.println("Subject identity" +
- " is not the same");
- }
- } else {
- if (debug != null && Debug.isOn("session"))
- System.out.println("Subject identity" +
- " is same");
- }
- } else {
- resumingSession = false;
- if (debug != null && Debug.isOn("session"))
- System.out.println("Kerberos credentials are" +
- " not present in the current Subject;" +
- " check if " +
- " javax.security.auth.useSubjectAsCreds" +
- " system property has been set to false");
- }
- }
- }
-
- if (resumingSession) {
- CipherSuite suite = previous.getSuite();
- // verify that the ciphersuite from the cached session
- // is in the list of client requested ciphersuites and
- // we have it enabled
- if ((isNegotiable(suite) == false) ||
- (mesg.getCipherSuites().contains(suite) == false)) {
- resumingSession = false;
- } else {
- // everything looks ok, set the ciphersuite
- // this should be done last when we are sure we
- // will resume
- setCipherSuite(suite);
- }
- }
-
- if (resumingSession) {
- session = previous;
- if (debug != null &&
- (Debug.isOn("handshake") || Debug.isOn("session"))) {
- System.out.println("%% Resuming " + session);
- }
- }
- }
- } // else client did not try to resume
-
- //
- // If client hasn't specified a session we can resume, start a
- // new one and choose its cipher suite and compression options.
- // Unless new session creation is disabled for this connection!
- //
- if (session == null) {
- if (!enableNewSession) {
- throw new SSLException("Client did not resume a session");
- }
-
- supportedCurves = (SupportedEllipticCurvesExtension)
- mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
-
- // We only need to handle the "signature_algorithm" extension
- // for full handshakes and TLS 1.2 or later.
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- SignatureAlgorithmsExtension signAlgs =
- (SignatureAlgorithmsExtension)mesg.extensions.get(
- ExtensionType.EXT_SIGNATURE_ALGORITHMS);
- if (signAlgs != null) {
- Collection<SignatureAndHashAlgorithm> peerSignAlgs =
- signAlgs.getSignAlgorithms();
- if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
- throw new SSLHandshakeException(
- "No peer supported signature algorithms");
- }
-
- Collection<SignatureAndHashAlgorithm>
- supportedPeerSignAlgs =
- SignatureAndHashAlgorithm.getSupportedAlgorithms(
- peerSignAlgs);
- if (supportedPeerSignAlgs.isEmpty()) {
- throw new SSLHandshakeException(
- "No supported signature and hash algorithm " +
- "in common");
- }
-
- setPeerSupportedSignAlgs(supportedPeerSignAlgs);
- } // else, need to use peer implicit supported signature algs
- }
-
- session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL,
- getLocalSupportedSignAlgs(),
- sslContext.getSecureRandom(),
- getHostAddressSE(), getPortSE());
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (peerSupportedSignAlgs != null) {
- session.setPeerSupportedSignatureAlgorithms(
- peerSupportedSignAlgs);
- } // else, we will set the implicit peer supported signature
- // algorithms in chooseCipherSuite()
- }
-
- // set the handshake session
- setHandshakeSessionSE(session);
-
- // choose cipher suite and corresponding private key
- chooseCipherSuite(mesg);
-
- session.setSuite(cipherSuite);
- session.setLocalPrivateKey(privateKey);
-
- // chooseCompression(mesg);
- } else {
- // set the handshake session
- setHandshakeSessionSE(session);
- }
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (resumingSession) {
- handshakeHash.setCertificateVerifyAlg(null);
- }
- handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
- }
-
- m1.cipherSuite = cipherSuite;
- m1.sessionId = session.getSessionId();
- m1.compression_method = session.getCompression();
-
- if (secureRenegotiation) {
- // For ServerHellos that are initial handshakes, then the
- // "renegotiated_connection" field in "renegotiation_info"
- // extension is of zero length.
- //
- // For ServerHellos that are renegotiating, this field contains
- // the concatenation of client_verify_data and server_verify_data.
- //
- // Note that for initial handshakes, both the clientVerifyData
- // variable and serverVerifyData variable are of zero length.
- HelloExtension serverHelloRI = new RenegotiationInfoExtension(
- clientVerifyData, serverVerifyData);
- m1.extensions.add(serverHelloRI);
- }
-
- if (debug != null && Debug.isOn("handshake")) {
- m1.print(System.out);
- System.out.println("Cipher suite: " + session.getSuite());
- }
- m1.write(output);
-
- //
- // If we are resuming a session, we finish writing handshake
- // messages right now and then finish.
- //
- if (resumingSession) {
- calculateConnectionKeys(session.getMasterSecret());
- sendChangeCipherAndFinish(false);
- return;
- }
-
-
- /*
- * SECOND, write the server Certificate(s) if we need to.
- *
- * NOTE: while an "anonymous RSA" mode is explicitly allowed by
- * the protocol, we can't support it since all of the SSL flavors
- * defined in the protocol spec are explicitly stated to require
- * using RSA certificates.
- */
- if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
- // Server certificates are omitted for Kerberos ciphers
-
- } else if ((keyExchange != K_DH_ANON) && (keyExchange != K_ECDH_ANON)) {
- if (certs == null) {
- throw new RuntimeException("no certificates");
- }
-
- CertificateMsg m2 = new CertificateMsg(certs);
-
- /*
- * Set local certs in the SSLSession, output
- * debug info, and then actually write to the client.
- */
- session.setLocalCertificates(certs);
- if (debug != null && Debug.isOn("handshake")) {
- m2.print(System.out);
- }
- m2.write(output);
-
- // XXX has some side effects with OS TCP buffering,
- // leave it out for now
-
- // let client verify chain in the meantime...
- // output.flush();
- } else {
- if (certs != null) {
- throw new RuntimeException("anonymous keyexchange with certs");
- }
- }
-
- /*
- * THIRD, the ServerKeyExchange message ... iff it's needed.
- *
- * It's usually needed unless there's an encryption-capable
- * RSA cert, or a D-H cert. The notable exception is that
- * exportable ciphers used with big RSA keys need to downgrade
- * to use short RSA keys, even when the key/cert encrypts OK.
- */
-
- ServerKeyExchange m3;
- switch (keyExchange) {
- case K_RSA:
- case K_KRB5:
- case K_KRB5_EXPORT:
- // no server key exchange for RSA or KRB5 ciphersuites
- m3 = null;
- break;
- case K_RSA_EXPORT:
- if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) {
- try {
- m3 = new RSA_ServerKeyExchange(
- tempPublicKey, privateKey,
- clnt_random, svr_random,
- sslContext.getSecureRandom());
- privateKey = tempPrivateKey;
- } catch (GeneralSecurityException e) {
- throwSSLException
- ("Error generating RSA server key exchange", e);
- m3 = null; // make compiler happy
- }
- } else {
- // RSA_EXPORT with short key, don't need ServerKeyExchange
- m3 = null;
- }
- break;
- case K_DHE_RSA:
- case K_DHE_DSS:
- try {
- m3 = new DH_ServerKeyExchange(dh,
- privateKey,
- clnt_random.random_bytes,
- svr_random.random_bytes,
- sslContext.getSecureRandom(),
- preferableSignatureAlgorithm,
- protocolVersion);
- } catch (GeneralSecurityException e) {
- throwSSLException("Error generating DH server key exchange", e);
- m3 = null; // make compiler happy
- }
- break;
- case K_DH_ANON:
- m3 = new DH_ServerKeyExchange(dh, protocolVersion);
- break;
- case K_ECDHE_RSA:
- case K_ECDHE_ECDSA:
- case K_ECDH_ANON:
- try {
- m3 = new ECDH_ServerKeyExchange(ecdh,
- privateKey,
- clnt_random.random_bytes,
- svr_random.random_bytes,
- sslContext.getSecureRandom(),
- preferableSignatureAlgorithm,
- protocolVersion);
- } catch (GeneralSecurityException e) {
- throwSSLException(
- "Error generating ECDH server key exchange", e);
- m3 = null; // make compiler happy
- }
- break;
- case K_ECDH_RSA:
- case K_ECDH_ECDSA:
- // ServerKeyExchange not used for fixed ECDH
- m3 = null;
- break;
- default:
- throw new RuntimeException("internal error: " + keyExchange);
- }
- if (m3 != null) {
- if (debug != null && Debug.isOn("handshake")) {
- m3.print(System.out);
- }
- m3.write(output);
- }
-
- //
- // FOURTH, the CertificateRequest message. The details of
- // the message can be affected by the key exchange algorithm
- // in use. For example, certs with fixed Diffie-Hellman keys
- // are only useful with the DH_DSS and DH_RSA key exchange
- // algorithms.
- //
- // Needed only if server requires client to authenticate self.
- // Illegal for anonymous flavors, so we need to check that.
- //
- // CertificateRequest is omitted for Kerberos ciphers
- if (doClientAuth != SSLEngineImpl.clauth_none &&
- keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON &&
- keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) {
-
- CertificateRequest m4;
- X509Certificate caCerts[];
-
- Collection<SignatureAndHashAlgorithm> localSignAlgs = null;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- // We currently use all local upported signature and hash
- // algorithms. However, to minimize the computation cost
- // of requested hash algorithms, we may use a restricted
- // set of signature algorithms in the future.
- localSignAlgs = getLocalSupportedSignAlgs();
- if (localSignAlgs.isEmpty()) {
- throw new SSLHandshakeException(
- "No supported signature algorithm");
- }
-
- Set<String> localHashAlgs =
- SignatureAndHashAlgorithm.getHashAlgorithmNames(
- localSignAlgs);
- if (localHashAlgs.isEmpty()) {
- throw new SSLHandshakeException(
- "No supported signature algorithm");
- }
- handshakeHash.restrictCertificateVerifyAlgs(localHashAlgs);
- }
-
- caCerts = sslContext.getX509TrustManager().getAcceptedIssuers();
- m4 = new CertificateRequest(caCerts, keyExchange,
- localSignAlgs, protocolVersion);
-
- if (debug != null && Debug.isOn("handshake")) {
- m4.print(System.out);
- }
- m4.write(output);
- } else {
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- handshakeHash.setCertificateVerifyAlg(null);
- }
- }
-
- /*
- * FIFTH, say ServerHelloDone.
- */
- ServerHelloDone m5 = new ServerHelloDone();
-
- if (debug != null && Debug.isOn("handshake")) {
- m5.print(System.out);
- }
- m5.write(output);
-
- /*
- * Flush any buffered messages so the client will see them.
- * Ideally, all the messages above go in a single network level
- * message to the client. Without big Certificate chains, it's
- * going to be the common case.
- */
- output.flush();
- }
-
- /*
- * Choose cipher suite from among those supported by client. Sets
- * the cipherSuite and keyExchange variables.
- */
- private void chooseCipherSuite(ClientHello mesg) throws IOException {
- for (CipherSuite suite : mesg.getCipherSuites().collection()) {
- if (isNegotiable(suite) == false) {
- continue;
- }
-
- if (doClientAuth == SSLEngineImpl.clauth_required) {
- if ((suite.keyExchange == K_DH_ANON) ||
- (suite.keyExchange == K_ECDH_ANON)) {
- continue;
- }
- }
- if (trySetCipherSuite(suite) == false) {
- continue;
- }
- return;
- }
- fatalSE(Alerts.alert_handshake_failure,
- "no cipher suites in common");
- }
-
- /**
- * Set the given CipherSuite, if possible. Return the result.
- * The call succeeds if the CipherSuite is available and we have
- * the necessary certificates to complete the handshake. We don't
- * check if the CipherSuite is actually enabled.
- *
- * If successful, this method also generates ephemeral keys if
- * required for this ciphersuite. This may take some time, so this
- * method should only be called if you really want to use the
- * CipherSuite.
- *
- * This method is called from chooseCipherSuite() in this class.
- */
- boolean trySetCipherSuite(CipherSuite suite) {
- /*
- * If we're resuming a session we know we can
- * support this key exchange algorithm and in fact
- * have already cached the result of it in
- * the session state.
- */
- if (resumingSession) {
- return true;
- }
-
- if (suite.isNegotiable() == false) {
- return false;
- }
-
- // must not negotiate the obsoleted weak cipher suites.
- if (protocolVersion.v >= suite.obsoleted) {
- return false;
- }
-
- // must not negotiate unsupported cipher suites.
- if (protocolVersion.v < suite.supported) {
- return false;
- }
-
- KeyExchange keyExchange = suite.keyExchange;
-
- // null out any existing references
- privateKey = null;
- certs = null;
- dh = null;
- tempPrivateKey = null;
- tempPublicKey = null;
-
- Collection<SignatureAndHashAlgorithm> supportedSignAlgs = null;
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (peerSupportedSignAlgs != null) {
- supportedSignAlgs = peerSupportedSignAlgs;
- } else {
- SignatureAndHashAlgorithm algorithm = null;
-
- // we may optimize the performance
- switch (keyExchange) {
- // If the negotiated key exchange algorithm is one of
- // (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA),
- // behave as if client had sent the value {sha1,rsa}.
- case K_RSA:
- case K_DHE_RSA:
- case K_DH_RSA:
- // case K_RSA_PSK:
- case K_ECDH_RSA:
- case K_ECDHE_RSA:
- algorithm = SignatureAndHashAlgorithm.valueOf(
- HashAlgorithm.SHA1.value,
- SignatureAlgorithm.RSA.value, 0);
- break;
- // If the negotiated key exchange algorithm is one of
- // (DHE_DSS, DH_DSS), behave as if the client had
- // sent the value {sha1,dsa}.
- case K_DHE_DSS:
- case K_DH_DSS:
- algorithm = SignatureAndHashAlgorithm.valueOf(
- HashAlgorithm.SHA1.value,
- SignatureAlgorithm.DSA.value, 0);
- break;
- // If the negotiated key exchange algorithm is one of
- // (ECDH_ECDSA, ECDHE_ECDSA), behave as if the client
- // had sent value {sha1,ecdsa}.
- case K_ECDH_ECDSA:
- case K_ECDHE_ECDSA:
- algorithm = SignatureAndHashAlgorithm.valueOf(
- HashAlgorithm.SHA1.value,
- SignatureAlgorithm.ECDSA.value, 0);
- break;
- default:
- // no peer supported signature algorithms
- }
-
- if (algorithm == null) {
- supportedSignAlgs =
- Collections.<SignatureAndHashAlgorithm>emptySet();
- } else {
- supportedSignAlgs =
- new ArrayList<SignatureAndHashAlgorithm>(1);
- supportedSignAlgs.add(algorithm);
- }
-
- // Sets the peer supported signature algorithm to use in KM
- // temporarily.
- session.setPeerSupportedSignatureAlgorithms(supportedSignAlgs);
- }
- }
-
- switch (keyExchange) {
- case K_RSA:
- // need RSA certs for authentication
- if (setupPrivateKeyAndChain("RSA") == false) {
- return false;
- }
- break;
- case K_RSA_EXPORT:
- // need RSA certs for authentication
- if (setupPrivateKeyAndChain("RSA") == false) {
- return false;
- }
-
- try {
- if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) {
- if (!setupEphemeralRSAKeys(suite.exportable)) {
- return false;
- }
- }
- } catch (RuntimeException e) {
- // could not determine keylength, ignore key
- return false;
- }
- break;
- case K_DHE_RSA:
- // need RSA certs for authentication
- if (setupPrivateKeyAndChain("RSA") == false) {
- return false;
- }
-
- // get preferable peer signature algorithm for server key exchange
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.getPreferableAlgorithm(
- supportedSignAlgs, "RSA", privateKey);
- if (preferableSignatureAlgorithm == null) {
- return false;
- }
- }
-
- setupEphemeralDHKeys(suite.exportable);
- break;
- case K_ECDHE_RSA:
- // need RSA certs for authentication
- if (setupPrivateKeyAndChain("RSA") == false) {
- return false;
- }
-
- // get preferable peer signature algorithm for server key exchange
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.getPreferableAlgorithm(
- supportedSignAlgs, "RSA", privateKey);
- if (preferableSignatureAlgorithm == null) {
- return false;
- }
- }
-
- if (setupEphemeralECDHKeys() == false) {
- return false;
- }
- break;
- case K_DHE_DSS:
- // get preferable peer signature algorithm for server key exchange
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.getPreferableAlgorithm(
- supportedSignAlgs, "DSA");
- if (preferableSignatureAlgorithm == null) {
- return false;
- }
- }
-
- // need DSS certs for authentication
- if (setupPrivateKeyAndChain("DSA") == false) {
- return false;
- }
- setupEphemeralDHKeys(suite.exportable);
- break;
- case K_ECDHE_ECDSA:
- // get preferable peer signature algorithm for server key exchange
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- preferableSignatureAlgorithm =
- SignatureAndHashAlgorithm.getPreferableAlgorithm(
- supportedSignAlgs, "ECDSA");
- if (preferableSignatureAlgorithm == null) {
- return false;
- }
- }
-
- // need EC cert signed using EC
- if (setupPrivateKeyAndChain("EC_EC") == false) {
- return false;
- }
- if (setupEphemeralECDHKeys() == false) {
- return false;
- }
- break;
- case K_ECDH_RSA:
- // need EC cert signed using RSA
- if (setupPrivateKeyAndChain("EC_RSA") == false) {
- return false;
- }
- setupStaticECDHKeys();
- break;
- case K_ECDH_ECDSA:
- // need EC cert signed using EC
- if (setupPrivateKeyAndChain("EC_EC") == false) {
- return false;
- }
- setupStaticECDHKeys();
- break;
- case K_KRB5:
- case K_KRB5_EXPORT:
- // need Kerberos Key
- if (!setupKerberosKeys()) {
- return false;
- }
- break;
- case K_DH_ANON:
- // no certs needed for anonymous
- setupEphemeralDHKeys(suite.exportable);
- break;
- case K_ECDH_ANON:
- // no certs needed for anonymous
- if (setupEphemeralECDHKeys() == false) {
- return false;
- }
- break;
- default:
- // internal error, unknown key exchange
- throw new RuntimeException("Unrecognized cipherSuite: " + suite);
- }
- setCipherSuite(suite);
-
- // set the peer implicit supported signature algorithms
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (peerSupportedSignAlgs == null) {
- setPeerSupportedSignAlgs(supportedSignAlgs);
- // we had alreay update the session
- }
- }
- return true;
- }
-
- /*
- * Get some "ephemeral" RSA keys for this context. This means
- * generating them if it's not already been done.
- *
- * Note that we currently do not implement any ciphersuites that use
- * strong ephemeral RSA. (We do not support the EXPORT1024 ciphersuites
- * and standard RSA ciphersuites prohibit ephemeral mode for some reason)
- * This means that export is always true and 512 bit keys are generated.
- */
- private boolean setupEphemeralRSAKeys(boolean export) {
- KeyPair kp = sslContext.getEphemeralKeyManager().
- getRSAKeyPair(export, sslContext.getSecureRandom());
- if (kp == null) {
- return false;
- } else {
- tempPublicKey = kp.getPublic();
- tempPrivateKey = kp.getPrivate();
- return true;
- }
- }
-
- /*
- * Acquire some "ephemeral" Diffie-Hellman keys for this handshake.
- * We don't reuse these, for improved forward secrecy.
- */
- private void setupEphemeralDHKeys(boolean export) {
- /*
- * Diffie-Hellman keys ... we use 768 bit private keys due
- * to the "use twice as many key bits as bits you want secret"
- * rule of thumb, assuming we want the same size premaster
- * secret with Diffie-Hellman and RSA key exchanges. Except
- * that exportable ciphers max out at 512 bits modulus values.
- */
- dh = new DHCrypt((export ? 512 : 768), sslContext.getSecureRandom());
- }
-
- // Setup the ephemeral ECDH parameters.
- // If we cannot continue because we do not support any of the curves that
- // the client requested, return false. Otherwise (all is well), return true.
- private boolean setupEphemeralECDHKeys() {
- int index = -1;
- if (supportedCurves != null) {
- // if the client sent the supported curves extension, pick the
- // first one that we support;
- for (int curveId : supportedCurves.curveIds()) {
- if (SupportedEllipticCurvesExtension.isSupported(curveId)) {
- index = curveId;
- break;
- }
- }
- if (index < 0) {
- // no match found, cannot use this ciphersuite
- return false;
- }
- } else {
- // pick our preference
- index = SupportedEllipticCurvesExtension.DEFAULT.curveIds()[0];
- }
- String oid = SupportedEllipticCurvesExtension.getCurveOid(index);
- ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom());
- return true;
- }
-
- private void setupStaticECDHKeys() {
- // don't need to check whether the curve is supported, already done
- // in setupPrivateKeyAndChain().
- ecdh = new ECDHCrypt(privateKey, certs[0].getPublicKey());
- }
-
- /**
- * Retrieve the server key and certificate for the specified algorithm
- * from the KeyManager and set the instance variables.
- *
- * @return true if successful, false if not available or invalid
- */
- private boolean setupPrivateKeyAndChain(String algorithm) {
- X509ExtendedKeyManager km = sslContext.getX509KeyManager();
- String alias;
- if (conn != null) {
- alias = km.chooseServerAlias(algorithm, null, conn);
- } else {
- alias = km.chooseEngineServerAlias(algorithm, null, engine);
- }
- if (alias == null) {
- return false;
- }
- PrivateKey tempPrivateKey = km.getPrivateKey(alias);
- if (tempPrivateKey == null) {
- return false;
- }
- X509Certificate[] tempCerts = km.getCertificateChain(alias);
- if ((tempCerts == null) || (tempCerts.length == 0)) {
- return false;
- }
- String keyAlgorithm = algorithm.split("_")[0];
- PublicKey publicKey = tempCerts[0].getPublicKey();
- if ((tempPrivateKey.getAlgorithm().equals(keyAlgorithm) == false)
- || (publicKey.getAlgorithm().equals(keyAlgorithm) == false)) {
- return false;
- }
- // For ECC certs, check whether we support the EC domain parameters.
- // If the client sent a SupportedEllipticCurves ClientHello extension,
- // check against that too.
- if (keyAlgorithm.equals("EC")) {
- if (publicKey instanceof ECPublicKey == false) {
- return false;
- }
- ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
- int index = SupportedEllipticCurvesExtension.getCurveIndex(params);
- if (SupportedEllipticCurvesExtension.isSupported(index) == false) {
- return false;
- }
- if ((supportedCurves != null) && !supportedCurves.contains(index)) {
- return false;
- }
- }
- this.privateKey = tempPrivateKey;
- this.certs = tempCerts;
- return true;
- }
-
- /**
- * Retrieve the Kerberos key for the specified server principal
- * from the JAAS configuration file.
- *
- * @return true if successful, false if not available or invalid
- */
- private boolean setupKerberosKeys() {
- if (kerberosKeys != null) {
- return true;
- }
- try {
- final AccessControlContext acc = getAccSE();
- kerberosKeys = AccessController.doPrivileged(
- // Eliminate dependency on KerberosKey
- new PrivilegedExceptionAction<SecretKey[]>() {
- public SecretKey[] run() throws Exception {
- // get kerberos key for the default principal
- return Krb5Helper.getServerKeys(acc);
- }});
-
- // check permission to access and use the secret key of the
- // Kerberized "host" service
- if (kerberosKeys != null && kerberosKeys.length > 0) {
- if (debug != null && Debug.isOn("handshake")) {
- for (SecretKey k: kerberosKeys) {
- System.out.println("Using Kerberos key: " +
- k);
- }
- }
-
- String serverPrincipal =
- Krb5Helper.getServerPrincipalName(kerberosKeys[0]);
- SecurityManager sm = System.getSecurityManager();
- try {
- if (sm != null) {
- // Eliminate dependency on ServicePermission
- sm.checkPermission(Krb5Helper.getServicePermission(
- serverPrincipal, "accept"), acc);
- }
- } catch (SecurityException se) {
- kerberosKeys = null;
- // %%% destroy keys? or will that affect Subject?
- if (debug != null && Debug.isOn("handshake"))
- System.out.println("Permission to access Kerberos"
- + " secret key denied");
- return false;
- }
- }
- return (kerberosKeys != null && kerberosKeys.length > 0);
- } catch (PrivilegedActionException e) {
- // Likely exception here is LoginExceptin
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("Attempt to obtain Kerberos key failed: "
- + e.toString());
- }
- return false;
- }
- }
-
- /*
- * For Kerberos ciphers, the premaster secret is encrypted using
- * the session key. See RFC 2712.
- */
- private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg)
- throws IOException {
-
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- // Record the principals involved in exchange
- session.setPeerPrincipal(mesg.getPeerPrincipal());
- session.setLocalPrincipal(mesg.getLocalPrincipal());
-
- byte[] b = mesg.getUnencryptedPreMasterSecret();
- return new SecretKeySpec(b, "TlsPremasterSecret");
- }
-
- /*
- * Diffie Hellman key exchange is used when the server presented
- * D-H parameters in its certificate (signed using RSA or DSS/DSA),
- * or else the server presented no certificate but sent D-H params
- * in a ServerKeyExchange message. Use of D-H is specified by the
- * cipher suite chosen.
- *
- * The message optionally contains the client's D-H public key (if
- * it wasn't not sent in a client certificate). As always with D-H,
- * if a client and a server have each other's D-H public keys and
- * they use common algorithm parameters, they have a shared key
- * that's derived via the D-H calculation. That key becomes the
- * pre-master secret.
- */
- private SecretKey clientKeyExchange(DHClientKeyExchange mesg)
- throws IOException {
-
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- return dh.getAgreedSecret(mesg.getClientPublicKey(), false);
- }
-
- private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg)
- throws IOException {
-
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- return ecdh.getAgreedSecret(mesg.getEncodedPoint());
- }
-
- /*
- * Client wrote a message to verify the certificate it sent earlier.
- *
- * Note that this certificate isn't involved in key exchange. Client
- * authentication messages are included in the checksums used to
- * validate the handshake (e.g. Finished messages). Other than that,
- * the _exact_ identity of the client is less fundamental to protocol
- * security than its role in selecting keys via the pre-master secret.
- */
- private void clientCertificateVerify(CertificateVerify mesg)
- throws IOException {
-
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- SignatureAndHashAlgorithm signAlg =
- mesg.getPreferableSignatureAlgorithm();
- if (signAlg == null) {
- throw new SSLHandshakeException(
- "Illegal CertificateVerify message");
- }
-
- String hashAlg =
- SignatureAndHashAlgorithm.getHashAlgorithmName(signAlg);
- if (hashAlg == null || hashAlg.length() == 0) {
- throw new SSLHandshakeException(
- "No supported hash algorithm");
- }
-
- handshakeHash.setCertificateVerifyAlg(hashAlg);
- }
-
- try {
- PublicKey publicKey =
- session.getPeerCertificates()[0].getPublicKey();
-
- boolean valid = mesg.verify(protocolVersion, handshakeHash,
- publicKey, session.getMasterSecret());
- if (valid == false) {
- fatalSE(Alerts.alert_bad_certificate,
- "certificate verify message signature error");
- }
- } catch (GeneralSecurityException e) {
- fatalSE(Alerts.alert_bad_certificate,
- "certificate verify format error", e);
- }
-
- // reset the flag for clientCertificateVerify message
- needClientVerify = false;
- }
-
-
- /*
- * Client writes "finished" at the end of its handshake, after cipher
- * spec is changed. We verify it and then send ours.
- *
- * When we're resuming a session, we'll have already sent our own
- * Finished message so just the verification is needed.
- */
- private void clientFinished(Finished mesg) throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- /*
- * Verify if client did send the certificate when client
- * authentication was required, otherwise server should not proceed
- */
- if (doClientAuth == SSLEngineImpl.clauth_required) {
- // get X500Principal of the end-entity certificate for X509-based
- // ciphersuites, or Kerberos principal for Kerberos ciphersuites
- session.getPeerPrincipal();
- }
-
- /*
- * Verify if client did send clientCertificateVerify message following
- * the client Certificate, otherwise server should not proceed
- */
- if (needClientVerify) {
- fatalSE(Alerts.alert_handshake_failure,
- "client did not send certificate verify message");
- }
-
- /*
- * Verify the client's message with the "before" digest of messages,
- * and forget about continuing to use that digest.
- */
- boolean verified = mesg.verify(handshakeHash, Finished.CLIENT,
- session.getMasterSecret());
-
- if (!verified) {
- fatalSE(Alerts.alert_handshake_failure,
- "client 'finished' message doesn't verify");
- // NOTREACHED
- }
-
- /*
- * save client verify data for secure renegotiation
- */
- if (secureRenegotiation) {
- clientVerifyData = mesg.getVerifyData();
- }
-
- /*
- * OK, it verified. If we're doing the full handshake, add that
- * "Finished" message to the hash of handshake messages, then send
- * the change_cipher_spec and Finished message.
- */
- if (!resumingSession) {
- input.digestNow();
- sendChangeCipherAndFinish(true);
- }
-
- /*
- * Update the session cache only after the handshake completed, else
- * we're open to an attack against a partially completed handshake.
- */
- session.setLastAccessedTime(System.currentTimeMillis());
- if (!resumingSession && session.isRejoinable()) {
- ((SSLSessionContextImpl)sslContext.engineGetServerSessionContext())
- .put(session);
- if (debug != null && Debug.isOn("session")) {
- System.out.println(
- "%% Cached server session: " + session);
- }
- } else if (!resumingSession &&
- debug != null && Debug.isOn("session")) {
- System.out.println(
- "%% Didn't cache non-resumable server session: "
- + session);
- }
- }
-
- /*
- * Compute finished message with the "server" digest (and then forget
- * about that digest, it can't be used again).
- */
- private void sendChangeCipherAndFinish(boolean finishedTag)
- throws IOException {
-
- output.flush();
-
- Finished mesg = new Finished(protocolVersion, handshakeHash,
- Finished.SERVER, session.getMasterSecret(), cipherSuite);
-
- /*
- * Send the change_cipher_spec record; then our Finished handshake
- * message will be the last handshake message. Flush, and now we
- * are ready for application data!!
- */
- sendChangeCipherSpec(mesg, finishedTag);
-
- /*
- * save server verify data for secure renegotiation
- */
- if (secureRenegotiation) {
- serverVerifyData = mesg.getVerifyData();
- }
-
- /*
- * Update state machine so client MUST send 'finished' next
- * The update should only take place if it is not in the fast
- * handshake mode since the server has to wait for a finished
- * message from the client.
- */
- if (finishedTag) {
- state = HandshakeMessage.ht_finished;
- }
- }
-
-
- /*
- * Returns a HelloRequest message to kickstart renegotiations
- */
- HandshakeMessage getKickstartMessage() {
- return new HelloRequest();
- }
-
-
- /*
- * Fault detected during handshake.
- */
- void handshakeAlert(byte description) throws SSLProtocolException {
-
- String message = Alerts.alertDescription(description);
-
- if (debug != null && Debug.isOn("handshake")) {
- System.out.println("SSL -- handshake alert: "
- + message);
- }
-
- /*
- * It's ok to get a no_certificate alert from a client of which
- * we *requested* authentication information.
- * However, if we *required* it, then this is not acceptable.
- *
- * Anyone calling getPeerCertificates() on the
- * session will get an SSLPeerUnverifiedException.
- */
- if ((description == Alerts.alert_no_certificate) &&
- (doClientAuth == SSLEngineImpl.clauth_requested)) {
- return;
- }
-
- throw new SSLProtocolException("handshake alert: " + message);
- }
-
- /*
- * RSA key exchange is normally used. The client encrypts a "pre-master
- * secret" with the server's public key, from the Certificate (or else
- * ServerKeyExchange) message that was sent to it by the server. That's
- * decrypted using the private key before we get here.
- */
- private SecretKey clientKeyExchange(RSAClientKeyExchange mesg)
- throws IOException {
-
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
- return mesg.preMaster;
- }
-
- /*
- * Verify the certificate sent by the client. We'll only get one if we
- * sent a CertificateRequest to request client authentication. If we
- * are in TLS mode, the client may send a message with no certificates
- * to indicate it does not have an appropriate chain. (In SSLv3 mode,
- * it would send a no certificate alert).
- */
- private void clientCertificate(CertificateMsg mesg) throws IOException {
- if (debug != null && Debug.isOn("handshake")) {
- mesg.print(System.out);
- }
-
- X509Certificate[] peerCerts = mesg.getCertificateChain();
-
- if (peerCerts.length == 0) {
- /*
- * If the client authentication is only *REQUESTED* (e.g.
- * not *REQUIRED*, this is an acceptable condition.)
- */
- if (doClientAuth == SSLEngineImpl.clauth_requested) {
- // Smart (aka stupid) to forecast that no CertificateVerify
- // message will be received.
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- handshakeHash.setCertificateVerifyAlg(null);
- }
- return;
- } else {
- fatalSE(Alerts.alert_bad_certificate,
- "null cert chain");
- }
- }
-
- // ask the trust manager to verify the chain
- X509TrustManager tm = sslContext.getX509TrustManager();
-
- try {
- // find out the types of client authentication used
- PublicKey key = peerCerts[0].getPublicKey();
- String keyAlgorithm = key.getAlgorithm();
- String authType;
- if (keyAlgorithm.equals("RSA")) {
- authType = "RSA";
- } else if (keyAlgorithm.equals("DSA")) {
- authType = "DSA";
- } else if (keyAlgorithm.equals("EC")) {
- authType = "EC";
- } else {
- // unknown public key type
- authType = "UNKNOWN";
- }
-
- if (tm instanceof X509ExtendedTrustManager) {
- if (conn != null) {
- ((X509ExtendedTrustManager)tm).checkClientTrusted(
- peerCerts.clone(),
- authType,
- conn);
- } else {
- ((X509ExtendedTrustManager)tm).checkClientTrusted(
- peerCerts.clone(),
- authType,
- engine);
- }
- } else {
- // Unlikely to happen, because we have wrapped the old
- // X509TrustManager with the new X509ExtendedTrustManager.
- throw new CertificateException(
- "Improper X509TrustManager implementation");
- }
- } catch (CertificateException e) {
- // This will throw an exception, so include the original error.
- fatalSE(Alerts.alert_certificate_unknown, e);
- }
- // set the flag for clientCertificateVerify message
- needClientVerify = true;
-
- session.setPeerCertificates(peerCerts);
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SessionId.java b/ojluni/src/main/java/sun/security/ssl/SessionId.java
deleted file mode 100755
index 1707d42..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SessionId.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.security.SecureRandom;
-
-/**
- * Encapsulates an SSL session ID. SSL Session IDs are not reused by
- * servers during the lifetime of any sessions it created. Sessions may
- * be used by many connections, either concurrently (for example, two
- * connections to a web server at the same time) or sequentially (over as
- * long a time period as is allowed by a given server).
- *
- * @author Satish Dharmaraj
- * @author David Brownell
- */
-final
-class SessionId
-{
- private byte sessionId []; // max 32 bytes
-
- /** Constructs a new session ID ... perhaps for a rejoinable session */
- SessionId (boolean isRejoinable, SecureRandom generator)
- {
- if (isRejoinable)
- // this will be unique, it's a timestamp plus much randomness
- sessionId = new RandomCookie (generator).random_bytes;
- else
- sessionId = new byte [0];
- }
-
- /** Constructs a session ID from a byte array (max size 32 bytes) */
- SessionId (byte sessionId [])
- { this.sessionId = sessionId; }
-
- /** Returns the length of the ID, in bytes */
- int length ()
- { return sessionId.length; }
-
- /** Returns the bytes in the ID. May be an empty array. */
- byte [] getId ()
- {
- return sessionId.clone ();
- }
-
- /** Returns the ID as a string */
- public String toString ()
- {
- int len = sessionId.length;
- StringBuffer s = new StringBuffer (10 + 2 * len);
-
- s.append ("{");
- for (int i = 0; i < len; i++) {
- s.append (0x0ff & sessionId [i]);
- if (i != (len - 1))
- s.append (", ");
- }
- s.append ("}");
- return s.toString ();
- }
-
-
- /** Returns a value which is the same for session IDs which are equal */
- public int hashCode ()
- {
- int retval = 0;
-
- for (int i = 0; i < sessionId.length; i++)
- retval += sessionId [i];
- return retval;
- }
-
- /** Returns true if the parameter is the same session ID */
- public boolean equals (Object obj)
- {
- if (!(obj instanceof SessionId))
- return false;
-
- SessionId s = (SessionId) obj;
- byte b [] = s.getId ();
-
- if (b.length != sessionId.length)
- return false;
- for (int i = 0; i < sessionId.length; i++) {
- if (b [i] != sessionId [i])
- return false;
- }
- return true;
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SignatureAndHashAlgorithm.java b/ojluni/src/main/java/sun/security/ssl/SignatureAndHashAlgorithm.java
deleted file mode 100755
index 043b9b1..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SignatureAndHashAlgorithm.java
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.security.AlgorithmConstraints;
-import java.security.CryptoPrimitive;
-import java.security.PrivateKey;
-
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.EnumSet;
-import java.util.TreeMap;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.ArrayList;
-
-import sun.security.util.KeyUtil;
-
-/**
- * Signature and hash algorithm.
- *
- * [RFC5246] The client uses the "signature_algorithms" extension to
- * indicate to the server which signature/hash algorithm pairs may be
- * used in digital signatures. The "extension_data" field of this
- * extension contains a "supported_signature_algorithms" value.
- *
- * enum {
- * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
- * sha512(6), (255)
- * } HashAlgorithm;
- *
- * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) }
- * SignatureAlgorithm;
- *
- * struct {
- * HashAlgorithm hash;
- * SignatureAlgorithm signature;
- * } SignatureAndHashAlgorithm;
- */
-final class SignatureAndHashAlgorithm {
-
- // minimum priority for default enabled algorithms
- final static int SUPPORTED_ALG_PRIORITY_MAX_NUM = 0x00F0;
-
- // performance optimization
- private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
- EnumSet.of(CryptoPrimitive.SIGNATURE);
-
- // supported pairs of signature and hash algorithm
- private final static Map<Integer, SignatureAndHashAlgorithm> supportedMap;
- private final static Map<Integer, SignatureAndHashAlgorithm> priorityMap;
-
- // the hash algorithm
- private HashAlgorithm hash;
-
- // the signature algorithm
- private SignatureAlgorithm signature;
-
- // id in 16 bit MSB format, i.e. 0x0603 for SHA512withECDSA
- private int id;
-
- // the standard algorithm name, for example "SHA512withECDSA"
- private String algorithm;
-
- // Priority for the preference order. The lower the better.
- //
- // If the algorithm is unsupported, its priority should be bigger
- // than SUPPORTED_ALG_PRIORITY_MAX_NUM.
- private int priority;
-
- // constructor for supported algorithm
- private SignatureAndHashAlgorithm(HashAlgorithm hash,
- SignatureAlgorithm signature, String algorithm, int priority) {
- this.hash = hash;
- this.signature = signature;
- this.algorithm = algorithm;
- this.id = ((hash.value & 0xFF) << 8) | (signature.value & 0xFF);
- this.priority = priority;
- }
-
- // constructor for unsupported algorithm
- private SignatureAndHashAlgorithm(String algorithm, int id, int sequence) {
- this.hash = HashAlgorithm.valueOf((id >> 8) & 0xFF);
- this.signature = SignatureAlgorithm.valueOf(id & 0xFF);
- this.algorithm = algorithm;
- this.id = id;
-
- // add one more to the sequece number, in case that the number is zero
- this.priority = SUPPORTED_ALG_PRIORITY_MAX_NUM + sequence + 1;
- }
-
- // Note that we do not use the sequence argument for supported algorithms,
- // so please don't sort by comparing the objects read from handshake
- // messages.
- static SignatureAndHashAlgorithm valueOf(int hash,
- int signature, int sequence) {
- hash &= 0xFF;
- signature &= 0xFF;
-
- int id = (hash << 8) | signature;
- SignatureAndHashAlgorithm signAlg = supportedMap.get(id);
- if (signAlg == null) {
- // unsupported algorithm
- signAlg = new SignatureAndHashAlgorithm(
- "Unknown (hash:0x" + Integer.toString(hash, 16) +
- ", signature:0x" + Integer.toString(signature, 16) + ")",
- id, sequence);
- }
-
- return signAlg;
- }
-
- int getHashValue() {
- return (id >> 8) & 0xFF;
- }
-
- int getSignatureValue() {
- return id & 0xFF;
- }
-
- String getAlgorithmName() {
- return algorithm;
- }
-
- // return the size of a SignatureAndHashAlgorithm structure in TLS record
- static int sizeInRecord() {
- return 2;
- }
-
- // Get local supported algorithm collection complying to
- // algorithm constraints
- static Collection<SignatureAndHashAlgorithm>
- getSupportedAlgorithms(AlgorithmConstraints constraints) {
-
- Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>();
- synchronized (priorityMap) {
- for (SignatureAndHashAlgorithm sigAlg : priorityMap.values()) {
- if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM &&
- constraints.permits(SIGNATURE_PRIMITIVE_SET,
- sigAlg.algorithm, null)) {
- supported.add(sigAlg);
- }
- }
- }
-
- return supported;
- }
-
- // Get supported algorithm collection from an untrusted collection
- static Collection<SignatureAndHashAlgorithm> getSupportedAlgorithms(
- Collection<SignatureAndHashAlgorithm> algorithms ) {
- Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>();
- for (SignatureAndHashAlgorithm sigAlg : algorithms) {
- if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) {
- supported.add(sigAlg);
- }
- }
-
- return supported;
- }
-
- static String[] getAlgorithmNames(
- Collection<SignatureAndHashAlgorithm> algorithms) {
- ArrayList<String> algorithmNames = new ArrayList<>();
- if (algorithms != null) {
- for (SignatureAndHashAlgorithm sigAlg : algorithms) {
- algorithmNames.add(sigAlg.algorithm);
- }
- }
-
- String[] array = new String[algorithmNames.size()];
- return algorithmNames.toArray(array);
- }
-
- static Set<String> getHashAlgorithmNames(
- Collection<SignatureAndHashAlgorithm> algorithms) {
- Set<String> algorithmNames = new HashSet<>();
- if (algorithms != null) {
- for (SignatureAndHashAlgorithm sigAlg : algorithms) {
- if (sigAlg.hash.value > 0) {
- algorithmNames.add(sigAlg.hash.standardName);
- }
- }
- }
-
- return algorithmNames;
- }
-
- static String getHashAlgorithmName(SignatureAndHashAlgorithm algorithm) {
- return algorithm.hash.standardName;
- }
-
- private static void supports(HashAlgorithm hash,
- SignatureAlgorithm signature, String algorithm, int priority) {
-
- SignatureAndHashAlgorithm pair =
- new SignatureAndHashAlgorithm(hash, signature, algorithm, priority);
- if (supportedMap.put(pair.id, pair) != null) {
- throw new RuntimeException(
- "Duplicate SignatureAndHashAlgorithm definition, id: " +
- pair.id);
- }
- if (priorityMap.put(pair.priority, pair) != null) {
- throw new RuntimeException(
- "Duplicate SignatureAndHashAlgorithm definition, priority: " +
- pair.priority);
- }
- }
-
- static SignatureAndHashAlgorithm getPreferableAlgorithm(
- Collection<SignatureAndHashAlgorithm> algorithms, String expected) {
-
- return SignatureAndHashAlgorithm.getPreferableAlgorithm(
- algorithms, expected, null);
- }
-
- static SignatureAndHashAlgorithm getPreferableAlgorithm(
- Collection<SignatureAndHashAlgorithm> algorithms,
- String expected, PrivateKey signingKey) {
-
- if (expected == null && !algorithms.isEmpty()) {
- for (SignatureAndHashAlgorithm sigAlg : algorithms) {
- if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM) {
- return sigAlg;
- }
- }
-
- return null; // no supported algorithm
- }
-
- if (expected == null ) {
- return null; // no expected algorithm, no supported algorithm
- }
-
- /*
- * Need to check RSA key length to match the length of hash value
- */
- int maxDigestLength = Integer.MAX_VALUE;
- if (signingKey != null &&
- "rsa".equalsIgnoreCase(signingKey.getAlgorithm()) &&
- expected.equalsIgnoreCase("rsa")) {
- /*
- * RSA keys of 512 bits have been shown to be practically
- * breakable, it does not make much sense to use the strong
- * hash algorithm for keys whose key size less than 512 bits.
- * So it is not necessary to caculate the required max digest
- * length exactly.
- *
- * If key size is greater than or equals to 768, there is no max
- * digest length limitation in currect implementation.
- *
- * If key size is greater than or equals to 512, but less than
- * 768, the digest length should be less than or equal to 32 bytes.
- *
- * If key size is less than 512, the digest length should be
- * less than or equal to 20 bytes.
- */
- int keySize = KeyUtil.getKeySize(signingKey);
- if (keySize >= 768) {
- maxDigestLength = HashAlgorithm.SHA512.length;
- } else if ((keySize >= 512) && (keySize < 768)) {
- maxDigestLength = HashAlgorithm.SHA256.length;
- } else if ((keySize > 0) && (keySize < 512)) {
- maxDigestLength = HashAlgorithm.SHA1.length;
- } // Otherwise, cannot determine the key size, prefer the most
- // perferable hash algorithm.
- }
-
- for (SignatureAndHashAlgorithm algorithm : algorithms) {
- int signValue = algorithm.id & 0xFF;
- if (expected.equalsIgnoreCase("rsa") &&
- signValue == SignatureAlgorithm.RSA.value) {
- if (algorithm.hash.length <= maxDigestLength) {
- return algorithm;
- }
- } else if (
- (expected.equalsIgnoreCase("dsa") &&
- signValue == SignatureAlgorithm.DSA.value) ||
- (expected.equalsIgnoreCase("ecdsa") &&
- signValue == SignatureAlgorithm.ECDSA.value) ||
- (expected.equalsIgnoreCase("ec") &&
- signValue == SignatureAlgorithm.ECDSA.value)) {
- return algorithm;
- }
- }
-
- return null;
- }
-
- static enum HashAlgorithm {
- UNDEFINED("undefined", "", -1, -1),
- NONE( "none", "NONE", 0, -1),
- MD5( "md5", "MD5", 1, 16),
- SHA1( "sha1", "SHA-1", 2, 20),
- SHA224( "sha224", "SHA-224", 3, 28),
- SHA256( "sha256", "SHA-256", 4, 32),
- SHA384( "sha384", "SHA-384", 5, 48),
- SHA512( "sha512", "SHA-512", 6, 64);
-
- final String name; // not the standard signature algorithm name
- // except the UNDEFINED, other names are defined
- // by TLS 1.2 protocol
- final String standardName; // the standard MessageDigest algorithm name
- final int value;
- final int length; // digest length in bytes, -1 means not applicable
-
- private HashAlgorithm(String name, String standardName,
- int value, int length) {
- this.name = name;
- this.standardName = standardName;
- this.value = value;
- this.length = length;
- }
-
- static HashAlgorithm valueOf(int value) {
- HashAlgorithm algorithm = UNDEFINED;
- switch (value) {
- case 0:
- algorithm = NONE;
- break;
- case 1:
- algorithm = MD5;
- break;
- case 2:
- algorithm = SHA1;
- break;
- case 3:
- algorithm = SHA224;
- break;
- case 4:
- algorithm = SHA256;
- break;
- case 5:
- algorithm = SHA384;
- break;
- case 6:
- algorithm = SHA512;
- break;
- }
-
- return algorithm;
- }
- }
-
- static enum SignatureAlgorithm {
- UNDEFINED("undefined", -1),
- ANONYMOUS("anonymous", 0),
- RSA( "rsa", 1),
- DSA( "dsa", 2),
- ECDSA( "ecdsa", 3);
-
- final String name; // not the standard signature algorithm name
- // except the UNDEFINED, other names are defined
- // by TLS 1.2 protocol
- final int value;
-
- private SignatureAlgorithm(String name, int value) {
- this.name = name;
- this.value = value;
- }
-
- static SignatureAlgorithm valueOf(int value) {
- SignatureAlgorithm algorithm = UNDEFINED;
- switch (value) {
- case 0:
- algorithm = ANONYMOUS;
- break;
- case 1:
- algorithm = RSA;
- break;
- case 2:
- algorithm = DSA;
- break;
- case 3:
- algorithm = ECDSA;
- break;
- }
-
- return algorithm;
- }
- }
-
- static {
- supportedMap = Collections.synchronizedSortedMap(
- new TreeMap<Integer, SignatureAndHashAlgorithm>());
- priorityMap = Collections.synchronizedSortedMap(
- new TreeMap<Integer, SignatureAndHashAlgorithm>());
-
- synchronized (supportedMap) {
- int p = SUPPORTED_ALG_PRIORITY_MAX_NUM;
- supports(HashAlgorithm.MD5, SignatureAlgorithm.RSA,
- "MD5withRSA", --p);
- supports(HashAlgorithm.SHA1, SignatureAlgorithm.DSA,
- "SHA1withDSA", --p);
- supports(HashAlgorithm.SHA1, SignatureAlgorithm.RSA,
- "SHA1withRSA", --p);
- supports(HashAlgorithm.SHA1, SignatureAlgorithm.ECDSA,
- "SHA1withECDSA", --p);
- supports(HashAlgorithm.SHA224, SignatureAlgorithm.RSA,
- "SHA224withRSA", --p);
- supports(HashAlgorithm.SHA224, SignatureAlgorithm.ECDSA,
- "SHA224withECDSA", --p);
- supports(HashAlgorithm.SHA256, SignatureAlgorithm.RSA,
- "SHA256withRSA", --p);
- supports(HashAlgorithm.SHA256, SignatureAlgorithm.ECDSA,
- "SHA256withECDSA", --p);
- supports(HashAlgorithm.SHA384, SignatureAlgorithm.RSA,
- "SHA384withRSA", --p);
- supports(HashAlgorithm.SHA384, SignatureAlgorithm.ECDSA,
- "SHA384withECDSA", --p);
- supports(HashAlgorithm.SHA512, SignatureAlgorithm.RSA,
- "SHA512withRSA", --p);
- supports(HashAlgorithm.SHA512, SignatureAlgorithm.ECDSA,
- "SHA512withECDSA", --p);
- }
- }
-}
-
diff --git a/ojluni/src/main/java/sun/security/ssl/SunJSSE.java b/ojluni/src/main/java/sun/security/ssl/SunJSSE.java
deleted file mode 100755
index 16cb35c..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SunJSSE.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.security.*;
-
-/**
- * The JSSE provider.
- *
- * The RSA implementation has been removed from JSSE, but we still need to
- * register the same algorithms for compatibility. We just point to the RSA
- * implementation in the SunRsaSign provider. This works because all classes
- * are in the bootclasspath and therefore loaded by the same classloader.
- *
- * SunJSSE now supports an experimental FIPS compliant mode when used with an
- * appropriate FIPS certified crypto provider. In FIPS mode, we:
- * . allow only TLS 1.0 or later
- * . allow only FIPS approved ciphersuites
- * . perform all crypto in the FIPS crypto provider
- *
- * It is currently not possible to use both FIPS compliant SunJSSE and
- * standard JSSE at the same time because of the various static data structures
- * we use.
- *
- * However, we do want to allow FIPS mode to be enabled at runtime and without
- * editing the java.security file. That means we need to allow
- * Security.removeProvider("SunJSSE") to work, which creates an instance of
- * this class in non-FIPS mode. That is why we delay the selection of the mode
- * as long as possible. This is until we open an SSL/TLS connection and the
- * data structures need to be initialized or until SunJSSE is initialized in
- * FIPS mode.
- *
- */
-public abstract class SunJSSE extends java.security.Provider {
-
- private static final long serialVersionUID = 3231825739635378733L;
-
- private static String info = "Sun JSSE provider" +
- "(PKCS12, SunX509 key/trust factories, SSLv3, TLSv1)";
-
- private static String fipsInfo =
- "Sun JSSE provider (FIPS mode, crypto provider ";
-
- // tri-valued flag:
- // null := no final decision made
- // false := data structures initialized in non-FIPS mode
- // true := data structures initialized in FIPS mode
- private static Boolean fips;
-
- // the FIPS certificate crypto provider that we use to perform all crypto
- // operations. null in non-FIPS mode
- static java.security.Provider cryptoProvider;
-
- protected static synchronized boolean isFIPS() {
- if (fips == null) {
- fips = false;
- }
- return fips;
- }
-
- // ensure we can use FIPS mode using the specified crypto provider.
- // enable FIPS mode if not already enabled.
- private static synchronized void ensureFIPS(java.security.Provider p) {
- if (fips == null) {
- fips = true;
- cryptoProvider = p;
- } else {
- if (fips == false) {
- throw new ProviderException
- ("SunJSSE already initialized in non-FIPS mode");
- }
- if (cryptoProvider != p) {
- throw new ProviderException
- ("SunJSSE already initialized with FIPS crypto provider "
- + cryptoProvider);
- }
- }
- }
-
- // standard constructor
- protected SunJSSE() {
- super("SunJSSE", 1.7d, info);
- subclassCheck();
- if (Boolean.TRUE.equals(fips)) {
- throw new ProviderException
- ("SunJSSE is already initialized in FIPS mode");
- }
- registerAlgorithms(false);
- }
-
- // prefered constructor to enable FIPS mode at runtime
- protected SunJSSE(java.security.Provider cryptoProvider){
- this(checkNull(cryptoProvider), cryptoProvider.getName());
- }
-
- // constructor to enable FIPS mode from java.security file
- protected SunJSSE(String cryptoProvider){
- this(null, checkNull(cryptoProvider));
- }
-
- private static <T> T checkNull(T t) {
- if (t == null) {
- throw new ProviderException("cryptoProvider must not be null");
- }
- return t;
- }
-
- private SunJSSE(java.security.Provider cryptoProvider,
- String providerName) {
- super("SunJSSE", 1.6d, fipsInfo + providerName + ")");
- subclassCheck();
- if (cryptoProvider == null) {
- // Calling Security.getProvider() will cause other providers to be
- // loaded. That is not good but unavoidable here.
- cryptoProvider = Security.getProvider(providerName);
- if (cryptoProvider == null) {
- throw new ProviderException
- ("Crypto provider not installed: " + providerName);
- }
- }
- ensureFIPS(cryptoProvider);
- registerAlgorithms(true);
- }
-
- private void registerAlgorithms(final boolean isfips) {
- AccessController.doPrivileged(new PrivilegedAction<Object>() {
- public Object run() {
- doRegister(isfips);
- return null;
- }
- });
- }
-
- private void doRegister(boolean isfips) {
- if (isfips == false) {
- put("KeyFactory.RSA",
- "sun.security.rsa.RSAKeyFactory");
- put("Alg.Alias.KeyFactory.1.2.840.113549.1.1", "RSA");
- put("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1", "RSA");
-
- put("KeyPairGenerator.RSA",
- "sun.security.rsa.RSAKeyPairGenerator");
- put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA");
- put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA");
-
- put("Signature.MD2withRSA",
- "sun.security.rsa.RSASignature$MD2withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA");
- put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2",
- "MD2withRSA");
-
- put("Signature.MD5withRSA",
- "sun.security.rsa.RSASignature$MD5withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
- put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4",
- "MD5withRSA");
-
- put("Signature.SHA1withRSA",
- "sun.security.rsa.RSASignature$SHA1withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA");
- put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5",
- "SHA1withRSA");
- put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA");
- put("Alg.Alias.Signature.OID.1.3.14.3.2.29", "SHA1withRSA");
-
- }
- put("Signature.MD5andSHA1withRSA",
- "sun.security.ssl.RSASignature");
-
- put("KeyManagerFactory.SunX509",
- "sun.security.ssl.KeyManagerFactoryImpl$SunX509");
- put("KeyManagerFactory.NewSunX509",
- "sun.security.ssl.KeyManagerFactoryImpl$X509");
- put("Alg.Alias.KeyManagerFactory.PKIX", "NewSunX509");
-
- put("TrustManagerFactory.SunX509",
- "sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory");
- put("TrustManagerFactory.PKIX",
- "sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory");
- put("Alg.Alias.TrustManagerFactory.SunPKIX", "PKIX");
- put("Alg.Alias.TrustManagerFactory.X509", "PKIX");
- put("Alg.Alias.TrustManagerFactory.X.509", "PKIX");
-
- put("SSLContext.TLSv1",
- "sun.security.ssl.SSLContextImpl$TLS10Context");
- put("Alg.Alias.SSLContext.TLS", "TLSv1");
- if (isfips == false) {
- put("Alg.Alias.SSLContext.SSL", "TLSv1");
- put("Alg.Alias.SSLContext.SSLv3", "TLSv1");
- }
-
- put("SSLContext.TLSv1.1",
- "sun.security.ssl.SSLContextImpl$TLS11Context");
- put("SSLContext.TLSv1.2",
- "sun.security.ssl.SSLContextImpl$TLS12Context");
- put("SSLContext.Default",
- "sun.security.ssl.SSLContextImpl$DefaultSSLContext");
-
- /*
- * KeyStore
- */
- put("KeyStore.PKCS12",
- "sun.security.pkcs12.PKCS12KeyStore");
- }
-
- private void subclassCheck() {
- if (getClass() != com.sun.net.ssl.internal.ssl.Provider.class) {
- throw new AssertionError("Illegal subclass: " + getClass());
- }
- }
-
- @Override
- protected final void finalize() throws Throwable {
- // empty
- super.finalize();
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/SunX509KeyManagerImpl.java b/ojluni/src/main/java/sun/security/ssl/SunX509KeyManagerImpl.java
deleted file mode 100755
index bdf113d..0000000
--- a/ojluni/src/main/java/sun/security/ssl/SunX509KeyManagerImpl.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import javax.net.ssl.*;
-import java.security.*;
-import java.security.cert.*;
-import java.security.cert.Certificate;
-import java.util.*;
-import java.net.Socket;
-
-import javax.security.auth.x500.X500Principal;
-
-
-/**
- * An implemention of X509KeyManager backed by a KeyStore.
- *
- * The backing KeyStore is inspected when this object is constructed.
- * All key entries containing a PrivateKey and a non-empty chain of
- * X509Certificate are then copied into an internal store. This means
- * that subsequent modifications of the KeyStore have no effect on the
- * X509KeyManagerImpl object.
- *
- * Note that this class assumes that all keys are protected by the same
- * password.
- *
- * The JSSE handshake code currently calls into this class via
- * chooseClientAlias() and chooseServerAlias() to find the certificates to
- * use. As implemented here, both always return the first alias returned by
- * getClientAliases() and getServerAliases(). In turn, these methods are
- * implemented by calling getAliases(), which performs the actual lookup.
- *
- * Note that this class currently implements no checking of the local
- * certificates. In particular, it is *not* guaranteed that:
- * . the certificates are within their validity period and not revoked
- * . the signatures verify
- * . they form a PKIX compliant chain.
- * . the certificate extensions allow the certificate to be used for
- * the desired purpose.
- *
- * Chains that fail any of these criteria will probably be rejected by
- * the remote peer.
- *
- */
-final class SunX509KeyManagerImpl extends X509ExtendedKeyManager {
-
- private static final Debug debug = Debug.getInstance("ssl");
-
- private static final String[] STRING0 = new String[0];
-
- /*
- * The credentials from the KeyStore as
- * Map: String(alias) -> X509Credentials(credentials)
- */
- private Map<String,X509Credentials> credentialsMap;
-
- /*
- * Cached server aliases for the case issuers == null.
- * (in the current JSSE implementation, issuers are always null for
- * server certs). See chooseServerAlias() for details.
- *
- * Map: String(keyType) -> String[](alias)
- */
- private Map<String,String[]> serverAliasCache;
-
- /*
- * Basic container for credentials implemented as an inner class.
- */
- private static class X509Credentials {
- PrivateKey privateKey;
- X509Certificate[] certificates;
- private Set<X500Principal> issuerX500Principals;
-
- X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) {
- // assert privateKey and certificates != null
- this.privateKey = privateKey;
- this.certificates = certificates;
- }
-
- synchronized Set<X500Principal> getIssuerX500Principals() {
- // lazy initialization
- if (issuerX500Principals == null) {
- issuerX500Principals = new HashSet<X500Principal>();
- for (int i = 0; i < certificates.length; i++) {
- issuerX500Principals.add(
- certificates[i].getIssuerX500Principal());
- }
- }
- return issuerX500Principals;
- }
- }
-
- SunX509KeyManagerImpl(KeyStore ks, char[] password) throws KeyStoreException,
- NoSuchAlgorithmException, UnrecoverableKeyException {
-
- credentialsMap = new HashMap<String,X509Credentials>();
- serverAliasCache = new HashMap<String,String[]>();
- if (ks == null) {
- return;
- }
-
- for (Enumeration<String> aliases = ks.aliases();
- aliases.hasMoreElements(); ) {
- String alias = aliases.nextElement();
- if (!ks.isKeyEntry(alias)) {
- continue;
- }
- Key key = ks.getKey(alias, password);
- if (key instanceof PrivateKey == false) {
- continue;
- }
- Certificate[] certs = ks.getCertificateChain(alias);
- if ((certs == null) || (certs.length == 0) ||
- !(certs[0] instanceof X509Certificate)) {
- continue;
- }
- if (!(certs instanceof X509Certificate[])) {
- Certificate[] tmp = new X509Certificate[certs.length];
- System.arraycopy(certs, 0, tmp, 0, certs.length);
- certs = tmp;
- }
-
- X509Credentials cred = new X509Credentials((PrivateKey)key,
- (X509Certificate[])certs);
- credentialsMap.put(alias, cred);
- if (debug != null && Debug.isOn("keymanager")) {
- System.out.println("***");
- System.out.println("found key for : " + alias);
- for (int i = 0; i < certs.length; i++) {
- System.out.println("chain [" + i + "] = "
- + certs[i]);
- }
- System.out.println("***");
- }
- }
- }
-
- /*
- * Returns the certificate chain associated with the given alias.
- *
- * @return the certificate chain (ordered with the user's certificate first
- * and the root certificate authority last)
- */
- public X509Certificate[] getCertificateChain(String alias) {
- if (alias == null) {
- return null;
- }
- X509Credentials cred = credentialsMap.get(alias);
- if (cred == null) {
- return null;
- } else {
- return cred.certificates.clone();
- }
- }
-
- /*
- * Returns the key associated with the given alias
- */
- public PrivateKey getPrivateKey(String alias) {
- if (alias == null) {
- return null;
- }
- X509Credentials cred = credentialsMap.get(alias);
- if (cred == null) {
- return null;
- } else {
- return cred.privateKey;
- }
- }
-
- /*
- * Choose an alias to authenticate the client side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
- Socket socket) {
- /*
- * We currently don't do anything with socket, but
- * someday we might. It might be a useful hint for
- * selecting one of the aliases we get back from
- * getClientAliases().
- */
-
- if (keyTypes == null) {
- return null;
- }
-
- for (int i = 0; i < keyTypes.length; i++) {
- String[] aliases = getClientAliases(keyTypes[i], issuers);
- if ((aliases != null) && (aliases.length > 0)) {
- return aliases[0];
- }
- }
- return null;
- }
-
- /*
- * Choose an alias to authenticate the client side of an
- * <code>SSLEngine</code> connection given the public key type
- * and the list of certificate issuer authorities recognized by
- * the peer (if any).
- *
- * @since 1.5
- */
- public String chooseEngineClientAlias(String[] keyType,
- Principal[] issuers, SSLEngine engine) {
- /*
- * If we ever start using socket as a selection criteria,
- * we'll need to adjust this.
- */
- return chooseClientAlias(keyType, issuers, null);
- }
-
- /*
- * Choose an alias to authenticate the server side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String chooseServerAlias(String keyType,
- Principal[] issuers, Socket socket) {
- /*
- * We currently don't do anything with socket, but
- * someday we might. It might be a useful hint for
- * selecting one of the aliases we get back from
- * getServerAliases().
- */
- if (keyType == null) {
- return null;
- }
-
- String[] aliases;
-
- if (issuers == null || issuers.length == 0) {
- aliases = serverAliasCache.get(keyType);
- if (aliases == null) {
- aliases = getServerAliases(keyType, issuers);
- // Cache the result (positive and negative lookups)
- if (aliases == null) {
- aliases = STRING0;
- }
- serverAliasCache.put(keyType, aliases);
- }
- } else {
- aliases = getServerAliases(keyType, issuers);
- }
- if ((aliases != null) && (aliases.length > 0)) {
- return aliases[0];
- }
- return null;
- }
-
- /*
- * Choose an alias to authenticate the server side of an
- * <code>SSLEngine</code> connection given the public key type
- * and the list of certificate issuer authorities recognized by
- * the peer (if any).
- *
- * @since 1.5
- */
- public String chooseEngineServerAlias(String keyType,
- Principal[] issuers, SSLEngine engine) {
- /*
- * If we ever start using socket as a selection criteria,
- * we'll need to adjust this.
- */
- return chooseServerAlias(keyType, issuers, null);
- }
-
- /*
- * Get the matching aliases for authenticating the client side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String[] getClientAliases(String keyType, Principal[] issuers) {
- return getAliases(keyType, issuers);
- }
-
- /*
- * Get the matching aliases for authenticating the server side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- */
- public String[] getServerAliases(String keyType, Principal[] issuers) {
- return getAliases(keyType, issuers);
- }
-
- /*
- * Get the matching aliases for authenticating the either side of a secure
- * socket given the public key type and the list of
- * certificate issuer authorities recognized by the peer (if any).
- *
- * Issuers comes to us in the form of X500Principal[].
- */
- private String[] getAliases(String keyType, Principal[] issuers) {
- if (keyType == null) {
- return null;
- }
- if (issuers == null) {
- issuers = new X500Principal[0];
- }
- if (issuers instanceof X500Principal[] == false) {
- // normally, this will never happen but try to recover if it does
- issuers = convertPrincipals(issuers);
- }
- String sigType;
- if (keyType.contains("_")) {
- int k = keyType.indexOf("_");
- sigType = keyType.substring(k + 1);
- keyType = keyType.substring(0, k);
- } else {
- sigType = null;
- }
-
- X500Principal[] x500Issuers = (X500Principal[])issuers;
- // the algorithm below does not produce duplicates, so avoid Set
- List<String> aliases = new ArrayList<>();
-
- for (Map.Entry<String,X509Credentials> entry :
- credentialsMap.entrySet()) {
-
- String alias = entry.getKey();
- X509Credentials credentials = entry.getValue();
- X509Certificate[] certs = credentials.certificates;
-
- if (!keyType.equals(certs[0].getPublicKey().getAlgorithm())) {
- continue;
- }
- if (sigType != null) {
- if (certs.length > 1) {
- // if possible, check the public key in the issuer cert
- if (!sigType.equals(certs[1].getPublicKey().getAlgorithm())) {
- continue;
- }
- } else {
- // Check the signature algorithm of the certificate itself.
- // Look for the "withRSA" in "SHA1withRSA", etc.
- String sigAlgName =
- certs[0].getSigAlgName().toUpperCase(Locale.ENGLISH);
- String pattern = "WITH" + sigType.toUpperCase(Locale.ENGLISH);
- if (sigAlgName.contains(pattern) == false) {
- continue;
- }
- }
- }
-
- if (issuers.length == 0) {
- // no issuer specified, match all
- aliases.add(alias);
- if (debug != null && Debug.isOn("keymanager")) {
- System.out.println("matching alias: " + alias);
- }
- } else {
- Set<X500Principal> certIssuers =
- credentials.getIssuerX500Principals();
- for (int i = 0; i < x500Issuers.length; i++) {
- if (certIssuers.contains(issuers[i])) {
- aliases.add(alias);
- if (debug != null && Debug.isOn("keymanager")) {
- System.out.println("matching alias: " + alias);
- }
- break;
- }
- }
- }
- }
-
- String[] aliasStrings = aliases.toArray(STRING0);
- return ((aliasStrings.length == 0) ? null : aliasStrings);
- }
-
- /*
- * Convert an array of Principals to an array of X500Principals, if
- * possible. Principals that cannot be converted are ignored.
- */
- private static X500Principal[] convertPrincipals(Principal[] principals) {
- List<X500Principal> list = new ArrayList<>(principals.length);
- for (int i = 0; i < principals.length; i++) {
- Principal p = principals[i];
- if (p instanceof X500Principal) {
- list.add((X500Principal)p);
- } else {
- try {
- list.add(new X500Principal(p.getName()));
- } catch (IllegalArgumentException e) {
- // ignore
- }
- }
- }
- return list.toArray(new X500Principal[list.size()]);
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/TrustManagerFactoryImpl.java b/ojluni/src/main/java/sun/security/ssl/TrustManagerFactoryImpl.java
deleted file mode 100755
index ee2142c..0000000
--- a/ojluni/src/main/java/sun/security/ssl/TrustManagerFactoryImpl.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.util.*;
-import java.io.*;
-import java.math.*;
-import java.security.*;
-import java.security.cert.*;
-import javax.net.ssl.*;
-import java.security.spec.AlgorithmParameterSpec;
-
-import sun.security.validator.Validator;
-
-abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
-
- private static final Debug debug = Debug.getInstance("ssl");
- private X509TrustManager trustManager = null;
- private boolean isInitialized = false;
-
- TrustManagerFactoryImpl() {
- // empty
- }
-
- protected void engineInit(KeyStore ks) throws KeyStoreException {
- if (ks == null) {
- try {
- ks = getCacertsKeyStore("trustmanager");
- } catch (SecurityException se) {
- // eat security exceptions but report other throwables
- if (debug != null && Debug.isOn("trustmanager")) {
- System.out.println(
- "SunX509: skip default keystore: " + se);
- }
- } catch (Error err) {
- if (debug != null && Debug.isOn("trustmanager")) {
- System.out.println(
- "SunX509: skip default keystore: " + err);
- }
- throw err;
- } catch (RuntimeException re) {
- if (debug != null && Debug.isOn("trustmanager")) {
- System.out.println(
- "SunX509: skip default keystore: " + re);
- }
- throw re;
- } catch (Exception e) {
- if (debug != null && Debug.isOn("trustmanager")) {
- System.out.println(
- "SunX509: skip default keystore: " + e);
- }
- throw new KeyStoreException(
- "problem accessing trust store" + e);
- }
- }
- trustManager = getInstance(ks);
- isInitialized = true;
- }
-
- abstract X509TrustManager getInstance(KeyStore ks) throws KeyStoreException;
-
- abstract X509TrustManager getInstance(ManagerFactoryParameters spec)
- throws InvalidAlgorithmParameterException;
-
- protected void engineInit(ManagerFactoryParameters spec) throws
- InvalidAlgorithmParameterException {
- trustManager = getInstance(spec);
- isInitialized = true;
- }
-
- /**
- * Returns one trust manager for each type of trust material.
- */
- protected TrustManager[] engineGetTrustManagers() {
- if (!isInitialized) {
- throw new IllegalStateException(
- "TrustManagerFactoryImpl is not initialized");
- }
- return new TrustManager[] { trustManager };
- }
-
- /*
- * Try to get an InputStream based on the file we pass in.
- */
- private static FileInputStream getFileInputStream(final File file)
- throws Exception {
- return AccessController.doPrivileged(
- new PrivilegedExceptionAction<FileInputStream>() {
- public FileInputStream run() throws Exception {
- try {
- if (file.exists()) {
- return new FileInputStream(file);
- } else {
- return null;
- }
- } catch (FileNotFoundException e) {
- // couldn't find it, oh well.
- return null;
- }
- }
- });
- }
-
- /**
- * Returns the keystore with the configured CA certificates.
- */
- static KeyStore getCacertsKeyStore(String dbgname) throws Exception
- {
- String storeFileName = null;
- File storeFile = null;
- FileInputStream fis = null;
- String defaultTrustStoreType;
- String defaultTrustStoreProvider;
- final HashMap<String,String> props = new HashMap<>();
- final String sep = File.separator;
- KeyStore ks = null;
-
- AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
- public Void run() throws Exception {
- props.put("trustStore", System.getProperty(
- "javax.net.ssl.trustStore"));
- props.put("javaHome", System.getProperty(
- "java.home"));
- props.put("trustStoreType", System.getProperty(
- "javax.net.ssl.trustStoreType",
- KeyStore.getDefaultType()));
- props.put("trustStoreProvider", System.getProperty(
- "javax.net.ssl.trustStoreProvider", ""));
- props.put("trustStorePasswd", System.getProperty(
- "javax.net.ssl.trustStorePassword", ""));
- return null;
- }
- });
-
- /*
- * Try:
- * javax.net.ssl.trustStore (if this variable exists, stop)
- * jssecacerts
- * cacerts
- *
- * If none exists, we use an empty keystore.
- */
-
- storeFileName = props.get("trustStore");
- if (!"NONE".equals(storeFileName)) {
- if (storeFileName != null) {
- storeFile = new File(storeFileName);
- fis = getFileInputStream(storeFile);
- } else {
- String javaHome = props.get("javaHome");
- storeFile = new File(javaHome + sep + "lib" + sep
- + "security" + sep +
- "jssecacerts");
- if ((fis = getFileInputStream(storeFile)) == null) {
- storeFile = new File(javaHome + sep + "lib" + sep
- + "security" + sep +
- "cacerts");
- fis = getFileInputStream(storeFile);
- }
- }
-
- if (fis != null) {
- storeFileName = storeFile.getPath();
- } else {
- storeFileName = "No File Available, using empty keystore.";
- }
- }
-
- defaultTrustStoreType = props.get("trustStoreType");
- defaultTrustStoreProvider = props.get("trustStoreProvider");
- if (debug != null && Debug.isOn(dbgname)) {
- System.out.println("trustStore is: " + storeFileName);
- System.out.println("trustStore type is : " +
- defaultTrustStoreType);
- System.out.println("trustStore provider is : " +
- defaultTrustStoreProvider);
- }
-
- /*
- * Try to initialize trust store.
- */
- if (defaultTrustStoreType.length() != 0) {
- if (debug != null && Debug.isOn(dbgname)) {
- System.out.println("init truststore");
- }
- if (defaultTrustStoreProvider.length() == 0) {
- ks = KeyStore.getInstance(defaultTrustStoreType);
- } else {
- ks = KeyStore.getInstance(defaultTrustStoreType,
- defaultTrustStoreProvider);
- }
- char[] passwd = null;
- String defaultTrustStorePassword = props.get("trustStorePasswd");
- if (defaultTrustStorePassword.length() != 0)
- passwd = defaultTrustStorePassword.toCharArray();
-
- // if trustStore is NONE, fis will be null
- ks.load(fis, passwd);
-
- // Zero out the temporary password storage
- if (passwd != null) {
- for (int i = 0; i < passwd.length; i++) {
- passwd[i] = (char)0;
- }
- }
- }
-
- if (fis != null) {
- fis.close();
- }
-
- return ks;
- }
-
- public static final class SimpleFactory extends TrustManagerFactoryImpl {
- X509TrustManager getInstance(KeyStore ks) throws KeyStoreException {
- return new X509TrustManagerImpl(Validator.TYPE_SIMPLE, ks);
- }
- X509TrustManager getInstance(ManagerFactoryParameters spec)
- throws InvalidAlgorithmParameterException {
- throw new InvalidAlgorithmParameterException
- ("SunX509 TrustManagerFactory does not use "
- + "ManagerFactoryParameters");
- }
- }
-
- public static final class PKIXFactory extends TrustManagerFactoryImpl {
- X509TrustManager getInstance(KeyStore ks) throws KeyStoreException {
- return new X509TrustManagerImpl(Validator.TYPE_PKIX, ks);
- }
- X509TrustManager getInstance(ManagerFactoryParameters spec)
- throws InvalidAlgorithmParameterException {
- if (spec instanceof CertPathTrustManagerParameters == false) {
- throw new InvalidAlgorithmParameterException
- ("Parameters must be CertPathTrustManagerParameters");
- }
- CertPathParameters params =
- ((CertPathTrustManagerParameters)spec).getParameters();
- if (params instanceof PKIXBuilderParameters == false) {
- throw new InvalidAlgorithmParameterException
- ("Encapsulated parameters must be PKIXBuilderParameters");
- }
- PKIXBuilderParameters pkixParams = (PKIXBuilderParameters)params;
- return new X509TrustManagerImpl(Validator.TYPE_PKIX, pkixParams);
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/X509KeyManagerImpl.java b/ojluni/src/main/java/sun/security/ssl/X509KeyManagerImpl.java
deleted file mode 100755
index 426f5bf..0000000
--- a/ojluni/src/main/java/sun/security/ssl/X509KeyManagerImpl.java
+++ /dev/null
@@ -1,741 +0,0 @@
-/*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.lang.ref.*;
-import java.util.*;
-import static java.util.Locale.ENGLISH;
-import java.util.concurrent.atomic.AtomicLong;
-import java.net.Socket;
-
-import java.security.*;
-import java.security.KeyStore.*;
-import java.security.cert.*;
-import java.security.cert.Certificate;
-
-import javax.net.ssl.*;
-
-import sun.security.provider.certpath.AlgorithmChecker;
-
-/**
- * The new X509 key manager implementation. The main differences to the
- * old SunX509 key manager are:
- * . it is based around the KeyStore.Builder API. This allows it to use
- * other forms of KeyStore protection or password input (e.g. a
- * CallbackHandler) or to have keys within one KeyStore protected by
- * different keys.
- * . it can use multiple KeyStores at the same time.
- * . it is explicitly designed to accomodate KeyStores that change over
- * the lifetime of the process.
- * . it makes an effort to choose the key that matches best, i.e. one that
- * is not expired and has the appropriate certificate extensions.
- *
- * Note that this code is not explicitly performance optimzied yet.
- *
- * @author Andreas Sterbenz
- */
-final class X509KeyManagerImpl extends X509ExtendedKeyManager
- implements X509KeyManager {
-
- private static final Debug debug = Debug.getInstance("ssl");
-
- private final static boolean useDebug =
- (debug != null) && Debug.isOn("keymanager");
-
- // for unit testing only, set via privileged reflection
- private static Date verificationDate;
-
- // list of the builders
- private final List<Builder> builders;
-
- // counter to generate unique ids for the aliases
- private final AtomicLong uidCounter;
-
- // cached entries
- private final Map<String,Reference<PrivateKeyEntry>> entryCacheMap;
-
- X509KeyManagerImpl(Builder builder) {
- this(Collections.singletonList(builder));
- }
-
- X509KeyManagerImpl(List<Builder> builders) {
- this.builders = builders;
- uidCounter = new AtomicLong();
- entryCacheMap = Collections.synchronizedMap
- (new SizedMap<String,Reference<PrivateKeyEntry>>());
- }
-
- // LinkedHashMap with a max size of 10
- // see LinkedHashMap JavaDocs
- private static class SizedMap<K,V> extends LinkedHashMap<K,V> {
- @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
- return size() > 10;
- }
- }
-
- //
- // public methods
- //
-
- public X509Certificate[] getCertificateChain(String alias) {
- PrivateKeyEntry entry = getEntry(alias);
- return entry == null ? null :
- (X509Certificate[])entry.getCertificateChain();
- }
-
- public PrivateKey getPrivateKey(String alias) {
- PrivateKeyEntry entry = getEntry(alias);
- return entry == null ? null : entry.getPrivateKey();
- }
-
- public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
- Socket socket) {
- return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
- getAlgorithmConstraints(socket));
- }
-
- public String chooseEngineClientAlias(String[] keyTypes,
- Principal[] issuers, SSLEngine engine) {
- return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT,
- getAlgorithmConstraints(engine));
- }
-
- public String chooseServerAlias(String keyType,
- Principal[] issuers, Socket socket) {
- return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
- getAlgorithmConstraints(socket));
- }
-
- public String chooseEngineServerAlias(String keyType,
- Principal[] issuers, SSLEngine engine) {
- return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER,
- getAlgorithmConstraints(engine));
- }
-
- public String[] getClientAliases(String keyType, Principal[] issuers) {
- return getAliases(keyType, issuers, CheckType.CLIENT, null);
- }
-
- public String[] getServerAliases(String keyType, Principal[] issuers) {
- return getAliases(keyType, issuers, CheckType.SERVER, null);
- }
-
- //
- // implementation private methods
- //
-
- // Gets algorithm constraints of the socket.
- private AlgorithmConstraints getAlgorithmConstraints(Socket socket) {
- if (socket != null && socket.isConnected() &&
- socket instanceof SSLSocket) {
-
- SSLSocket sslSocket = (SSLSocket)socket;
- SSLSession session = sslSocket.getHandshakeSession();
-
- if (session != null) {
- ProtocolVersion protocolVersion =
- ProtocolVersion.valueOf(session.getProtocol());
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- String[] peerSupportedSignAlgs = null;
-
- if (session instanceof ExtendedSSLSession) {
- ExtendedSSLSession extSession =
- (ExtendedSSLSession)session;
- peerSupportedSignAlgs =
- extSession.getPeerSupportedSignatureAlgorithms();
- }
-
- return new SSLAlgorithmConstraints(
- sslSocket, peerSupportedSignAlgs, true);
- }
- }
-
- return new SSLAlgorithmConstraints(sslSocket, true);
- }
-
- return new SSLAlgorithmConstraints((SSLSocket)null, true);
- }
-
- // Gets algorithm constraints of the engine.
- private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) {
- if (engine != null) {
- SSLSession session = engine.getHandshakeSession();
- if (session != null) {
- ProtocolVersion protocolVersion =
- ProtocolVersion.valueOf(session.getProtocol());
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- String[] peerSupportedSignAlgs = null;
-
- if (session instanceof ExtendedSSLSession) {
- ExtendedSSLSession extSession =
- (ExtendedSSLSession)session;
- peerSupportedSignAlgs =
- extSession.getPeerSupportedSignatureAlgorithms();
- }
-
- return new SSLAlgorithmConstraints(
- engine, peerSupportedSignAlgs, true);
- }
- }
- }
-
- return new SSLAlgorithmConstraints(engine, true);
- }
-
- // we construct the alias we return to JSSE as seen in the code below
- // a unique id is included to allow us to reliably cache entries
- // between the calls to getCertificateChain() and getPrivateKey()
- // even if tokens are inserted or removed
- private String makeAlias(EntryStatus entry) {
- return uidCounter.incrementAndGet() + "." + entry.builderIndex + "."
- + entry.alias;
- }
-
- private PrivateKeyEntry getEntry(String alias) {
- // if the alias is null, return immediately
- if (alias == null) {
- return null;
- }
-
- // try to get the entry from cache
- Reference<PrivateKeyEntry> ref = entryCacheMap.get(alias);
- PrivateKeyEntry entry = (ref != null) ? ref.get() : null;
- if (entry != null) {
- return entry;
- }
-
- // parse the alias
- int firstDot = alias.indexOf('.');
- int secondDot = alias.indexOf('.', firstDot + 1);
- if ((firstDot == -1) || (secondDot == firstDot)) {
- // invalid alias
- return null;
- }
- try {
- int builderIndex = Integer.parseInt
- (alias.substring(firstDot + 1, secondDot));
- String keyStoreAlias = alias.substring(secondDot + 1);
- Builder builder = builders.get(builderIndex);
- KeyStore ks = builder.getKeyStore();
- Entry newEntry = ks.getEntry
- (keyStoreAlias, builder.getProtectionParameter(alias));
- if (newEntry instanceof PrivateKeyEntry == false) {
- // unexpected type of entry
- return null;
- }
- entry = (PrivateKeyEntry)newEntry;
- entryCacheMap.put(alias, new SoftReference(entry));
- return entry;
- } catch (Exception e) {
- // ignore
- return null;
- }
- }
-
- // Class to help verify that the public key algorithm (and optionally
- // the signature algorithm) of a certificate matches what we need.
- private static class KeyType {
-
- final String keyAlgorithm;
-
- // In TLS 1.2, the signature algorithm has been obsoleted by the
- // supported_signature_algorithms, and the certificate type no longer
- // restricts the algorithm used to sign the certificate.
- // However, because we don't support certificate type checking other
- // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the
- // protocol version here.
- final String sigKeyAlgorithm;
-
- KeyType(String algorithm) {
- int k = algorithm.indexOf("_");
- if (k == -1) {
- keyAlgorithm = algorithm;
- sigKeyAlgorithm = null;
- } else {
- keyAlgorithm = algorithm.substring(0, k);
- sigKeyAlgorithm = algorithm.substring(k + 1);
- }
- }
-
- boolean matches(Certificate[] chain) {
- if (!chain[0].getPublicKey().getAlgorithm().equals(keyAlgorithm)) {
- return false;
- }
- if (sigKeyAlgorithm == null) {
- return true;
- }
- if (chain.length > 1) {
- // if possible, check the public key in the issuer cert
- return sigKeyAlgorithm.equals(
- chain[1].getPublicKey().getAlgorithm());
- } else {
- // Check the signature algorithm of the certificate itself.
- // Look for the "withRSA" in "SHA1withRSA", etc.
- X509Certificate issuer = (X509Certificate)chain[0];
- String sigAlgName = issuer.getSigAlgName().toUpperCase(ENGLISH);
- String pattern = "WITH" + sigKeyAlgorithm.toUpperCase(ENGLISH);
- return sigAlgName.contains(pattern);
- }
- }
- }
-
- private static List<KeyType> getKeyTypes(String ... keyTypes) {
- if ((keyTypes == null) ||
- (keyTypes.length == 0) || (keyTypes[0] == null)) {
- return null;
- }
- List<KeyType> list = new ArrayList<>(keyTypes.length);
- for (String keyType : keyTypes) {
- list.add(new KeyType(keyType));
- }
- return list;
- }
-
- /*
- * Return the best alias that fits the given parameters.
- * The algorithm we use is:
- * . scan through all the aliases in all builders in order
- * . as soon as we find a perfect match, return
- * (i.e. a match with a cert that has appropriate key usage
- * and is not expired).
- * . if we do not find a perfect match, keep looping and remember
- * the imperfect matches
- * . at the end, sort the imperfect matches. we prefer expired certs
- * with appropriate key usage to certs with the wrong key usage.
- * return the first one of them.
- */
- private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers,
- CheckType checkType, AlgorithmConstraints constraints) {
- if (keyTypeList == null || keyTypeList.size() == 0) {
- return null;
- }
-
- Set<Principal> issuerSet = getIssuerSet(issuers);
- List<EntryStatus> allResults = null;
- for (int i = 0, n = builders.size(); i < n; i++) {
- try {
- List<EntryStatus> results = getAliases(i, keyTypeList,
- issuerSet, false, checkType, constraints);
- if (results != null) {
- // the results will either be a single perfect match
- // or 1 or more imperfect matches
- // if it's a perfect match, return immediately
- EntryStatus status = results.get(0);
- if (status.checkResult == CheckResult.OK) {
- if (useDebug) {
- debug.println("KeyMgr: choosing key: " + status);
- }
- return makeAlias(status);
- }
- if (allResults == null) {
- allResults = new ArrayList<EntryStatus>();
- }
- allResults.addAll(results);
- }
- } catch (Exception e) {
- // ignore
- }
- }
- if (allResults == null) {
- if (useDebug) {
- debug.println("KeyMgr: no matching key found");
- }
- return null;
- }
- Collections.sort(allResults);
- if (useDebug) {
- debug.println("KeyMgr: no good matching key found, "
- + "returning best match out of:");
- debug.println(allResults.toString());
- }
- return makeAlias(allResults.get(0));
- }
-
- /*
- * Return all aliases that (approximately) fit the parameters.
- * These are perfect matches plus imperfect matches (expired certificates
- * and certificates with the wrong extensions).
- * The perfect matches will be first in the array.
- */
- public String[] getAliases(String keyType, Principal[] issuers,
- CheckType checkType, AlgorithmConstraints constraints) {
- if (keyType == null) {
- return null;
- }
-
- Set<Principal> issuerSet = getIssuerSet(issuers);
- List<KeyType> keyTypeList = getKeyTypes(keyType);
- List<EntryStatus> allResults = null;
- for (int i = 0, n = builders.size(); i < n; i++) {
- try {
- List<EntryStatus> results = getAliases(i, keyTypeList,
- issuerSet, true, checkType, constraints);
- if (results != null) {
- if (allResults == null) {
- allResults = new ArrayList<EntryStatus>();
- }
- allResults.addAll(results);
- }
- } catch (Exception e) {
- // ignore
- }
- }
- if (allResults == null || allResults.size() == 0) {
- if (useDebug) {
- debug.println("KeyMgr: no matching alias found");
- }
- return null;
- }
- Collections.sort(allResults);
- if (useDebug) {
- debug.println("KeyMgr: getting aliases: " + allResults);
- }
- return toAliases(allResults);
- }
-
- // turn candidate entries into unique aliases we can return to JSSE
- private String[] toAliases(List<EntryStatus> results) {
- String[] s = new String[results.size()];
- int i = 0;
- for (EntryStatus result : results) {
- s[i++] = makeAlias(result);
- }
- return s;
- }
-
- // make a Set out of the array
- private Set<Principal> getIssuerSet(Principal[] issuers) {
- if ((issuers != null) && (issuers.length != 0)) {
- return new HashSet<>(Arrays.asList(issuers));
- } else {
- return null;
- }
- }
-
- // a candidate match
- // identifies the entry by builder and alias
- // and includes the result of the certificate check
- private static class EntryStatus implements Comparable<EntryStatus> {
-
- final int builderIndex;
- final int keyIndex;
- final String alias;
- final CheckResult checkResult;
-
- EntryStatus(int builderIndex, int keyIndex, String alias,
- Certificate[] chain, CheckResult checkResult) {
- this.builderIndex = builderIndex;
- this.keyIndex = keyIndex;
- this.alias = alias;
- this.checkResult = checkResult;
- }
-
- public int compareTo(EntryStatus other) {
- int result = this.checkResult.compareTo(other.checkResult);
- return (result == 0) ? (this.keyIndex - other.keyIndex) : result;
- }
-
- public String toString() {
- String s = alias + " (verified: " + checkResult + ")";
- if (builderIndex == 0) {
- return s;
- } else {
- return "Builder #" + builderIndex + ", alias: " + s;
- }
- }
- }
-
- // enum for the type of certificate check we want to perform
- // (client or server)
- // also includes the check code itself
- private static enum CheckType {
-
- // enum constant for "no check" (currently not used)
- NONE(Collections.<String>emptySet()),
-
- // enum constant for "tls client" check
- // valid EKU for TLS client: any, tls_client
- CLIENT(new HashSet<String>(Arrays.asList(new String[] {
- "2.5.29.37.0", "1.3.6.1.5.5.7.3.2" }))),
-
- // enum constant for "tls server" check
- // valid EKU for TLS server: any, tls_server, ns_sgc, ms_sgc
- SERVER(new HashSet<String>(Arrays.asList(new String[] {
- "2.5.29.37.0", "1.3.6.1.5.5.7.3.1", "2.16.840.1.113730.4.1",
- "1.3.6.1.4.1.311.10.3.3" })));
-
- // set of valid EKU values for this type
- final Set<String> validEku;
-
- CheckType(Set<String> validEku) {
- this.validEku = validEku;
- }
-
- private static boolean getBit(boolean[] keyUsage, int bit) {
- return (bit < keyUsage.length) && keyUsage[bit];
- }
-
- // check if this certificate is appropriate for this type of use
- // first check extensions, if they match, check expiration
- // note: we may want to move this code into the sun.security.validator
- // package
- CheckResult check(X509Certificate cert, Date date) {
- if (this == NONE) {
- return CheckResult.OK;
- }
-
- // check extensions
- try {
- // check extended key usage
- List<String> certEku = cert.getExtendedKeyUsage();
- if ((certEku != null) &&
- Collections.disjoint(validEku, certEku)) {
- // if extension present and it does not contain any of
- // the valid EKU OIDs, return extension_mismatch
- return CheckResult.EXTENSION_MISMATCH;
- }
-
- // check key usage
- boolean[] ku = cert.getKeyUsage();
- if (ku != null) {
- String algorithm = cert.getPublicKey().getAlgorithm();
- boolean kuSignature = getBit(ku, 0);
- if (algorithm.equals("RSA")) {
- // require either signature bit
- // or if server also allow key encipherment bit
- if (kuSignature == false) {
- if ((this == CLIENT) || (getBit(ku, 2) == false)) {
- return CheckResult.EXTENSION_MISMATCH;
- }
- }
- } else if (algorithm.equals("DSA")) {
- // require signature bit
- if (kuSignature == false) {
- return CheckResult.EXTENSION_MISMATCH;
- }
- } else if (algorithm.equals("DH")) {
- // require keyagreement bit
- if (getBit(ku, 4) == false) {
- return CheckResult.EXTENSION_MISMATCH;
- }
- } else if (algorithm.equals("EC")) {
- // require signature bit
- if (kuSignature == false) {
- return CheckResult.EXTENSION_MISMATCH;
- }
- // For servers, also require key agreement.
- // This is not totally accurate as the keyAgreement bit
- // is only necessary for static ECDH key exchange and
- // not ephemeral ECDH. We leave it in for now until
- // there are signs that this check causes problems
- // for real world EC certificates.
- if ((this == SERVER) && (getBit(ku, 4) == false)) {
- return CheckResult.EXTENSION_MISMATCH;
- }
- }
- }
- } catch (CertificateException e) {
- // extensions unparseable, return failure
- return CheckResult.EXTENSION_MISMATCH;
- }
-
- try {
- cert.checkValidity(date);
- return CheckResult.OK;
- } catch (CertificateException e) {
- return CheckResult.EXPIRED;
- }
- }
- }
-
- // enum for the result of the extension check
- // NOTE: the order of the constants is important as they are used
- // for sorting, i.e. OK is best, followed by EXPIRED and EXTENSION_MISMATCH
- private static enum CheckResult {
- OK, // ok or not checked
- EXPIRED, // extensions valid but cert expired
- EXTENSION_MISMATCH, // extensions invalid (expiration not checked)
- }
-
- /*
- * Return a List of all candidate matches in the specified builder
- * that fit the parameters.
- * We exclude entries in the KeyStore if they are not:
- * . private key entries
- * . the certificates are not X509 certificates
- * . the algorithm of the key in the EE cert doesn't match one of keyTypes
- * . none of the certs is issued by a Principal in issuerSet
- * Using those entries would not be possible or they would almost
- * certainly be rejected by the peer.
- *
- * In addition to those checks, we also check the extensions in the EE
- * cert and its expiration. Even if there is a mismatch, we include
- * such certificates because they technically work and might be accepted
- * by the peer. This leads to more graceful failure and better error
- * messages if the cert expires from one day to the next.
- *
- * The return values are:
- * . null, if there are no matching entries at all
- * . if 'findAll' is 'false' and there is a perfect match, a List
- * with a single element (early return)
- * . if 'findAll' is 'false' and there is NO perfect match, a List
- * with all the imperfect matches (expired, wrong extensions)
- * . if 'findAll' is 'true', a List with all perfect and imperfect
- * matches
- */
- private List<EntryStatus> getAliases(int builderIndex,
- List<KeyType> keyTypes, Set<Principal> issuerSet,
- boolean findAll, CheckType checkType,
- AlgorithmConstraints constraints) throws Exception {
- Builder builder = builders.get(builderIndex);
- KeyStore ks = builder.getKeyStore();
- List<EntryStatus> results = null;
- Date date = verificationDate;
- boolean preferred = false;
- for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
- String alias = e.nextElement();
- // check if it is a key entry (private key or secret key)
- if (ks.isKeyEntry(alias) == false) {
- continue;
- }
-
- Certificate[] chain = ks.getCertificateChain(alias);
- if ((chain == null) || (chain.length == 0)) {
- // must be secret key entry, ignore
- continue;
- }
-
- boolean incompatible = false;
- for (Certificate cert : chain) {
- if (cert instanceof X509Certificate == false) {
- // not an X509Certificate, ignore this alias
- incompatible = true;
- break;
- }
- }
- if (incompatible) {
- continue;
- }
-
- // check keytype
- int keyIndex = -1;
- int j = 0;
- for (KeyType keyType : keyTypes) {
- if (keyType.matches(chain)) {
- keyIndex = j;
- break;
- }
- j++;
- }
- if (keyIndex == -1) {
- if (useDebug) {
- debug.println("Ignoring alias " + alias
- + ": key algorithm does not match");
- }
- continue;
- }
- // check issuers
- if (issuerSet != null) {
- boolean found = false;
- for (Certificate cert : chain) {
- X509Certificate xcert = (X509Certificate)cert;
- if (issuerSet.contains(xcert.getIssuerX500Principal())) {
- found = true;
- break;
- }
- }
- if (found == false) {
- if (useDebug) {
- debug.println("Ignoring alias " + alias
- + ": issuers do not match");
- }
- continue;
- }
- }
-
- // check the algorithm constraints
- if (constraints != null &&
- !conformsToAlgorithmConstraints(constraints, chain)) {
-
- if (useDebug) {
- debug.println("Ignoring alias " + alias +
- ": certificate list does not conform to " +
- "algorithm constraints");
- }
- continue;
- }
-
- if (date == null) {
- date = new Date();
- }
- CheckResult checkResult =
- checkType.check((X509Certificate)chain[0], date);
- EntryStatus status =
- new EntryStatus(builderIndex, keyIndex,
- alias, chain, checkResult);
- if (!preferred && checkResult == CheckResult.OK && keyIndex == 0) {
- preferred = true;
- }
- if (preferred && (findAll == false)) {
- // if we have a good match and do not need all matches,
- // return immediately
- return Collections.singletonList(status);
- } else {
- if (results == null) {
- results = new ArrayList<EntryStatus>();
- }
- results.add(status);
- }
- }
- return results;
- }
-
- private static boolean conformsToAlgorithmConstraints(
- AlgorithmConstraints constraints, Certificate[] chain) {
-
- AlgorithmChecker checker = new AlgorithmChecker(constraints);
- try {
- checker.init(false);
- } catch (CertPathValidatorException cpve) {
- // unlikely to happen
- return false;
- }
-
- // It is a forward checker, so we need to check from trust to target.
- for (int i = chain.length - 1; i >= 0; i--) {
- Certificate cert = chain[i];
- try {
- // We don't care about the unresolved critical extensions.
- checker.check(cert, Collections.<String>emptySet());
- } catch (CertPathValidatorException cpve) {
- return false;
- }
- }
-
- return true;
- }
-
-}
diff --git a/ojluni/src/main/java/sun/security/ssl/X509TrustManagerImpl.java b/ojluni/src/main/java/sun/security/ssl/X509TrustManagerImpl.java
deleted file mode 100755
index d38e727..0000000
--- a/ojluni/src/main/java/sun/security/ssl/X509TrustManagerImpl.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.net.Socket;
-import javax.net.ssl.SSLSession;
-
-import java.util.*;
-import java.security.*;
-import java.security.cert.*;
-
-import javax.net.ssl.*;
-
-import sun.security.validator.*;
-
-import sun.security.util.HostnameChecker;
-
-/**
- * This class implements the SunJSSE X.509 trust manager using the internal
- * validator API in J2SE core. The logic in this class is minimal.<p>
- * <p>
- * This class supports both the Simple validation algorithm from previous
- * JSSE versions and PKIX validation. Currently, it is not possible for the
- * application to specify PKIX parameters other than trust anchors. This will
- * be fixed in a future release using new APIs. When that happens, it may also
- * make sense to separate the Simple and PKIX trust managers into separate
- * classes.
- *
- * @author Andreas Sterbenz
- */
-final class X509TrustManagerImpl extends X509ExtendedTrustManager
- implements X509TrustManager {
-
- private final String validatorType;
-
- /**
- * The Set of trusted X509Certificates.
- */
- private final Collection<X509Certificate> trustedCerts;
-
- private final PKIXBuilderParameters pkixParams;
-
- // note that we need separate validator for client and server due to
- // the different extension checks. They are initialized lazily on demand.
- private volatile Validator clientValidator, serverValidator;
-
- private static final Debug debug = Debug.getInstance("ssl");
-
- X509TrustManagerImpl(String validatorType, KeyStore ks)
- throws KeyStoreException {
- this.validatorType = validatorType;
- this.pkixParams = null;
- if (ks == null) {
- trustedCerts = Collections.<X509Certificate>emptySet();
- } else {
- trustedCerts = KeyStores.getTrustedCerts(ks);
- }
- showTrustedCerts();
- }
-
- X509TrustManagerImpl(String validatorType, PKIXBuilderParameters params) {
- this.validatorType = validatorType;
- this.pkixParams = params;
- // create server validator eagerly so that we can conveniently
- // get the trusted certificates
- // clients need it anyway eventually, and servers will not mind
- // the little extra footprint
- Validator v = getValidator(Validator.VAR_TLS_SERVER);
- trustedCerts = v.getTrustedCertificates();
- serverValidator = v;
- showTrustedCerts();
- }
-
- @Override
- public void checkClientTrusted(X509Certificate chain[], String authType)
- throws CertificateException {
- checkTrusted(chain, authType, (Socket)null, true);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate chain[], String authType)
- throws CertificateException {
- checkTrusted(chain, authType, (Socket)null, false);
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
- trustedCerts.toArray(certsArray);
- return certsArray;
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- Socket socket) throws CertificateException {
- checkTrusted(chain, authType, socket, true);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- Socket socket) throws CertificateException {
- checkTrusted(chain, authType, socket, false);
- }
-
- @Override
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- SSLEngine engine) throws CertificateException {
- checkTrusted(chain, authType, engine, true);
- }
-
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- SSLEngine engine) throws CertificateException {
- checkTrusted(chain, authType, engine, false);
- }
-
- private Validator checkTrustedInit(X509Certificate[] chain,
- String authType, boolean isClient) {
- if (chain == null || chain.length == 0) {
- throw new IllegalArgumentException(
- "null or zero-length certificate chain");
- }
-
- if (authType == null || authType.length() == 0) {
- throw new IllegalArgumentException(
- "null or zero-length authentication type");
- }
-
- Validator v = null;
- if (isClient) {
- v = clientValidator;
- if (v == null) {
- synchronized (this) {
- v = clientValidator;
- if (v == null) {
- v = getValidator(Validator.VAR_TLS_CLIENT);
- clientValidator = v;
- }
- }
- }
- } else {
- // assume double checked locking with a volatile flag works
- // (guaranteed under the new Tiger memory model)
- v = serverValidator;
- if (v == null) {
- synchronized (this) {
- v = serverValidator;
- if (v == null) {
- v = getValidator(Validator.VAR_TLS_SERVER);
- serverValidator = v;
- }
- }
- }
- }
-
- return v;
- }
-
-
- private void checkTrusted(X509Certificate[] chain, String authType,
- Socket socket, boolean isClient) throws CertificateException {
- Validator v = checkTrustedInit(chain, authType, isClient);
-
- AlgorithmConstraints constraints = null;
- if ((socket != null) && socket.isConnected() &&
- (socket instanceof SSLSocket)) {
-
- SSLSocket sslSocket = (SSLSocket)socket;
- SSLSession session = sslSocket.getHandshakeSession();
- if (session == null) {
- throw new CertificateException("No handshake session");
- }
-
- // check endpoint identity
- String identityAlg = sslSocket.getSSLParameters().
- getEndpointIdentificationAlgorithm();
- if (identityAlg != null && identityAlg.length() != 0) {
- String hostname = session.getPeerHost();
- checkIdentity(hostname, chain[0], identityAlg);
- }
-
- // create the algorithm constraints
- ProtocolVersion protocolVersion =
- ProtocolVersion.valueOf(session.getProtocol());
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (session instanceof ExtendedSSLSession) {
- ExtendedSSLSession extSession =
- (ExtendedSSLSession)session;
- String[] localSupportedSignAlgs =
- extSession.getLocalSupportedSignatureAlgorithms();
-
- constraints = new SSLAlgorithmConstraints(
- sslSocket, localSupportedSignAlgs, false);
- } else {
- constraints =
- new SSLAlgorithmConstraints(sslSocket, false);
- }
- } else {
- constraints = new SSLAlgorithmConstraints(sslSocket, false);
- }
- }
-
- X509Certificate[] trustedChain = null;
- if (isClient) {
- trustedChain = validate(v, chain, constraints, null);
- } else {
- trustedChain = validate(v, chain, constraints, authType);
- }
- if (debug != null && Debug.isOn("trustmanager")) {
- System.out.println("Found trusted certificate:");
- System.out.println(trustedChain[trustedChain.length - 1]);
- }
- }
-
- private void checkTrusted(X509Certificate[] chain, String authType,
- SSLEngine engine, boolean isClient) throws CertificateException {
- Validator v = checkTrustedInit(chain, authType, isClient);
-
- AlgorithmConstraints constraints = null;
- if (engine != null) {
- SSLSession session = engine.getHandshakeSession();
- if (session == null) {
- throw new CertificateException("No handshake session");
- }
-
- // check endpoint identity
- String identityAlg = engine.getSSLParameters().
- getEndpointIdentificationAlgorithm();
- if (identityAlg != null && identityAlg.length() != 0) {
- String hostname = session.getPeerHost();
- checkIdentity(hostname, chain[0], identityAlg);
- }
-
- // create the algorithm constraints
- ProtocolVersion protocolVersion =
- ProtocolVersion.valueOf(session.getProtocol());
- if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
- if (session instanceof ExtendedSSLSession) {
- ExtendedSSLSession extSession =
- (ExtendedSSLSession)session;
- String[] localSupportedSignAlgs =
- extSession.getLocalSupportedSignatureAlgorithms();
-
- constraints = new SSLAlgorithmConstraints(
- engine, localSupportedSignAlgs, false);
- } else {
- constraints =
- new SSLAlgorithmConstraints(engine, false);
- }
- } else {
- constraints = new SSLAlgorithmConstraints(engine, false);
- }
- }
-
- X509Certificate[] trustedChain = null;
- if (isClient) {
- trustedChain = validate(v, chain, constraints, null);
- } else {
- trustedChain = validate(v, chain, constraints, authType);
- }
- if (debug != null && Debug.isOn("trustmanager")) {
- System.out.println("Found trusted certificate:");
- System.out.println(trustedChain[trustedChain.length - 1]);
- }
- }
-
- private void showTrustedCerts() {
- if (debug != null && Debug.isOn("trustmanager")) {
- for (X509Certificate cert : trustedCerts) {
- System.out.println("adding as trusted cert:");
- System.out.println(" Subject: "
- + cert.getSubjectX500Principal());
- System.out.println(" Issuer: "
- + cert.getIssuerX500Principal());
- System.out.println(" Algorithm: "
- + cert.getPublicKey().getAlgorithm()
- + "; Serial number: 0x"
- + cert.getSerialNumber().toString(16));
- System.out.println(" Valid from "
- + cert.getNotBefore() + " until "
- + cert.getNotAfter());
- System.out.println();
- }
- }
- }
-
- private Validator getValidator(String variant) {
- Validator v;
- if (pkixParams == null) {
- v = Validator.getInstance(validatorType, variant, trustedCerts);
- } else {
- v = Validator.getInstance(validatorType, variant, pkixParams);
- }
- return v;
- }
-
- private static X509Certificate[] validate(Validator v,
- X509Certificate[] chain, AlgorithmConstraints constraints,
- String authType) throws CertificateException {
- Object o = JsseJce.beginFipsProvider();
- try {
- return v.validate(chain, null, constraints, authType);
- } finally {
- JsseJce.endFipsProvider(o);
- }
- }
-
- /*
- * Identify the peer by its certificate and hostname.
- *
- * Lifted from sun.net.www.protocol.https.HttpsClient.
- */
- static void checkIdentity(String hostname, X509Certificate cert,
- String algorithm) throws CertificateException {
- if (algorithm != null && algorithm.length() != 0) {
- // if IPv6 strip off the "[]"
- if ((hostname != null) && hostname.startsWith("[") &&
- hostname.endsWith("]")) {
- hostname = hostname.substring(1, hostname.length() - 1);
- }
-
- if (algorithm.equalsIgnoreCase("HTTPS")) {
- HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
- hostname, cert);
- } else if (algorithm.equalsIgnoreCase("LDAP") ||
- algorithm.equalsIgnoreCase("LDAPS")) {
- HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match(
- hostname, cert);
- } else {
- throw new CertificateException(
- "Unknown identification algorithm: " + algorithm);
- }
- }
- }
-}
diff --git a/ojluni/src/main/java/sun/security/util/HostnameChecker.java b/ojluni/src/main/java/sun/security/util/HostnameChecker.java
deleted file mode 100755
index b3e8971..0000000
--- a/ojluni/src/main/java/sun/security/util/HostnameChecker.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.util;
-
-import java.io.IOException;
-import java.util.*;
-
-import java.security.Principal;
-import java.security.cert.*;
-
-import javax.security.auth.x500.X500Principal;
-
-import sun.security.ssl.Krb5Helper;
-import sun.security.x509.X500Name;
-
-import sun.net.util.IPAddressUtil;
-
-/**
- * Class to check hostnames against the names specified in a certificate as
- * required for TLS and LDAP.
- *
- */
-public class HostnameChecker {
-
- // Constant for a HostnameChecker for TLS
- public final static byte TYPE_TLS = 1;
- private final static HostnameChecker INSTANCE_TLS =
- new HostnameChecker(TYPE_TLS);
-
- // Constant for a HostnameChecker for LDAP
- public final static byte TYPE_LDAP = 2;
- private final static HostnameChecker INSTANCE_LDAP =
- new HostnameChecker(TYPE_LDAP);
-
- // constants for subject alt names of type DNS and IP
- private final static int ALTNAME_DNS = 2;
- private final static int ALTNAME_IP = 7;
-
- // the algorithm to follow to perform the check. Currently unused.
- private final byte checkType;
-
- private HostnameChecker(byte checkType) {
- this.checkType = checkType;
- }
-
- /**
- * Get a HostnameChecker instance. checkType should be one of the
- * TYPE_* constants defined in this class.
- */
- public static HostnameChecker getInstance(byte checkType) {
- if (checkType == TYPE_TLS) {
- return INSTANCE_TLS;
- } else if (checkType == TYPE_LDAP) {
- return INSTANCE_LDAP;
- }
- throw new IllegalArgumentException("Unknown check type: " + checkType);
- }
-
- /**
- * Perform the check.
- *
- * @exception CertificateException if the name does not match any of
- * the names specified in the certificate
- */
- public void match(String expectedName, X509Certificate cert)
- throws CertificateException {
- if (isIpAddress(expectedName)) {
- matchIP(expectedName, cert);
- } else {
- matchDNS(expectedName, cert);
- }
- }
-
- /**
- * Perform the check for Kerberos.
- */
- public static boolean match(String expectedName, Principal principal) {
- String hostName = getServerName(principal);
- return (expectedName.equalsIgnoreCase(hostName));
- }
-
- /**
- * Return the Server name from Kerberos principal.
- */
- public static String getServerName(Principal principal) {
- return Krb5Helper.getPrincipalHostName(principal);
- }
-
- /**
- * Test whether the given hostname looks like a literal IPv4 or IPv6
- * address. The hostname does not need to be a fully qualified name.
- *
- * This is not a strict check that performs full input validation.
- * That means if the method returns true, name need not be a correct
- * IP address, rather that it does not represent a valid DNS hostname.
- * Likewise for IP addresses when it returns false.
- */
- private static boolean isIpAddress(String name) {
- if (IPAddressUtil.isIPv4LiteralAddress(name) ||
- IPAddressUtil.isIPv6LiteralAddress(name)) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Check if the certificate allows use of the given IP address.
- *
- * From RFC2818:
- * In some cases, the URI is specified as an IP address rather than a
- * hostname. In this case, the iPAddress subjectAltName must be present
- * in the certificate and must exactly match the IP in the URI.
- */
- private static void matchIP(String expectedIP, X509Certificate cert)
- throws CertificateException {
- Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
- if (subjAltNames == null) {
- throw new CertificateException
- ("No subject alternative names present");
- }
- for (List<?> next : subjAltNames) {
- // For IP address, it needs to be exact match
- if (((Integer)next.get(0)).intValue() == ALTNAME_IP) {
- String ipAddress = (String)next.get(1);
- if (expectedIP.equalsIgnoreCase(ipAddress)) {
- return;
- }
- }
- }
- throw new CertificateException("No subject alternative " +
- "names matching " + "IP address " +
- expectedIP + " found");
- }
-
- /**
- * Check if the certificate allows use of the given DNS name.
- *
- * From RFC2818:
- * If a subjectAltName extension of type dNSName is present, that MUST
- * be used as the identity. Otherwise, the (most specific) Common Name
- * field in the Subject field of the certificate MUST be used. Although
- * the use of the Common Name is existing practice, it is deprecated and
- * Certification Authorities are encouraged to use the dNSName instead.
- *
- * Matching is performed using the matching rules specified by
- * [RFC2459]. If more than one identity of a given type is present in
- * the certificate (e.g., more than one dNSName name, a match in any one
- * of the set is considered acceptable.)
- */
- private void matchDNS(String expectedName, X509Certificate cert)
- throws CertificateException {
- Collection<List<?>> subjAltNames = cert.getSubjectAlternativeNames();
- if (subjAltNames != null) {
- boolean foundDNS = false;
- for ( List<?> next : subjAltNames) {
- if (((Integer)next.get(0)).intValue() == ALTNAME_DNS) {
- foundDNS = true;
- String dnsName = (String)next.get(1);
- if (isMatched(expectedName, dnsName)) {
- return;
- }
- }
- }
- if (foundDNS) {
- // if certificate contains any subject alt names of type DNS
- // but none match, reject
- throw new CertificateException("No subject alternative DNS "
- + "name matching " + expectedName + " found.");
- }
- }
- X500Name subjectName = getSubjectX500Name(cert);
- DerValue derValue = subjectName.findMostSpecificAttribute
- (X500Name.commonName_oid);
- if (derValue != null) {
- try {
- if (isMatched(expectedName, derValue.getAsString())) {
- return;
- }
- } catch (IOException e) {
- // ignore
- }
- }
- String msg = "No name matching " + expectedName + " found";
- throw new CertificateException(msg);
- }
-
-
- /**
- * Return the subject of a certificate as X500Name, by reparsing if
- * necessary. X500Name should only be used if access to name components
- * is required, in other cases X500Principal is to be prefered.
- *
- * This method is currently used from within JSSE, do not remove.
- */
- public static X500Name getSubjectX500Name(X509Certificate cert)
- throws CertificateParsingException {
- try {
- Principal subjectDN = cert.getSubjectDN();
- if (subjectDN instanceof X500Name) {
- return (X500Name)subjectDN;
- } else {
- X500Principal subjectX500 = cert.getSubjectX500Principal();
- return new X500Name(subjectX500.getEncoded());
- }
- } catch (IOException e) {
- throw(CertificateParsingException)
- new CertificateParsingException().initCause(e);
- }
- }
-
-
- /**
- * Returns true if name matches against template.<p>
- *
- * The matching is performed as per RFC 2818 rules for TLS and
- * RFC 2830 rules for LDAP.<p>
- *
- * The <code>name</code> parameter should represent a DNS name.
- * The <code>template</code> parameter
- * may contain the wildcard character *
- */
- private boolean isMatched(String name, String template) {
- if (checkType == TYPE_TLS) {
- return matchAllWildcards(name, template);
- } else if (checkType == TYPE_LDAP) {
- return matchLeftmostWildcard(name, template);
- } else {
- return false;
- }
- }
-
-
- /**
- * Returns true if name matches against template.<p>
- *
- * According to RFC 2818, section 3.1 -
- * Names may contain the wildcard character * which is
- * considered to match any single domain name component
- * or component fragment.
- * E.g., *.a.com matches foo.a.com but not
- * bar.foo.a.com. f*.com matches foo.com but not bar.com.
- */
- private static boolean matchAllWildcards(String name,
- String template) {
- name = name.toLowerCase();
- template = template.toLowerCase();
- StringTokenizer nameSt = new StringTokenizer(name, ".");
- StringTokenizer templateSt = new StringTokenizer(template, ".");
-
- if (nameSt.countTokens() != templateSt.countTokens()) {
- return false;
- }
-
- while (nameSt.hasMoreTokens()) {
- if (!matchWildCards(nameSt.nextToken(),
- templateSt.nextToken())) {
- return false;
- }
- }
- return true;
- }
-
-
- /**
- * Returns true if name matches against template.<p>
- *
- * As per RFC 2830, section 3.6 -
- * The "*" wildcard character is allowed. If present, it applies only
- * to the left-most name component.
- * E.g. *.bar.com would match a.bar.com, b.bar.com, etc. but not
- * bar.com.
- */
- private static boolean matchLeftmostWildcard(String name,
- String template) {
- name = name.toLowerCase();
- template = template.toLowerCase();
-
- // Retreive leftmost component
- int templateIdx = template.indexOf(".");
- int nameIdx = name.indexOf(".");
-
- if (templateIdx == -1)
- templateIdx = template.length();
- if (nameIdx == -1)
- nameIdx = name.length();
-
- if (matchWildCards(name.substring(0, nameIdx),
- template.substring(0, templateIdx))) {
-
- // match rest of the name
- return template.substring(templateIdx).equals(
- name.substring(nameIdx));
- } else {
- return false;
- }
- }
-
-
- /**
- * Returns true if the name matches against the template that may
- * contain wildcard char * <p>
- */
- private static boolean matchWildCards(String name, String template) {
-
- int wildcardIdx = template.indexOf("*");
- if (wildcardIdx == -1)
- return name.equals(template);
-
- boolean isBeginning = true;
- String beforeWildcard = "";
- String afterWildcard = template;
-
- while (wildcardIdx != -1) {
-
- // match in sequence the non-wildcard chars in the template.
- beforeWildcard = afterWildcard.substring(0, wildcardIdx);
- afterWildcard = afterWildcard.substring(wildcardIdx + 1);
-
- int beforeStartIdx = name.indexOf(beforeWildcard);
- if ((beforeStartIdx == -1) ||
- (isBeginning && beforeStartIdx != 0)) {
- return false;
- }
- isBeginning = false;
-
- // update the match scope
- name = name.substring(beforeStartIdx + beforeWildcard.length());
- wildcardIdx = afterWildcard.indexOf("*");
- }
- return name.endsWith(afterWildcard);
- }
-}
diff --git a/ojluni/src/main/native/AbstractPlainDatagramSocketImpl.c b/ojluni/src/main/native/AbstractPlainDatagramSocketImpl.c
new file mode 100644
index 0000000..d1de68f
--- /dev/null
+++ b/ojluni/src/main/native/AbstractPlainDatagramSocketImpl.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef __solaris__
+#include <unistd.h>
+#include <stropts.h>
+
+#ifndef BSD_COMP
+#define BSD_COMP
+#endif
+
+#endif
+
+#include <sys/ioctl.h>
+
+#include "jvm.h"
+#include "jni_util.h"
+#include "net_util.h"
+
+#include "java_net_AbstractPlainDatagramSocketImpl.h"
+
+#include "JNIHelp.h"
+
+#define NATIVE_METHOD(className, functionName, signature) \
+{ #functionName, signature, (void*)(className ## _ ## functionName) }
+
+static jfieldID IO_fd_fdID;
+
+static jfieldID apdsi_fdID;
+
+
+/*
+ * Class: java_net_AbstractPlainDatagramSocketImpl
+ * Method: init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_java_net_AbstractPlainDatagramSocketImpl_init(JNIEnv *env, jclass cls) {
+
+ apdsi_fdID = (*env)->GetFieldID(env, cls, "fd",
+ "Ljava/io/FileDescriptor;");
+ CHECK_NULL(apdsi_fdID);
+
+ IO_fd_fdID = NET_GetFileDescriptorID(env);
+}
+
+/*
+ * Class: java_net_AbstractPlainDatagramSocketImpl
+ * Method: dataAvailable
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_java_net_AbstractPlainDatagramSocketImpl_dataAvailable
+(JNIEnv *env, jobject this) {
+ int fd, retval;
+
+ jobject fdObj = (*env)->GetObjectField(env, this, apdsi_fdID);
+
+ if (IS_NULL(fdObj)) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+ "Socket closed");
+ return -1;
+ }
+ fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+
+ if (ioctl(fd, FIONREAD, &retval) < 0) {
+ return -1;
+ }
+ return retval;
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Java_java_net_AbstractPlainDatagramSocketImpl, init, "()V"),
+ NATIVE_METHOD(Java_java_net_AbstractPlainDatagramSocketImpl, dataAvailable, "()I"),
+};
+
+void register_java_net_AbstractPlainDatagramSocketImpl(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/net/AbstractPlainDatagramSocketImpl", gMethods, NELEM(gMethods));
+}
diff --git a/ojluni/src/main/native/Register.cpp b/ojluni/src/main/native/Register.cpp
index c40dcd1..89dca05 100644
--- a/ojluni/src/main/native/Register.cpp
+++ b/ojluni/src/main/native/Register.cpp
@@ -52,6 +52,7 @@
extern void register_java_lang_System(JNIEnv*);
extern void register_java_lang_Thread(JNIEnv*);
extern void register_java_lang_UNIXProcess(JNIEnv*);
+extern void register_java_net_AbstractPlainDatagramSocketImpl(JNIEnv*);
extern void register_java_net_DatagramPacket(JNIEnv*);
extern void register_java_net_Inet4Address(JNIEnv*);
extern void register_java_net_Inet6Address(JNIEnv*);
@@ -130,6 +131,7 @@
// register_java_net_InetAddress depends on java_lang_Float & Math being
// fully registered (getMethodId on InetAddress class triggers its
// <clinit> which depends on java.lang.Float)
+ register_java_net_AbstractPlainDatagramSocketImpl(env);
register_java_net_InetAddress(env);
register_java_net_Inet4Address(env);
register_java_net_Inet6Address(env);
diff --git a/ojluni/src/main/native/java_net_AbstractPlainDatagramSocketImpl.h b/ojluni/src/main/native/java_net_AbstractPlainDatagramSocketImpl.h
new file mode 100644
index 0000000..5a50671
--- /dev/null
+++ b/ojluni/src/main/native/java_net_AbstractPlainDatagramSocketImpl.h
@@ -0,0 +1,57 @@
+/* This file was generated from java/net/AbstractPlainDatagramSocketImpl.java
+ * and is licensed under the same terms. The copyright and license information
+ * for java/net/AbstractPlainDatagramSocketImpl.java follows.
+ *
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class java_net_AbstractPlainDatagramSocketImpl */
+
+#ifndef _Included_java_net_AbstractPlainDatagramSocketImpl
+#define _Included_java_net_AbstractPlainDatagramSocketImpl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class: java_net_AbstractPlainDatagramSocketImpl
+ * Method: dataAvailable
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_java_net_AbstractPlainDatagramSocketImpl_dataAvailable
+ (JNIEnv *, jobject);
+
+/*
+ * Class: java_net_AbstractPlainDatagramSocketImpl
+ * Method: init
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_net_AbstractPlainDatagramSocketImpl_init
+ (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/ojluni/src/main/native/openjdksub.mk b/ojluni/src/main/native/openjdksub.mk
index 41f6e482..e861230 100644
--- a/ojluni/src/main/native/openjdksub.mk
+++ b/ojluni/src/main/native/openjdksub.mk
@@ -75,6 +75,7 @@
Character.cpp \
Register.cpp \
socket_tagger_util.cpp \
+ AbstractPlainDatagramSocketImpl.c \
LOCAL_C_INCLUDES += \
libcore/$(srcdir) \
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index fba2e73..9fa9afa 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -262,6 +262,7 @@
ojluni/src/main/java/java/net/Inet4Address.java \
ojluni/src/main/java/java/net/Inet6AddressImpl.java \
ojluni/src/main/java/java/net/Inet6Address.java \
+ ojluni/src/main/java/java/net/InetAddressContainer.java \
ojluni/src/main/java/java/net/InetAddressImpl.java \
ojluni/src/main/java/java/net/InetAddress.java \
ojluni/src/main/java/java/net/InetSocketAddress.java \
@@ -846,6 +847,7 @@
ojluni/src/main/java/java/util/function/ToLongBiFunction.java \
ojluni/src/main/java/java/util/function/ToLongFunction.java \
ojluni/src/main/java/java/util/function/UnaryOperator.java \
+ ojluni/src/main/java/java/util/function/package-info.java \
ojluni/src/main/java/java/util/jar/Attributes.java \
ojluni/src/main/java/java/util/jar/JarEntry.java \
ojluni/src/main/java/java/util/jar/JarException.java \
@@ -1134,7 +1136,6 @@
ojluni/src/main/java/sun/reflect/CallerSensitive.java \
openjdk_java_files := \
- ojluni/src/main/java/com/sun/net/ssl/internal/ssl/Provider.java \
ojluni/src/main/java/com/sun/net/ssl/internal/ssl/X509ExtendedTrustManager.java \
ojluni/src/main/java/com/sun/security/cert/internal/x509/X509V1CertImpl.java \
ojluni/src/main/java/com/sun/nio/file/ExtendedCopyOption.java \
@@ -1143,8 +1144,8 @@
ojluni/src/main/java/com/sun/nio/file/SensitivityWatchEventModifier.java \
ojluni/src/main/java/java/beans/ChangeListenerMap.java \
ojluni/src/main/java/java/lang/Shutdown.java \
- ojluni/src/main/java/sun/misc/FDBigInt.java \
- ojluni/src/main/java/java/lang/FloatingDecimal.java \
+ ojluni/src/main/java/sun/misc/FDBigInteger.java \
+ ojluni/src/main/java/sun/misc/FloatingDecimal.java \
ojluni/src/main/java/java/text/spi/BreakIteratorProvider.java \
ojluni/src/main/java/java/text/spi/CollatorProvider.java \
ojluni/src/main/java/java/text/spi/DateFormatProvider.java \
@@ -1226,60 +1227,46 @@
ojluni/src/main/java/sun/net/TransferProtocolClient.java \
ojluni/src/main/java/sun/net/util/IPAddressUtil.java \
ojluni/src/main/java/sun/net/util/URLUtil.java \
- ojluni/src/main/java/sun/net/www/ApplicationLaunchException.java \
ojluni/src/main/java/sun/net/www/HeaderParser.java \
+ ojluni/src/main/java/sun/net/www/MessageHeader.java \
+ ojluni/src/main/java/sun/net/www/MeteredStream.java \
+ ojluni/src/main/java/sun/net/www/ParseUtil.java \
+ ojluni/src/main/java/sun/net/www/URLConnection.java \
ojluni/src/main/java/sun/net/www/http/ChunkedInputStream.java \
ojluni/src/main/java/sun/net/www/http/ChunkedOutputStream.java \
- ojluni/src/main/java/sun/net/www/http/HttpCaptureInputStream.java \
ojluni/src/main/java/sun/net/www/http/HttpCapture.java \
+ ojluni/src/main/java/sun/net/www/http/HttpCaptureInputStream.java \
ojluni/src/main/java/sun/net/www/http/HttpCaptureOutputStream.java \
ojluni/src/main/java/sun/net/www/http/HttpClient.java \
ojluni/src/main/java/sun/net/www/http/Hurryable.java \
ojluni/src/main/java/sun/net/www/http/KeepAliveCache.java \
- ojluni/src/main/java/sun/net/www/http/KeepAliveStreamCleaner.java \
ojluni/src/main/java/sun/net/www/http/KeepAliveStream.java \
+ ojluni/src/main/java/sun/net/www/http/KeepAliveStreamCleaner.java \
ojluni/src/main/java/sun/net/www/http/PosterOutputStream.java \
- ojluni/src/main/java/sun/net/www/MessageHeader.java \
- ojluni/src/main/java/sun/net/www/MeteredStream.java \
- ojluni/src/main/java/sun/net/www/MimeEntry.java \
- ojluni/src/main/java/sun/net/www/MimeLauncher.java \
- ojluni/src/main/java/sun/net/www/MimeTable.java \
- ojluni/src/main/java/sun/net/www/ParseUtil.java \
ojluni/src/main/java/sun/net/www/protocol/file/FileURLConnection.java \
ojluni/src/main/java/sun/net/www/protocol/file/Handler.java \
ojluni/src/main/java/sun/net/www/protocol/ftp/FtpURLConnection.java \
ojluni/src/main/java/sun/net/www/protocol/ftp/Handler.java \
- ojluni/src/main/java/sun/net/www/protocol/gopher/GopherClient.java \
- ojluni/src/main/java/sun/net/www/protocol/gopher/Handler.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheImpl.java \
ojluni/src/main/java/sun/net/www/protocol/http/AuthCache.java \
+ ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheImpl.java \
ojluni/src/main/java/sun/net/www/protocol/http/AuthCacheValue.java \
+ ojluni/src/main/java/sun/net/www/protocol/http/AuthScheme.java \
ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationHeader.java \
ojluni/src/main/java/sun/net/www/protocol/http/AuthenticationInfo.java \
- ojluni/src/main/java/sun/net/www/protocol/http/AuthScheme.java \
ojluni/src/main/java/sun/net/www/protocol/http/BasicAuthentication.java \
ojluni/src/main/java/sun/net/www/protocol/http/DigestAuthentication.java \
ojluni/src/main/java/sun/net/www/protocol/http/Handler.java \
ojluni/src/main/java/sun/net/www/protocol/http/HttpAuthenticator.java \
ojluni/src/main/java/sun/net/www/protocol/http/HttpCallerInfo.java \
ojluni/src/main/java/sun/net/www/protocol/http/HttpURLConnection.java \
+ ojluni/src/main/java/sun/net/www/protocol/http/NTLMAuthenticationProxy.java \
ojluni/src/main/java/sun/net/www/protocol/http/NegotiateAuthentication.java \
ojluni/src/main/java/sun/net/www/protocol/http/Negotiator.java \
- ojluni/src/main/java/sun/net/www/protocol/http/NTLMAuthenticationProxy.java \
- ojluni/src/main/java/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java \
- ojluni/src/main/java/sun/net/www/protocol/https/DelegateHttpsURLConnection.java \
- ojluni/src/main/java/sun/net/www/protocol/https/Handler.java \
- ojluni/src/main/java/sun/net/www/protocol/https/HttpsClient.java \
- ojluni/src/main/java/sun/net/www/protocol/https/HttpsURLConnectionImpl.java \
ojluni/src/main/java/sun/net/www/protocol/jar/Handler.java \
ojluni/src/main/java/sun/net/www/protocol/jar/JarFileFactory.java \
ojluni/src/main/java/sun/net/www/protocol/jar/JarURLConnection.java \
- ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFileCallBack.java \
ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFile.java \
- ojluni/src/main/java/sun/net/www/protocol/mailto/Handler.java \
- ojluni/src/main/java/sun/net/www/protocol/mailto/MailToURLConnection.java \
- ojluni/src/main/java/sun/net/www/protocol/netdoc/Handler.java \
- ojluni/src/main/java/sun/net/www/URLConnection.java \
+ ojluni/src/main/java/sun/net/www/protocol/jar/URLJarFileCallBack.java \
ojluni/src/main/java/sun/nio/ByteBuffered.java \
ojluni/src/main/java/sun/nio/ch/AbstractPollArrayWrapper.java \
ojluni/src/main/java/sun/nio/ch/AbstractPollSelectorImpl.java \
@@ -1477,61 +1464,6 @@
ojluni/src/main/java/sun/security/provider/certpath/X509CertificatePair.java \
ojluni/src/main/java/sun/security/provider/X509Factory.java \
ojluni/src/main/java/sun/security/rsa/SunRsaSignEntries.java \
- ojluni/src/main/java/sun/security/ssl/Alerts.java \
- ojluni/src/main/java/sun/security/ssl/AppInputStream.java \
- ojluni/src/main/java/sun/security/ssl/AppOutputStream.java \
- ojluni/src/main/java/sun/security/ssl/BaseSSLSocketImpl.java \
- ojluni/src/main/java/sun/security/ssl/ByteBufferInputStream.java \
- ojluni/src/main/java/sun/security/ssl/CipherBox.java \
- ojluni/src/main/java/sun/security/ssl/CipherSuite.java \
- ojluni/src/main/java/sun/security/ssl/CipherSuiteList.java \
- ojluni/src/main/java/sun/security/ssl/ClientHandshaker.java \
- ojluni/src/main/java/sun/security/ssl/Debug.java \
- ojluni/src/main/java/sun/security/ssl/DHClientKeyExchange.java \
- ojluni/src/main/java/sun/security/ssl/DHCrypt.java \
- ojluni/src/main/java/sun/security/ssl/ECDHClientKeyExchange.java \
- ojluni/src/main/java/sun/security/ssl/ECDHCrypt.java \
- ojluni/src/main/java/sun/security/ssl/EngineArgs.java \
- ojluni/src/main/java/sun/security/ssl/EngineInputRecord.java \
- ojluni/src/main/java/sun/security/ssl/EngineOutputRecord.java \
- ojluni/src/main/java/sun/security/ssl/EngineWriter.java \
- ojluni/src/main/java/sun/security/ssl/EphemeralKeyManager.java \
- ojluni/src/main/java/sun/security/ssl/HandshakeHash.java \
- ojluni/src/main/java/sun/security/ssl/HandshakeInStream.java \
- ojluni/src/main/java/sun/security/ssl/HandshakeMessage.java \
- ojluni/src/main/java/sun/security/ssl/HandshakeOutStream.java \
- ojluni/src/main/java/sun/security/ssl/Handshaker.java \
- ojluni/src/main/java/sun/security/ssl/HelloExtensions.java \
- ojluni/src/main/java/sun/security/ssl/InputRecord.java \
- ojluni/src/main/java/sun/security/ssl/JsseJce.java \
- ojluni/src/main/java/sun/security/ssl/KerberosClientKeyExchange.java \
- ojluni/src/main/java/sun/security/ssl/Krb5Helper.java \
- ojluni/src/main/java/sun/security/ssl/Krb5Proxy.java \
- ojluni/src/main/java/sun/security/ssl/MAC.java \
- ojluni/src/main/java/sun/security/ssl/OutputRecord.java \
- ojluni/src/main/java/sun/security/ssl/ProtocolList.java \
- ojluni/src/main/java/sun/security/ssl/ProtocolVersion.java \
- ojluni/src/main/java/sun/security/ssl/RandomCookie.java \
- ojluni/src/main/java/sun/security/ssl/Record.java \
- ojluni/src/main/java/sun/security/ssl/RSAClientKeyExchange.java \
- ojluni/src/main/java/sun/security/ssl/RSASignature.java \
- ojluni/src/main/java/sun/security/ssl/ServerHandshaker.java \
- ojluni/src/main/java/sun/security/ssl/SessionId.java \
- ojluni/src/main/java/sun/security/ssl/SignatureAndHashAlgorithm.java \
- ojluni/src/main/java/sun/security/ssl/SSLAlgorithmConstraints.java \
- ojluni/src/main/java/sun/security/ssl/SSLContextImpl.java \
- ojluni/src/main/java/sun/security/ssl/SSLEngineImpl.java \
- ojluni/src/main/java/sun/security/ssl/SSLServerSocketFactoryImpl.java \
- ojluni/src/main/java/sun/security/ssl/SSLServerSocketImpl.java \
- ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java \
- ojluni/src/main/java/sun/security/ssl/SSLSessionImpl.java \
- ojluni/src/main/java/sun/security/ssl/SSLSocketFactoryImpl.java \
- ojluni/src/main/java/sun/security/ssl/SSLSocketImpl.java \
- ojluni/src/main/java/sun/security/ssl/SunJSSE.java \
- ojluni/src/main/java/sun/security/ssl/SunX509KeyManagerImpl.java \
- ojluni/src/main/java/sun/security/ssl/TrustManagerFactoryImpl.java \
- ojluni/src/main/java/sun/security/ssl/X509KeyManagerImpl.java \
- ojluni/src/main/java/sun/security/ssl/X509TrustManagerImpl.java \
ojluni/src/main/java/sun/security/timestamp/TimestampToken.java \
ojluni/src/main/java/sun/security/util/BitArray.java \
ojluni/src/main/java/sun/security/util/ByteArrayLexOrder.java \
@@ -1545,7 +1477,6 @@
ojluni/src/main/java/sun/security/util/DerOutputStream.java \
ojluni/src/main/java/sun/security/util/DerValue.java \
ojluni/src/main/java/sun/security/util/DisabledAlgorithmConstraints.java \
- ojluni/src/main/java/sun/security/util/HostnameChecker.java \
ojluni/src/main/java/sun/security/util/KeyUtil.java \
ojluni/src/main/java/sun/security/util/Length.java \
ojluni/src/main/java/sun/security/util/ManifestDigester.java \
diff --git a/support/src/test/java/tests/util/SummaryStatistics.java b/support/src/test/java/tests/util/SummaryStatistics.java
index 4ce0a04..7a0d0b1 100644
--- a/support/src/test/java/tests/util/SummaryStatistics.java
+++ b/support/src/test/java/tests/util/SummaryStatistics.java
@@ -23,11 +23,13 @@
/** Sum of the values. */
private double sum;
- /** Sum of the squares of the values added. */
- private double squaresSum;
+ /** Use the first value to shift all values to it when computing variance, as it improves
+ * numerical stability. Note variance is invariant to shifting. */
+ private Double firstValue = null;
- /** The previously added value. */
- private double lastValue;
+ /** Sum of the squares of the values added, shifted according to the first value. */
+ private double shiftedSquaresSum;
+
public SummaryStatistics() {
}
@@ -38,10 +40,12 @@
/** Add a new value to the values seen. */
public void add(double value) {
- sum += value - lastValue;
- squaresSum += square(value) - square(lastValue);
+ if (firstValue == null) {
+ firstValue = new Double(value);
+ }
+ sum += value;
+ shiftedSquaresSum += square(value - firstValue);
numValues++;
- lastValue = value;
}
/** Mean of the values seen. */
@@ -51,7 +55,8 @@
/** Variance of the values seen. */
public double var() {
- return (squaresSum / numValues) - square(mean());
+ double shiftedMean = (sum - numValues * firstValue) / numValues;
+ return (shiftedSquaresSum / numValues) - square(shiftedMean);
}
/** Standard deviation of the values seen. */