5

We're writing an app that must communicate with a few servers using HTTPS. It needs to communicate with AWS (using the AWS libraries) and also with some of our internal services that use TLS 1.2.

I started off by changing my HttpClient to use a TLS 1.2 SSLContext:

public static SchemeRegistry buildSchemeRegistry() throws Exception {
    final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
    sslContext.init(createKeyManager(), createTrustManager(), new SecureRandom());
    final SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("https", 443, new SSLSocketFactory(sslContext)));
    return schemeRegistry;
}

and injecting this SchemeRegistry into the DefaultHttpClient object (via spring), but doing that I get errors from AWS and so I assume (I may be wrong) that AWS doesn't support TLS 1.2 (I don't get this message if I just use the normal DefaultHttpClient):

AmazonServiceException: Status Code: 403, AWS Service: AmazonSimpleDB, AWS Request ID: 5d91d65f-7158-91b6-431d-56e1c76a844c, AWS Error Code: InvalidClientTokenId, AWS Error Message: The AWS Access Key Id you provided does not exist in our records.

If I try to have two HttpClients defined in spring, one that uses TLS 1.2 and one that is the default, I get the following error, which I assume means that Spring doesn't like instantiating and autowiring two HttpClient objects:

SEVERE: Servlet /my-refsvc threw load() exception
java.lang.NullPointerException
at com.company.project.refsvc.base.HttpsClientFactory.<clinit>(BentoHttpsClientFactory.java:25)
...
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1031)
at 
...
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)

I haven't used HTTPS much in java so could you kind people give me some advice please? 1) How would I get Spring to allow two HttpClient objects and for one to be wired to the AWS stuff beans and the other to be wired to the other beans for accessing the TLS1.2 services 2) Or is it possible to change the one HttpClient object to be able to try TLS1.2 (via SSLContext, or the SchemeRegistry or something) and if that fails then try TLS1.1 or 1.0? 3) If both are possible, what would be the 'better' way of doing it?

4

1 回答 1

5

TLS 有一个内置机制来协商要使用的协议版本。来自RFC 5246(附录 E)

TLS 1.0、1.1 和 1.2 版本与 SSL 3.0 非常相似,并且使用兼容的 ClientHello 消息;因此,支持所有这些相对容易。同样,只要 ClientHello 格式保持兼容,并且客户端支持服务器中可用的最高协议版本,服务器就可以轻松处理尝试使用未来版本 TLS 的客户端。

希望与此类旧服务器协商的 TLS 1.2 客户端将发送正常的 TLS 1.2 ClientHello,在 ClientHello.client_version 中包含 { 3, 3 } (TLS 1.2)。如果服务器不支持这个版本,它会响应一个包含旧版本号的 ServerHello。如果客户同意使用此版本,协商将根据协商的协议进行。

此外,更改版本号SSLContext.getInstance(...)仅更改默认启用的协议。设置实际的协议版本是通过SSLSocket.setEnabledProtocols(...)(参见这个问题)完成的。我不确定您正在使用的其他库,但它可能会在某处设置启用的协议。

有几种可能:

  • 您所做的createKeyManager()与默认行为不同。如果服务使用客户端证书身份验证,那么糟糕的配置肯定会导致 403 错误。

  • (我猜不太可能,但如果没有看到你的createKeyManager()and就很难说createTrustManager())。也许您使用的服务器与 TLS 1.2 和版本协商机制不兼容。有这个评论sun.security.ssl.SSLContextImpl

    SSL/TLS 协议指定了前向兼容性和版本回滚攻击保护,但是,许多 SSL/TLS 服务器供应商没有正确实现这些方面,并且一些当前的 SSL/TLS 服务器可能拒绝与 TLS 1.1 或更高版本通信客户。

于 2013-08-14T17:16:37.917 回答