0

I am trying to set up a small email server using Apache James v2.3.2.1. My Java version for this installation is jre1.8.0_131. My server is running CentOS 6.9. I have the server running, but I cannot get clients to properly connect via TLS.

First, I generated a key like this:

keytool -genkey -alias james -keyalg RSA -keystore ./keystore

For the common name of the subject, I provided the FQDN of the server as I will be using it, henceforth "a.b.c"

I then updated the James config.xml server-sockets section to load from said keystore:

<factory name="ssl" class="org.apache.avalon.cornerstone.blocks.sockets.TLSServerSocketFactory">
    <ssl-factory>
           <keystore>
              <file>conf/keystore</file>
              <password>?</password>
              <key-password>?</key-password>
              <type>JKS</type>
              <protocol>TLS</protocol>
              <algorithm>SunX509</algorithm>
              <authenticate-client>false</authenticate-client>
           </keystore>
        </ssl-factory>
     </factory>

The server starts properly, and with debug output turned on, I can see that it is reading the keystore:

Running Phoenix:

Phoenix 4.2

***
found key for : james
chain [0] = [
[
  Version: V3
  Subject: CN=a.b.c, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=US
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 2048 bits
  modulus: ...
  public exponent: ...
  Validity: [From: Thu Apr 20 13:11:08 EDT 2017,
               To: Wed Jul 19 13:11:08 EDT 2017]
  Issuer: CN=a.b.c, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=US
  SerialNumber: [    51a402ba]

...

adding as trusted cert:
  Subject: CN=a.b.c, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=US
  Issuer: CN=a.b.c, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=US
  Algorithm: RSA; Serial number: 0x51a402ba
  Valid from Thu Apr 20 13:11:08 EDT 2017 until Wed Jul 19 13:11:08 EDT 2017

However, I also receive a large number (100+) of unavailable cipher messages, which seems excessive:

....
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_anon_WITH_AES_128_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_RC4_128_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_NULL_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_RC4_128_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_RC4_128_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
...

I have tried two different ways to connect the server. The primary has been via Mozilla Thunderbird as a baseline email client. It indicates that it cannot connect to the server with no helpful additional information. However, over in the server console output (with Java SSL debug output enabled), I see:

Allow unsafe renegotiation: true
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
default Worker #2, setSoTimeout(300000) called
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 for TLSv1.1
default Worker #6, READ: TLSv1 Handshake, length = 181
*** ClientHello, TLSv1.2
RandomCookie:  GMT: ... bytes = { ... }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, Unknown 0xcc:0xa9, Unknown 0xcc:0xa8, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
Compression Methods:  { 0 }
Extension server_name, server_name: [type=host_name (0), value=a.b.c]
Unsupported extension type_23, data:
Extension renegotiation_info, renegotiated_connection: <empty>
Extension elliptic_curves, curve names: {unknown curve 29, secp256r1, secp384r1, secp521r1}
Extension ec_point_formats, formats: [uncompressed]
Unsupported extension type_35, data:
Unsupported extension status_request, data: 01:00:00:00:00
Unsupported extension type_18, data:
Unsupported extension type_65283, data:
Extension signature_algorithms, signature_algorithms: SHA256withECDSA, SHA384withECDSA, SHA512withECDSA, Unknown (hash:0x8, signature:0x4), Unknown (hash:0x8, signature:0x5), Unknown (hash:0x8, signature:0x6), SHA256withRSA, SHA384withRSA, SHA512withRSA, SHA1withECDSA, SHA1withRSA
***
%% Initialized:  [Session-2, SSL_NULL_WITH_NULL_NULL]
default Worker #6, handling exception: java.lang.RuntimeException: Could not generate DH keypair
%% Invalidated:  [Session-2, SSL_NULL_WITH_NULL_NULL]

And in the POP3 log, an impressive stack trace:

20/04/17 14:41:27 ERROR pop3server: Exception during connection from x.x.x.x (x.x.x.x) : Connection has been shutdown: javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
        at sun.security.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.java:1541)
        at sun.security.ssl.AppInputStream.read(AppInputStream.java:95)
        at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
        at org.apache.james.util.CRLFTerminatedReader.read(CRLFTerminatedReader.java:153)
        at org.apache.james.util.CRLFTerminatedReader.readLine(CRLFTerminatedReader.java:113)
        at org.apache.james.pop3server.POP3Handler.readCommandLine(POP3Handler.java:424)
        at org.apache.james.pop3server.POP3Handler.handleConnection(POP3Handler.java:277)
        at org.apache.james.util.connection.ServerConnection$ClientConnectionRunner.run(ServerConnection.java:432)
        at org.apache.excalibur.thread.impl.ExecutableRunnable.execute(ExecutableRunnable.java:55)
        at org.apache.excalibur.thread.impl.WorkerThread.run(WorkerThread.java:116)
Caused by: javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1906)
        at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1889)
        at sun.security.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1815)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:128)
        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
        at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:297)
        at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)
        at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)
        at java.io.BufferedWriter.flush(BufferedWriter.java:254)
        at java.io.PrintWriter.flush(PrintWriter.java:320)
        at org.apache.james.util.InternetPrintWriter.println(InternetPrintWriter.java:92)
        at org.apache.james.util.InternetPrintWriter.println(InternetPrintWriter.java:189)
        at org.apache.james.pop3server.POP3Handler.handleConnection(POP3Handler.java:274)
        ... 3 more
Caused by: java.lang.RuntimeException: Could not generate DH keypair
        at sun.security.ssl.DHCrypt.<init>(DHCrypt.java:142)
        at sun.security.ssl.DHCrypt.<init>(DHCrypt.java:103)
        at sun.security.ssl.ServerHandshaker.setupEphemeralDHKeys(ServerHandshaker.java:1416)
        at sun.security.ssl.ServerHandshaker.trySetCipherSuite(ServerHandshaker.java:1206)
        at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:1026)
        at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:741)
        at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:224)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:747)
        at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:123)
        ... 13 more
Caused by: java.security.NoSuchAlgorithmException: DiffieHellman KeyPairGenerator not available
        at java.security.KeyPairGenerator.getInstance(KeyPairGenerator.java:218)
        at sun.security.ssl.JsseJce.getKeyPairGenerator(JsseJce.java:260)
        at sun.security.ssl.DHCrypt.<init>(DHCrypt.java:126)
        ... 25 more

The second test I did was to just try to verify the TLS layer via an openssl (OpenSSL 1.0.1e-fips 11 Feb 2013) client call:

[user@host ~]$ openssl s_client -msg -connect a.b.c:995 -msg -debug
CONNECTED(00000003)
write to ...
0000 - ...
0010 - ...
0020 - ...
0030 - ...
0040 - ...
0050 - ...
0060 - ...
0070 - ...
0080 - ...
0090 - ...
00a0 - ...
00b0 - ...
00c0 - ...
00d0 - ...
00e0 - ...
00f0 - ...
>>> TLS 1.2 Handshake [length 00f2], ClientHello
    ...
read from ...
0000 - ...
<<< TLS 1.2 Alert [length 0002], fatal internal_error
    02 50
140124392265544:error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error:s23_clnt.c:744:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 247 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---

The same errors/stack traces occur at the James end here.

Googling the Exception chain within James' POP3 log produces suggestions that the JVM may not be able to handle the proper key size, BUT they are all much older and refer to problems in the Java5/6 timeframe, indicating that 6+ has that problem fixed. The fact that the base Exception claims that DH exchange is not available seemed significant, but other sources I found online indicated that that is actually a catch-all handshake failure Exception, and that singling out that cause might be unproductive.

Surely this is something simple that I've overlooked or fat fingered?

Omaha
  • 121
  • 3

1 Answers1

0

I still have no answer to the question but I have solved the problem: I set up James to accept only local, insecure connections, and then used stunnel to set up an external-facing TLS proxy. Email is now flowing, securely!

Omaha
  • 121
  • 3