古めのJerseyClient&Oracle JDK1.6でBouncyCastleを使いTLS1.2接続

#はじめに
JDK1.6で動いている環境から社内のシステムにTLS1.2で接続する必要があり、いろいろと調べた結果BouncyCastleを使うしか方法がなく、なんとか接続できたので記録として残しておきます。
社で使用しているJDKはIBM JDK1.6のため、まだサポートがありTLS1.2接続も可能でした。しかし、接続先が許可しているCipherと一致するものが存在せず、BouncyCastleに頼ることにしました。

こちらの記事は自宅で確認したため、Oracle JDKを使用しています。
ちなみにOracleについても[https://www.oracle.com/technetwork/java/javase/overview-156328.html#R160_121](https://www.oracle.com/technetwork/java/javase/overview-156328.html#R160_121)に記載があるように商用サポートを受ければTLS1.2が使えるバージョンが入手可能のようです。ただし、Cipher Suitesがどうなっているかは要確認です。

#動作確認環境
OS:Window 10
Oracle JDK: Version 1.6.0_45
Java Library:
bcprov-jdk15on-160.jar
bctls-jdk15on-160.jar
jersey-client-1.8.jar
jersey-core-1.8.jar
json-20131018.jar

#1. Bouncy Castleの設定
%JAVA_HOME%\jre\lib\security\java.securityに
***security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider***
を追加します。

```
#
# List of providers and their preference orders (see above):
#
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=com.sun.net.ssl.internal.ssl.Provider
security.provider.4=com.sun.crypto.provider.SunJCE
security.provider.5=sun.security.jgss.SunProvider
security.provider.6=com.sun.security.sasl.Provider
security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.8=sun.security.smartcardio.SunPCSC
security.provider.9=sun.security.mscapi.SunMSCAPI
security.provider.10=org.bouncycastle.jce.provider.BouncyCastleProvider
```

#2. ソースコード準備

```BCtest.java
package tlsclient.tworks55;

import java.security.Security;

public class BCtest {

	public static void main(String[] args) {
		// BC is the ID for the Bouncy Castle provider;
		if (Security.getProvider("BC") == null) {
			System.out.println("Bouncy Castle provider is NOT available");
		} else {
			System.out.println("Bouncy Castle provider is available");
		}
	}

}
```

```TLSJerseyClientTest.java
package tlsclient.tworks55;

import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.json.JSONObject;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.client.urlconnection.HTTPSProperties;

import java.security.Provider;
import java.security.Security;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.ws.rs.core.MediaType;

public class TLSJerseyClientTest {
	public static void main(String[] args) {
		try {
			TrustManager[] trustAllCerts = { new InsecureTrustManager() };
			HostnameVerifier hostnameVerifier = HttpsURLConnection.getDefaultHostnameVerifier();
			ClientConfig config = new DefaultClientConfig();

			Provider provider = new BouncyCastleJsseProvider();
			Security.addProvider(provider);
			SSLContext ctx = SSLContext.getInstance("TLSv1.2", provider.getName());

			ctx.init(null, trustAllCerts, null);

			config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
					new HTTPSProperties(hostnameVerifier, ctx));
			Client c = Client.create(config);
			WebResource resource = c.resource("https://github.com/login/oauth/access_token");

			JSONObject jsonObject = new JSONObject();
			jsonObject.put("client_id", "*** Set client_id here ***");
			jsonObject.put("client_secret", "*** Set client_secret here ***");
			jsonObject.put("code", "*** Set code here ***");
			String response = resource.type(MediaType.APPLICATION_JSON_TYPE).post(String.class, jsonObject.toString());

			System.out.println(response);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
```

```InsecureTrustManager.java
package tlsclient.tworks55;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;

public class InsecureTrustManager implements X509TrustManager {
    /**
     * {@inheritDoc}
     */
    public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
        // Everyone is trusted!
    }

    /**
     * {@inheritDoc}
     */
    public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
        // Everyone is trusted!
    }

    /**
     * {@inheritDoc}
     */
    public X509Certificate[] getAcceptedIssuers() {
        return new X509Certificate[0];
    }
}
```
※Githubは[こちら](https://github.com/tworks55/mytlsclient)

#3. Bouncy Castleが読めているか確認
BCtest.javaを実行し"Bouncy Castle provider is available"が表示されることを確認します。

```
Bouncy Castle provider is available
```
**Not** Availableになった場合は、設定がうまくいっていません。


#4. TLSv1.2でサイトに接続
上記ソースコードは、GithubithubにAuthorizing OAuth Appsの設定をした上で、OAuth Tokenを取得する部分を試す感じになっています。
GithubのOauth Appsは[https://github.com/settings/applications/new](https://github.com/settings/applications/new)で作成可能です。
client_id及びclient_secretは、アプリ作成時にサイトに表示されますが、codeについては動的に生成する必要があります。

ブラウザで以下のようにClient_idをセットするとcallback URLに対してcodeがパラメーターとして渡されます。
[https://github.com/login/oauth/authorize?client_id=[Set Client id here]](https://github.com/login/oauth/authorize?client_id=Set Client id here)

Callback URLをLocalhostなどにしておけば、ブラウザ上に
http://localhost:5555/?code=d86cabc30fdabc6abcb8
といった形で表示されますので、これをメモしておきます。

TLSJerseyClientTest.javaの以下にそれぞれパラメーターをセットして、実行します。

```
jsonObject.put("client_id", "*** Set client_id here ***");
jsonObject.put("client_secret", "*** Set client_secret here ***");
jsonObject.put("code", "*** Set code here ***");
```
うまく行けば、以下のような結果が得られます。

```
access_token=abc4cf0fda71e2abc358c22fba7abc8aabc56abc&scope=&token_type=bearer
```


#5. java.security.InvalidKeyException: Illegal key size が発生する場合の対応
接続先の状況によるものだと思いますが、InvalidKeyExceptionが発生するケースがあるようです。
その際は[jce_policy-6](https://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html)をダウンロードし、以下にライブラリをコピーすると動作するようです。

%JAVA_HOME%\jre\lib\security
local_policy.jar
US_export_policy.jar

以下、InvalidKeyException発生例:

```
2019/01/26 23:06:46 org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertRaised
警告: Client raised fatal(2) internal_error(80) alert: Failed to read record
java.lang.RuntimeException: java.security.InvalidKeyException: Illegal key size
	at org.bouncycastle.tls.crypto.impl.jcajce.JceChaCha20Poly1305.init(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.TlsAEADCipher.<init>(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.createChaCha20Poly1305(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.createCipher(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.AbstractTlsSecret.createCipher(Unknown Source)
	at org.bouncycastle.tls.AbstractTlsClient.getCipher(Unknown Source)
	at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
	at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
	at org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
	at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
	at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
	at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
	at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
	at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
	at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
	at com.sun.jersey.client.urlconnection.URLConnectionClientHandler$1$1.getOutputStream(URLConnectionClientHandler.java:225)
	at com.sun.jersey.api.client.CommittingOutputStream.commitWrite(CommittingOutputStream.java:117)
	at com.sun.jersey.api.client.CommittingOutputStream.write(CommittingOutputStream.java:89)
	at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
	at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
	at java.io.BufferedWriter.flush(BufferedWriter.java:236)
	at com.sun.jersey.core.util.ReaderWriter.writeToAsString(ReaderWriter.java:191)
	at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:128)
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:88)
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:58)
	at com.sun.jersey.api.client.RequestWriter.writeRequestEntity(RequestWriter.java:300)
	at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:204)
	at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:147)
	at com.sun.jersey.api.client.Client.handle(Client.java:648)
	at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670)
	at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
	at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:563)
	at tlsclient.tworks55.TLSJerseyClientTest.main(TLSJerseyClientTest.java:42)
Caused by: java.security.InvalidKeyException: Illegal key size
	at javax.crypto.Cipher.a(DashoA13*..)
	at javax.crypto.Cipher.a(DashoA13*..)
	at javax.crypto.Cipher.a(DashoA13*..)
	at javax.crypto.Cipher.init(DashoA13*..)
	at javax.crypto.Cipher.init(DashoA13*..)
	... 39 more
com.sun.jersey.api.client.ClientHandlerException: org.bouncycastle.tls.TlsFatalAlert: internal_error(80)
	at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:149)
	at com.sun.jersey.api.client.Client.handle(Client.java:648)
	at com.sun.jersey.api.client.WebResource.handle(WebResource.java:670)
	at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
	at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:563)
	at tlsclient.tworks55.TLSJerseyClientTest.main(TLSJerseyClientTest.java:42)
Caused by: org.bouncycastle.tls.TlsFatalAlert: internal_error(80)
	at org.bouncycastle.tls.TlsProtocol.safeReadRecord(Unknown Source)
	at org.bouncycastle.tls.TlsProtocol.blockForHandshake(Unknown Source)
	at org.bouncycastle.tls.TlsClientProtocol.connect(Unknown Source)
	at org.bouncycastle.jsse.provider.ProvSSLSocketDirect.startHandshake(Unknown Source)
	at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
	at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
	at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1031)
	at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
	at com.sun.jersey.client.urlconnection.URLConnectionClientHandler$1$1.getOutputStream(URLConnectionClientHandler.java:225)
	at com.sun.jersey.api.client.CommittingOutputStream.commitWrite(CommittingOutputStream.java:117)
	at com.sun.jersey.api.client.CommittingOutputStream.write(CommittingOutputStream.java:89)
	at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
	at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:272)
	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:276)
	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:122)
	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:212)
	at java.io.BufferedWriter.flush(BufferedWriter.java:236)
	at com.sun.jersey.core.util.ReaderWriter.writeToAsString(ReaderWriter.java:191)
	at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeToAsString(AbstractMessageReaderWriterProvider.java:128)
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:88)
	at com.sun.jersey.core.impl.provider.entity.StringProvider.writeTo(StringProvider.java:58)
	at com.sun.jersey.api.client.RequestWriter.writeRequestEntity(RequestWriter.java:300)
	at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:204)
	at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:147)
	... 5 more
Caused by: java.lang.RuntimeException: java.security.InvalidKeyException: Illegal key size
	at org.bouncycastle.tls.crypto.impl.jcajce.JceChaCha20Poly1305.init(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.TlsAEADCipher.<init>(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.createChaCha20Poly1305(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCrypto.createCipher(Unknown Source)
	at org.bouncycastle.tls.crypto.impl.AbstractTlsSecret.createCipher(Unknown Source)
	at org.bouncycastle.tls.AbstractTlsClient.getCipher(Unknown Source)
	at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(Unknown Source)
	at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(Unknown Source)
	at org.bouncycastle.tls.TlsProtocol.processRecord(Unknown Source)
	at org.bouncycastle.tls.RecordStream.readRecord(Unknown Source)
	... 29 more
Caused by: java.security.InvalidKeyException: Illegal key size
	at javax.crypto.Cipher.a(DashoA13*..)
	at javax.crypto.Cipher.a(DashoA13*..)
	at javax.crypto.Cipher.a(DashoA13*..)
	at javax.crypto.Cipher.init(DashoA13*..)
	at javax.crypto.Cipher.init(DashoA13*..)
	... 39 more
```

# 参考URL
[https://www.bouncycastle.org/](https://www.bouncycastle.org/)
[http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions#FrequentlyAskedQuestions-1.WhydoIget%22java.lang.SecurityException:Unsupportedkeysizeoralgorithmparameters%22or%22java.security.InvalidKeyException:Illegalkeysize%22whenItryusingtheBouncyCastleProvider?](http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions#FrequentlyAskedQuestions-1.WhydoIget%22java.lang.SecurityException:Unsupportedkeysizeoralgorithmparameters%22or%22java.security.InvalidKeyException:Illegalkeysize%22whenItryusingtheBouncyCastleProvider?)
[http://tech-son.hatenablog.jp/entry/2017/11/01/003000](http://tech-son.hatenablog.jp/entry/2017/11/01/003000)
[https://stackoverflow.com/questions/33364100/how-to-use-tls-1-2-in-java-6](https://stackoverflow.com/questions/33364100/how-to-use-tls-1-2-in-java-6)
[https://stackoverflow.com/questions/6363801/invalidkeyexception-illegal-key-size-java-code-throwing-exception-for-encryp?rq=1](https://stackoverflow.com/questions/6363801/invalidkeyexception-illegal-key-size-java-code-throwing-exception-for-encryp?rq=1)
[https://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html](https://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html)
[https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/](https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/)