SMTP TLS 证书

SMTP TLS certificate

我在理解 TLS/SSL 如何处理电子邮件时遇到了一些问题。

我有一些问题。

  1. 在我的开发机器中,如果我在 "sslSocket.startHandshake()" 行第一次调试以下代码失败,但如果我立即再次尝试,它工作正常。

我收到的错误消息是:"Remote host closed connection during handshake"。

当我将相同的代码部署到暂存环境并发送电子邮件时,代码第一次运行良好。 开发服务器和临时服务器都在同一个网络中,并且都没有运行防病毒程序。

我唯一能想到的是为什么它第一次在开发环境中不工作是因为我正在使用调试器单步执行代码,因此速度较慢。

您知道我收到此错误的原因吗?

  1. 下面的代码正在创建一个 SSL 套接字。我很想知道这段代码是否足以确保与邮件服务器的连接安全。这些 SSLSocketFactory 类 自己处理证书吗?

2a) 或者我还需要以某种方式指定证书吗?

2b) 或者这段代码是从服务器获取证书并使用证书加密数据并将加密的数据来回发送到电子邮件服务器?

我知道它应该像这里描述的那样工作: RFC 3207 定义了 SMTP 连接如何使用加密。建立连接后,客户端会发出 STARTTLS 命令。如果服务器接受,客户端和服务器协商加密机制。如果协商成功,则随后在它们之间传递的数据将被加密。

2c) 下面的代码是这样做的吗?

socket.setKeepAlive(true);

  SSLSocket sslSocket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(
          socket, 
          socket.getInetAddress().getHostAddress(), 
          socket.getPort(),
          true);                 

  sslSocket.setUseClientMode(true);
  sslSocket.setEnableSessionCreation(true);
  sslSocket.setEnabledProtocols(new String[]{"SSLv3", "TLSv1"});
  sslSocket.setKeepAlive(true);

  // Force handshake. This can throw!
  sslSocket.startHandshake();       

  socket = sslSocket;

  in  = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
  1. In my development machine if I debug the following code fails the first time arround on the "sslSocket.startHandshake()" line, but if I try it again straight away it is working fine.
    The error message that I'm getting is: "Remote host closed connection during handshake". []
    The only thing that I can think of as to why it is not working the first time around in the development environment is because I'm stepping through the code with the debugger and it's slower because of this.

如果您只是在底层套接字关闭的情况下再次执行 startHandshake(),它将永远无法工作。如果您返回进行 TCP 连接(例如 new Socket(host,port))和初始 SMTP 交换和 STARTTLS,那么是的,我希望它能避免影响先前连接的任何问题。

是的,由于您调试时的延迟,服务器超时很有可能,但要确定您需要检查服务器上的日志。

  1. The code underneath is creating an SSL Socket. I'm curious to know if this code is enough for the connection with the mail server to be secure. Are these SSLSocketFactory classes dealing with certificates themselves?

间接地,是的。 SSLSocketFactory 创建一个 SSLSocket linked 到 SSLContext,其中包括一个 TrustManager,通常从信任库文件加载。您的代码默认为默认值 SSLContext,它有一个从默认信任库加载的 TrustManager,如果存在则为文件 jssecacerts,否则为 lib/security 中的 cacerts您在 JRE 中的目录 运行。如果您的 JRE 没有被修改(由您或您系统上授权的任何其他人),根据您的 Java 的变体或包装,安装的 JRE 通常没有 jssecacerts 并且包含或 links 到一个 cacerts 文件,该文件(最初)包含大约一百个 'well-known' 的根证书或已建立的证书颁发机构,如 Symantec、GoDaddy、Comodo 等

2a) Or do I still need to specify a certificate somehow?

既然握手完成就成功了,显然不是。

2b) Or is this code getting the certificate from the server and using the certificate to encrypt the data and send the encrypted data back and forth to the email server?

亲切of/sortof/not挺。除了此处不适用的一些例外情况,在 SSL/TLS 握手中,服务器始终提供自己的证书,通常是中间证书或 'chain' 证书 link 其证书到受信任的根证书(例如上述赛门铁克等)。服务器证书始终用于对服务器进行身份验证,有时单独使用但通常与其他机制(特别是 Diffie-Hellman 临时 DHE 或其椭圆曲线变体 ECDHE)结合使用,用于建立一组多个对称密钥值,然后用于双向加密和验证数据。有关更完整的解释,请参阅 security.SX https://security.stackexchange.com/questions/20803/how-does-ssl-work/

中的规范问题和(多部分!)答案

2c) Is the code underneath doing this?

正在现有套接字上启动 SSLv3 或 TLSv1 客户端会话。我不确定你还有什么问题。

您最好省略 setEnabledProtocols()。 Sun/Oracle Java 版本 8,这是现在唯一支持的版本,默认支持 TLS 1.0、1.1 和 1.2。 1.1,尤其是 1.2 肯定比 1.0 好,而且绝对应该提供,这样如果服务器支持它们,它们就会被使用。 (Sun/Oracle 7 问题更大;它 实现 1.1 和 1.2,但默认情况下不会 启用 它们在客户端。我会查看 .getSupportedProtocols,如果支持 1.1 和 1.2 但未启用,我会添加启用它们。但如果可能的话,我只会升级到 8。Java 的其他版本,尤其是 IBM,在加密细节方面有很大差异.)

除非绝对必要,否则不应提供 SSLv3;它现在被POODLE严重破坏了(在security.SX上搜索了几十个关于POODLE的Q)。我会在没有它的情况下尝试,并且只有在服务器坚持要求它时才暂时重新启用它,_尽可能使用 TLS 1.0 到 1.2,同时敦促服务器升级以便我可以再次将其删除。