title: BouncyCastleJsseProvider: Client raised fatal(2) internal_error(80) alert: Failed to read record
body: <p>I have run into an issue developing a HTTP client with the use of BouncyCastle libraries.
  Target versions (but the error is also reproducible in <strong>Java 1.8.0_91</strong> with the same version of BouncyCastle.)</p>
  <ul>
  <li>JRE 1.6.0_45-b06</li>
  <li>BouncyCastle jdk15to18 167 (bcprov-jdk15to18-167.jar, bcpkix-jdk15to18-167.jar, bctls-jdk15to18-167.jar)</li>
  </ul>
  <p>HTTPClient code:</p>
  <pre><code>            String strURL = &quot;https://www.&lt;WEBSITE&gt;.com&quot;;
              // CODE to set default TrustStore, KeyStore to be used
  
              // setup BC as SecurityProvider and SSLSocketFactoryProvider
  /*
              Security.insertProviderAt(new BouncyCastleProvider(), 1);
              Security.insertProviderAt(new BouncyCastleJsseProvider(), 2);
              Security.setProperty(&quot;ssl.KeyManagerFactory.algorithm&quot;, &quot;PKIX&quot;);
              Security.setProperty(&quot;ssl.TrustManagerFactory.algorithm&quot;, &quot;PKIX&quot;);  
              Security.setProperty(&quot;ssl.SocketFactory.provider&quot;, &quot;org.bouncycastle.jsse.provider.SSLSocketFactoryImpl&quot;);
              System.setProperty(&quot;jdk.tls.trustNameService&quot;, &quot;true&quot;);
  */
              URL url = new URL( strURL );
              HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
              conn.setDoOutput(true);
              conn.setRequestMethod(&quot;GET&quot;);
              
              InputStream is = null;
              if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                  System.out.println(&quot;OK&quot;);
                  is = conn.getInputStream();
              } else if (conn.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
                  System.out.println(&quot;ERROR&quot;);
                  is = conn.getErrorStream();
              } else  {
                  System.out.println( conn.getResponseCode() );
                  System.out.println( conn.getResponseMessage() );
              }
          
              if (is != null) {  
                  System.out.println( readFullyAsString(is, &quot;UTF-8&quot;) );
              }
              conn.disconnect();
  </code></pre>
  <p>Accessing data on a website with TLS 1.2 <strong>without client_auth</strong> works fine (there are some issues with specific sites that return handshake_failure(40), but luckily not in our case). But when client_auth is required the code fails with the following (<em>a little cryptic</em>) error:</p>
  <pre><code>nov. 27, 2020 5:23:10 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertRaised
  WARNING: Client raised fatal(2) internal_error(80) alert: Failed to read record
  java.net.SocketException: Connection reset
      at java.net.SocketInputStream.read(Unknown Source)
      at java.net.SocketInputStream.read(Unknown Source)
      at org.bouncycastle.tls.RecordStream$Record.fillTo(RecordStream.java:429)
      at org.bouncycastle.tls.RecordStream$Record.readHeader(RecordStream.java:468)
      at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:201)
      at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:768)
      at org.bouncycastle.tls.TlsProtocol.readApplicationData(TlsProtocol.java:731)
      at org.bouncycastle.jsse.provider.ProvSSLSocketDirect$AppDataInput.read(ProvSSLSocketDirect.java:603)
      at java.io.BufferedInputStream.fill(Unknown Source)
      at java.io.BufferedInputStream.read1(Unknown Source)
      at java.io.BufferedInputStream.read(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
      at java.net.HttpURLConnection.getResponseCode(Unknown Source)
      at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
      at HttpsClient.main(HttpsClient.java:109)
  
  nov. 27, 2020 5:23:10 PM org.bouncycastle.jsse.provider.ProvTlsClient notifyAlertRaised
  WARNING: Client raised fatal(2) internal_error(80) alert: Failed to read record
  java.net.SocketException: Connection reset
      at java.net.SocketInputStream.read(Unknown Source)
      at java.net.SocketInputStream.read(Unknown Source)
      at org.bouncycastle.tls.RecordStream$Record.fillTo(RecordStream.java:429)
      at org.bouncycastle.tls.RecordStream$Record.readHeader(RecordStream.java:468)
      at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:201)
      at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:768)
      at org.bouncycastle.tls.TlsProtocol.readApplicationData(TlsProtocol.java:731)
      at org.bouncycastle.jsse.provider.ProvSSLSocketDirect$AppDataInput.read(ProvSSLSocketDirect.java:603)
      at java.io.BufferedInputStream.fill(Unknown Source)
      at java.io.BufferedInputStream.read1(Unknown Source)
      at java.io.BufferedInputStream.read(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
      at java.net.HttpURLConnection.getResponseCode(Unknown Source)
      at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
      at HttpsClient.main(HttpsClient.java:109)
  
  java.net.SocketException: Connection reset
      at java.net.SocketInputStream.read(Unknown Source)
      at java.net.SocketInputStream.read(Unknown Source)
      at org.bouncycastle.tls.RecordStream$Record.fillTo(RecordStream.java:429)
      at org.bouncycastle.tls.RecordStream$Record.readHeader(RecordStream.java:468)
      at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:201)
      at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:768)
      at org.bouncycastle.tls.TlsProtocol.readApplicationData(TlsProtocol.java:731)
      at org.bouncycastle.jsse.provider.ProvSSLSocketDirect$AppDataInput.read(ProvSSLSocketDirect.java:603)
      at java.io.BufferedInputStream.fill(Unknown Source)
      at java.io.BufferedInputStream.read1(Unknown Source)
      at java.io.BufferedInputStream.read(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
      at sun.net.www.http.HttpClient.parseHTTP(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
      at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
      at java.net.HttpURLConnection.getResponseCode(Unknown Source)
      at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(Unknown Source)
      at HttpsClient.main(HttpsClient.java:109)
  </code></pre>
  <p>As expected the code runs just fine in Java 1.8 without BC as Security Provider ... but in Java 1.6 BC is needed for TLS 1.2 support.</p>
  <p>I looked at the packets with Wireshark, but I don't have enough knowledge to analyze what's happening (failing) with the SSL handshake operation with the server.</p>
  <p>What am I missing here? Or it's just a known limitation of BC?
  Thanks for any suggestions.</p>