0

I'm using Apache httpcomponents 4.2.5 to build a simple https client to get a file from a server.

The code is based primarily off of the ClientExecuteProxy.java sample code. I developed and tested the client under Java 1.6.0_31 and it works as expected.

I distributed the final jar to one of my servers which has Java 1.7.0_25 (miraculously installed about 2 weeks ago). Under Java 7 is when I get the error.

I've tried a number of switches, accessed the site through firefox, clicked the lock and downloaded the certificate/added to cacerts. This is verified in the debug log below, note that it worked without it under java 6. I continue to get the same stack trace.

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at sun.security.ssl.SSLSessionImpl.getPeerCertificates(Unknown Source)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126)
    at org.apache.http.conn.ssl.SSLSocketFactory.createLayeredSocket(SSLSocketFactory.java:493)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.updateSecureConnection(DefaultClientConnectionOperator.java:232)
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.layerProtocol(ManagedClientConnectionImpl.java:401)
    at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:840)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:647)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:827)

Turned on the javax debug option and see what everyone else is posting...

    executing request to https://dmf.ntis.gov:443 via http://myproxy.mynet:8080
trustStore is: C:\Program Files\Java\jre7\lib\security\cacerts
trustStore type is : jks
trustStore provider is : 
init truststore

...

adding as trusted cert:
  Subject: CN=dmf.ntis.gov, O=National Technical Information Service, L=Alexandria, ST=Virginia, C=US
  Issuer:  CN=Entrust Certification Authority - L1C, OU="(c) 2009 Entrust, Inc.", OU=www.entrust.net/rpa is incorporated by reference, O="Entrust, Inc.", C=US
  Algorithm: RSA; Serial number: 0x4c1ed933
  Valid from Fri Jan 25 10:23:19 EST 2013 until Sun Jan 26 22:54:05 EST 2014

...

trigger seeding of SecureRandom
done seeding SecureRandom
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
Allow unsafe renegotiation: true
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1355254829 bytes = { 151, 204, 236, 54, 121, 42, 132, 221, 43, 116, 69, 16, 51, 17, 65, 109, 23, 135, 125, 16, 54, 72, 163, 189, 169, 189, 114, 223 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
Extension server_name, server_name: [host_name: dmf.ntis.gov]
***
[write] MD5 and SHA1 hashes:  len = 170
0000: 01 00 00 A6 03 01 51 C8   8C 2D 97 CC EC 36 79 2A  ......Q..-...6y*
0010: 84 DD 2B 74 45 10 33 11   41 6D 17 87 7D 10 36 48  ..+tE.3.Am....6H
0020: A3 BD A9 BD 72 DF 00 00   2A C0 09 C0 13 00 2F C0  ....r...*...../.
0030: 04 C0 0E 00 33 00 32 C0   07 C0 11 00 05 C0 02 C0  ....3.2.........
0040: 0C C0 08 C0 12 00 0A C0   03 C0 0D 00 16 00 13 00  ................
0050: 04 00 FF 01 00 00 53 00   0A 00 34 00 32 00 17 00  ......S...4.2...
0060: 01 00 03 00 13 00 15 00   06 00 07 00 09 00 0A 00  ................
0070: 18 00 0B 00 0C 00 19 00   0D 00 0E 00 0F 00 10 00  ................
0080: 11 00 02 00 12 00 04 00   05 00 14 00 08 00 16 00  ................
0090: 0B 00 02 01 00 00 00 00   11 00 0F 00 00 0C 64 6D  ..............dm
00A0: 66 2E 6E 74 69 73 2E 67   6F 76                    f.ntis.gov
main, WRITE: TLSv1 Handshake, length = 170
[Raw write]: length = 175
0000: 16 03 01 00 AA 01 00 00   A6 03 01 51 C8 8C 2D 97  ...........Q..-.
0010: CC EC 36 79 2A 84 DD 2B   74 45 10 33 11 41 6D 17  ..6y*..+tE.3.Am.
0020: 87 7D 10 36 48 A3 BD A9   BD 72 DF 00 00 2A C0 09  ...6H....r...*..
0030: C0 13 00 2F C0 04 C0 0E   00 33 00 32 C0 07 C0 11  .../.....3.2....
0040: 00 05 C0 02 C0 0C C0 08   C0 12 00 0A C0 03 C0 0D  ................
0050: 00 16 00 13 00 04 00 FF   01 00 00 53 00 0A 00 34  ...........S...4
0060: 00 32 00 17 00 01 00 03   00 13 00 15 00 06 00 07  .2..............
0070: 00 09 00 0A 00 18 00 0B   00 0C 00 19 00 0D 00 0E  ................
0080: 00 0F 00 10 00 11 00 02   00 12 00 04 00 05 00 14  ................
0090: 00 08 00 16 00 0B 00 02   01 00 00 00 00 11 00 0F  ................
00A0: 00 00 0C 64 6D 66 2E 6E   74 69 73 2E 67 6F 76     ...dmf.ntis.gov
main, handling exception: java.net.SocketException: Connection reset
main, SEND TLSv1 ALERT:  fatal, description = unexpected_message
main, WRITE: TLSv1 Alert, length = 2
main, Exception sending alert: java.net.SocketException: Connection reset by peer: socket write error
main, called closeSocket()
main, IOException in getSession():  java.net.SocketException: Connection reset

Sorry for the Long Post here. This log was generated using the -Dsun.security.ssl.allowUnsafeRenegotiation=true switch, but it made no difference.

The code has some custom classes, but there's no magic here. The configuration is in property files and loaded at runtime, parameters should be pretty self explanatory.

    private static void getHttpFile(HttpContextConfig cfg,
        HttpContextEntry ctx, 
        String remoteFile, 
        String localFile, 
        Boolean useTemp) throws Exception {


    SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss.SSS");
    System.out.println("\n\n" + sdf.format(new Date()) +  " HttpClientUtil Starting...");

    DefaultHttpClient httpclient = new DefaultHttpClient();
    // socket.setEnabledProtocols(new String[] { "SSLv3" }); 
    try {
        HttpHost target = new HttpHost(ctx.getHostName(), 
                Integer.parseInt(ctx.getPort()), 
                ctx.getScheme());

        if (null != cfg.getProxyHost()){
            HttpHost proxy = new HttpHost(cfg.getProxyHost(), 
                    cfg.getProxyPort(), 
                    cfg.getProxyScheme());

            httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
            System.out.println("executing request to " + target + " via " + proxy);
        }
        else
            System.out.println("executing request to " + target);

        // Set the credentials if we have a userID
        if (null != ctx.getUserName()){
            httpclient.getCredentialsProvider().setCredentials(
                    new AuthScope(ctx.getHostName(), Integer.parseInt(ctx.getPort())),
                    new UsernamePasswordCredentials(ctx.getUserName(), ctx.getPassword()));
        }


        HttpGet req = new HttpGet(remote);

        HttpResponse rsp = httpclient.execute(target, req);
        HttpEntity entity = rsp.getEntity();

        System.out.println("----------------------------------------");
        System.out.println(rsp.getStatusLine());
        Header[] headers = rsp.getAllHeaders();
        for (int i = 0; i<headers.length; i++) {
            System.out.println(headers[i]);
        }
        System.out.println("----------------------------------------");

        System.out.println("\n\t" + sdf.format(new Date()) +  " Writing Output to File: " + local );

            *** Snipped some unimportant code out ***

            OutputStream OutStream = new FileOutputStream(local);

            entity.writeTo(OutStream);
            OutStream.flush();
            OutStream.close();

    } finally {
        // When HttpClient instance is no longer needed,
        // shut down the connection manager to ensure
        // immediate deallocation of all system resources
        httpclient.getConnectionManager().shutdown();
    }
}

I have been plowing through various threads, trying to figure out the answer. I don't want to disable (accept all certificates) solution. I haven't tried the custom SSL socket factory for explicitly setting SSLv3 negotiation.

socket.setEnabledProtocols(new String[] { "SSLv3" });

This site does have a user id and password in order to download data, and does have cookies, but again, this does work under JRE 6.

Thanks for any help you can provide.

4

1 回答 1

1

这个问题的答案最终是很多事情。

  1. 生产服务器使用 WPAD(Web 代理自动发现)代理查找。我使用的是可访问的代理,但并未真正为我正在使用的主机配置。我最终使用proxy-vole来避免在属性文件中硬编码代理服务器。

  2. Java 7 改变了 httpclient 的行为。我将 JRE 7 从我的生产主机复制到我的本地电脑,并受到来自我的代理服务器的身份验证的挑战。这在 JRE 6 中没有发生。在 Windows 环境中,我通过使用 NTLM 代理身份验证解决了这个问题

DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.getAuthSchemes().register("ntlm", new NTLMSchemeFactory());

奇怪的是,在我针对有效的代理服务器/主机组合运行代码之前,我没有看到代理身份验证问题。我确定这是一个配置问题,但代理服务器返回了一个未经过身份验证的页面,并且配置正确。在我的生产服务器上,我刚刚断开了套接字。

不幸的是,这是似乎有许多根本原因的 30,000 英尺错误之一。

于 2013-06-26T20:27:20.900 回答