Skip to content

BouncyCastleJsseProvider: Client raised fatal(2) internal_error(80) alert: Failed to read record #847

@jankostefancic

Description

@jankostefancic

I have run into an issue developing a HTTP client with the use of BouncyCastle libraries. Target versions is Java 1.6.0_45-b06 (but the error is also reproducible in Java 1.8.0_91 with the same version of BouncyCastle.)

BouncyCastle jdk15to18 167 (bcprov-jdk15to18-167.jar, bcpkix-jdk15to18-167.jar, bctls-jdk15to18-167.jar)

Accessing data with TLS 1.2 without client_auth works fine (there are some issues with specific sites that return handshake_failure(40), but that's another issue and luckily not for our integration). But when client_auth is required the code fails with the following (a little cryptic) error:

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 without BC as SecurityProvider runs just fine in Java 1.8. But in our case BC is a requirement for TLS 1.2 support in Java 1.6.

I tried to analyze the SSL handshake with Wireshark, but I don't have enough knowledge to understand what's happening (failing).

What am I missing here? Or it's just a known limitation of BC?
Thanks for any suggestions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions