You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@directory.apache.org by Mat Gessel <ma...@gmail.com> on 2012/06/26 21:30:15 UTC

Can't connect w/ encryption after loading a custom certificate

I can connect using the default certificate that is automatically
created when creating a new server. However, I am unable to connect
when I specify a self-signed certificate for the server (via
uid=admin,ou=system). This problem originally occurred in a Java LDAP
client, however I can wholly reproduce the issue w/ Directory Studio.
Directions are below.

Client error:
javax.net.ssl.SSLHandshakeException: Received fatal alert:
handshake_failure (JDK 6)
javax.net.ssl.SSLKeyException: Server D-H key verification failed (JDK 7)

Reproduced on platforms:
Mac OS 10.6.8
Windows 7 x64

Reproduced on JREs:
Java(TM) SE Runtime Environment (build 1.6.0_33-b03-424-10M3720)
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)

Reproduced in Apache Directory Studio versions:
2.0.0.v20120224
1.5.3.v20100330

Repro
====================
1) create a certificate
keytool -genkeypair -keyalg RSA -keysize 2048 -validity 3650 -alias
localhost -dname "cn=localhost" -keypass changeit -keystore truststore
-storepass changeit
2) export certificate
keytool -exportcert -alias localhost -rfc -keystore truststore
-storepass changeit -file localhost.cer

-----BEGIN CERTIFICATE-----
MIICpDCCAYygAwIBAgIET+n1UTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDEwls
b2NhbGhvc3QwHhcNMTIwNjI2MTc0NTUzWhcNMjIwNjI0MTc0NTUzWjAUMRIwEAYD
VQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCe
i757nu2QV6lskOggRyFpXe0Kx1DoMVebYzHJkopfRBp3nmaqVQfR119ZkbH5au4V
v1fR0zGmPhOg0S+oeS12fB4Vpd4W94iWkPqxdWfQqa1hzphSLB92be4f5EwBHggT
Ia0v7+FIdS0s2oJz0tgQqHalNTLxuf8A3ZHw7GlBepLRpL6fiQbN43bwSsJb2FGD
XTRTlHI1c/acrPZaibjuVpDmjNxCv0ufShRqlByM19D3QFY6Z6Nt849eD2MIsdQD
VIIkwqW/lJKMNezc0A/NqEsUuQqZr0JtyJhMs/cCaTkMpIh+/e8bUFi+YrlpLI52
TFy331Abd1Q2/IPi46cLAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBAJddKZF2AeFT
QYnPG65a5dtWXdx6bmba0GjPacC/DXqLdRNKaKGwGFBN7fHjaigGcToVShaEBOBh
LM/5WUqD/xzdYkKsAHJjz+o8xtLRTBXR7uLnl412ZW5ypCGny5AmZP36G7E1CMPr
1RO9sIlLMBndPBYNw9312qY+daekV4yZ/+iQcJo0p726rYFEno+qUg5+eC8Z8w4Q
Gwl3BvUH2A8l6L66IuhWwGlPVcU6C6jDwVCExFG8dWjv7HPdhKxeoL7owweHpseI
zMDCez5/yrfsMsAO4idmHLJL10NPULPUJ4uCWGeSnrfG3OPUv8cstx8SrL4Ug4PN
+cbb5wmkb08=
-----END CERTIFICATE-----


3) in Directory Studio, Create a new Server
4) Run server
5) right-click on server and create a new connection
6) edit connection and change "Encryption method" to "Use StartTLS extension"
7) change "Provider" to JNDI
8) click OK to save connection
9) Open the connection
10) browse to "uid=admin,ou=system" in DIT
11 edit "userCertificate" entry
12) click "Load certificate"
13) choose localhost.cer
14) click OK to save entry
15) disconnect from server
16) stop server
17) restart Directory Studio (for kicks)
18) Run server
19) connection > Connect
20) in "Certificate Trust" dialog, select "Session" or "Always trust"
Expected Result: connection is established
Actual Result: "Problem Occurred" dialog. Error logs below.

Variations tried
==================
version 1 certificate
version 3 cert w/ SSL extension
Apache Directory LDAP Client API ("SSL handshake failed.")
specifying OU, O & C in cert
use 512 keysize for cert
set cert validity to 1 year
ApacheDS 1.5.3 vs 2.0.0
cert CN = localhost, "staticDnsName"

JRE 7 client log
Error while opening connection
 - Server D-H key verification failed
javax.naming.NamingException: Server D-H key verification failed [Root
exception is javax.net.ssl.SSLKeyException: Server D-H key
verification failed]
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper$6.run(JNDIConnectionWrapper.java:926)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper.runAndMonitor(JNDIConnectionWrapper.java:1305)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper.doConnect(JNDIConnectionWrapper.java:940)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper.connect(JNDIConnectionWrapper.java:209)
	at org.apache.directory.studio.connection.core.jobs.OpenConnectionsRunnable.run(OpenConnectionsRunnable.java:111)
	at org.apache.directory.studio.connection.core.jobs.StudioConnectionJob.run(StudioConnectionJob.java:109)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
Caused by: javax.net.ssl.SSLKeyException: Server D-H key verification failed
	at sun.security.ssl.HandshakeMessage$DH_ServerKeyExchange.<init>(Unknown
Source)
	at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
	at sun.security.ssl.Handshaker.processLoop(Unknown Source)
	at sun.security.ssl.Handshaker.process_record(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
	at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
	at com.sun.jndi.ldap.ext.StartTlsResponseImpl.startHandshake(Unknown Source)
	at com.sun.jndi.ldap.ext.StartTlsResponseImpl.negotiate(Unknown Source)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper$6.run(JNDIConnectionWrapper.java:917)
	... 6 more


JRE 6 client log
Error while opening connection
 - Received fatal alert: handshake_failure
  javax.naming.NamingException: Received fatal alert:
handshake_failure [Root exception is
javax.net.ssl.SSLHandshakeException: Received fatal alert:
handshake_failure]
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper$6.run(JNDIConnectionWrapper.java:900)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper.runAndMonitor(JNDIConnectionWrapper.java:1272)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper.doConnect(JNDIConnectionWrapper.java:914)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper.connect(JNDIConnectionWrapper.java:209)
	at org.apache.directory.studio.connection.core.jobs.OpenConnectionsRunnable.run(OpenConnectionsRunnable.java:111)
	at org.apache.directory.studio.connection.core.jobs.StudioConnectionJob.run(StudioConnectionJob.java:114)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert:
handshake_failure
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1806)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:986)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
	at com.sun.jndi.ldap.ext.StartTlsResponseImpl.startHandshake(StartTlsResponseImpl.java:344)
	at com.sun.jndi.ldap.ext.StartTlsResponseImpl.negotiate(StartTlsResponseImpl.java:208)
	at org.apache.directory.studio.connection.core.io.jndi.JNDIConnectionWrapper$6.run(JNDIConnectionWrapper.java:891)
	... 6 more

JRE 6 server log
[12:01:21] WARN [org.apache.directory.server.ldap.LdapProtocolHandler]
- Unexpected exception forcing session to close: sending disconnect
notice to client.
javax.net.ssl.SSLHandshakeException: SSL handshake failed.
	at org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:495)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilterChain.java:46)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:796)
	at org.apache.mina.core.filterchain.IoFilterAdapter.messageReceived(IoFilterAdapter.java:119)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.fireMessageReceived(DefaultIoFilterChain.java:426)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.read(AbstractPollingIoProcessor.java:715)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:668)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:657)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.access$600(AbstractPollingIoProcessor.java:68)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run(AbstractPollingIoProcessor.java:1141)
	at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:64)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:680)
Caused by: javax.net.ssl.SSLHandshakeException: bad handshake record MAC
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
	at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1467)
	at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1435)
	at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:937)
	at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:845)
	at com.sun.net.ssl.internal.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:721)
	at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:607)
	at org.apache.mina.filter.ssl.SslHandler.unwrap(SslHandler.java:725)
	at org.apache.mina.filter.ssl.SslHandler.unwrapHandshake(SslHandler.java:663)
	at org.apache.mina.filter.ssl.SslHandler.handshake(SslHandler.java:549)
	at org.apache.mina.filter.ssl.SslHandler.messageReceived(SslHandler.java:349)
	at org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:476)
	... 15 more
[12:01:21] WARN [org.apache.directory.server.ldap.LdapProtocolHandler]
- Null LdapSession given to cleanUpSession.

JRE 7 server log
[12:02:39] WARN
[org.apache.directory.server.ldap.LdapProtocolHandler] - Unexpected
exception forcing session to close: sending disconnect notice to
client.
javax.net.ssl.SSLHandshakeException: SSL handshake failed.
	at org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:495)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilterChain.java:46)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceived(DefaultIoFilterChain.java:796)
	at org.apache.mina.core.filterchain.IoFilterAdapter.messageReceived(IoFilterAdapter.java:119)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434)
	at org.apache.mina.core.filterchain.DefaultIoFilterChain.fireMessageReceived(DefaultIoFilterChain.java:426)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.read(AbstractPollingIoProcessor.java:715)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:668)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.process(AbstractPollingIoProcessor.java:657)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor.access$600(AbstractPollingIoProcessor.java:68)
	at org.apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run(AbstractPollingIoProcessor.java:1141)
	at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:64)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: javax.net.ssl.SSLException: Received fatal alert: unexpected_message
	at sun.security.ssl.Alerts.getSSLException(Unknown Source)
	at sun.security.ssl.SSLEngineImpl.fatal(Unknown Source)
	at sun.security.ssl.SSLEngineImpl.fatal(Unknown Source)
	at sun.security.ssl.SSLEngineImpl.recvAlert(Unknown Source)
	at sun.security.ssl.SSLEngineImpl.readRecord(Unknown Source)
	at sun.security.ssl.SSLEngineImpl.readNetRecord(Unknown Source)
	at sun.security.ssl.SSLEngineImpl.unwrap(Unknown Source)
	at javax.net.ssl.SSLEngine.unwrap(Unknown Source)
	at org.apache.mina.filter.ssl.SslHandler.unwrap(SslHandler.java:725)
	at org.apache.mina.filter.ssl.SslHandler.unwrapHandshake(SslHandler.java:663)
	at org.apache.mina.filter.ssl.SslHandler.handshake(SslHandler.java:549)
	at org.apache.mina.filter.ssl.SslHandler.messageReceived(SslHandler.java:349)
	at org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:476)
	... 15 more
[12:02:39] WARN [org.apache.directory.server.ldap.LdapProtocolHandler]
- Null LdapSession given to cleanUpSession.

-- 
Mat Gessel
http://www.asquare.net

Re: Can't connect w/ encryption after loading a custom certificate

Posted by Pierre-Arnaud Marcelot <pa...@marcelot.net>.
Hi Mat,

Indeed, both attributes need to be in sync to work correctly.

Thanks for the detailed step by step procedure.

Regards,
Pierre-Arnaud


On 27 juin 2012, at 21:23, Mat Gessel wrote:

> Figured it out. In this case the handshake error means that the data
> being served does not cryptographically correspond to the trusted
> certificate. The value of "userCertificate" must be derived from the
> value of "privateKey". If you change "userCertificate" on
> "uid=admin,ou=system" you must also change "privateKey" to the
> corresponding private key.
> 
> Getting a private key and corresponding certificate is a bit difficult
> with keytool (the Java key/certificate tool) because keytool does not
> expose private keys. Here is the procedure I came up with (copied from
> another document):
> 
> *** Installing a Certificate Generated By Keytool ***
> 
> When you create a new server, a private key and certificate are
> automatically created on the admin entry (uid=admin,ou=system).
> Unfortunately, the certificate references an non-existant issuer. This
> means that clients which expect a valid certificate cannot connect to
> the server.
> 
> In this procedure we will:
> 1. create a keystore containing a private key & certificate.
> 2. export the certificate
> 3. export the public key to X.509/DER format
> 4. export the private key to PKCS#8/DER format
> 5. import the keys and certificate to ApacheDS
> 
> # create a PKCS#12 keystore containing a 2048 bit RSA private key and
> a certificate for localhost
> # the CN must match the host name of the server. A CN of "localhost"
> will not work for ldaps://my-server:389 or vice-versa
> # we create a keystore in PKCS#12 format for consumption by OpenSSL
> keytool -genkeypair -keyalg RSA -keysize 2048 -validity 365 -alias
> ldap -dname "cn=localhost" -keypass changeit -keystore ldap.p12
> -storepass changeit -storetype PKCS12
> 
> # extract a certificate from the keystore
> keytool -exportcert -alias ldap -rfc -keystore ldap.p12 -storepass
> changeit -storetype PKCS12 -file ldap.cer
> 
> # extract the private key from the keystore
> openssl pkcs12 -in ldap.p12 -passin pass:changeit -nodes -nocerts |
> openssl rsa | openssl pkcs8 -topk8 -nocrypt -outform DER -out
> ldap-privatekey.der
> 
> # derive a public key from the private key in the keystore (this may
> be incorrect, but it does not seem to matter for ApacheDS)
> openssl pkcs12 -in ldap.p12 -passin pass:changeit -nodes -nocerts |
> openssl rsa -pubout -outform DER -out ldap-publickey.der
> 
> # import the server certificate to the truststore for V-Flex to use
> # this is a self-signed (root) certificate, so you be asked to confirm
> that you trust it
> keytool -importcert -alias ldap -keystore .truststore -storepass
> changeit -keypass changeit -file ldap.cer
> 
> To utilize the keys and certificate in ApacheDS:
> 1. browse to uid=admin,ou=system in the LDAP Browser
> 2. double-click on privateKey, click Load Data..., select
> ldap-privatekey.der and click OK
> 3. double-click on publicKey, click Load Data..., select
> ldap-publickey.der and click OK
> 4. double-click on userCertificate, click Load Certificate..., select
> ldap.cer and click OK
> 5. disconnect from the server
> 6. stop the server
> 7. restart the server
> 8. connect to the server
> 9. accept the new certificate as trusted
> 
> -- 
> Mat Gessel
> http://www.asquare.net
> 
> On Tue, Jun 26, 2012 at 12:30 PM, Mat Gessel <ma...@gmail.com> wrote:
>> However, I am unable to connect
>> when I specify a self-signed certificate for the server (via
>> uid=admin,ou=system).


Re: Can't connect w/ encryption after loading a custom certificate

Posted by Mat Gessel <ma...@gmail.com>.
Figured it out. In this case the handshake error means that the data
being served does not cryptographically correspond to the trusted
certificate. The value of "userCertificate" must be derived from the
value of "privateKey". If you change "userCertificate" on
"uid=admin,ou=system" you must also change "privateKey" to the
corresponding private key.

Getting a private key and corresponding certificate is a bit difficult
with keytool (the Java key/certificate tool) because keytool does not
expose private keys. Here is the procedure I came up with (copied from
another document):

*** Installing a Certificate Generated By Keytool ***

When you create a new server, a private key and certificate are
automatically created on the admin entry (uid=admin,ou=system).
Unfortunately, the certificate references an non-existant issuer. This
means that clients which expect a valid certificate cannot connect to
the server.

In this procedure we will:
1. create a keystore containing a private key & certificate.
2. export the certificate
3. export the public key to X.509/DER format
4. export the private key to PKCS#8/DER format
5. import the keys and certificate to ApacheDS

# create a PKCS#12 keystore containing a 2048 bit RSA private key and
a certificate for localhost
# the CN must match the host name of the server. A CN of "localhost"
will not work for ldaps://my-server:389 or vice-versa
# we create a keystore in PKCS#12 format for consumption by OpenSSL
keytool -genkeypair -keyalg RSA -keysize 2048 -validity 365 -alias
ldap -dname "cn=localhost" -keypass changeit -keystore ldap.p12
-storepass changeit -storetype PKCS12

# extract a certificate from the keystore
keytool -exportcert -alias ldap -rfc -keystore ldap.p12 -storepass
changeit -storetype PKCS12 -file ldap.cer

# extract the private key from the keystore
openssl pkcs12 -in ldap.p12 -passin pass:changeit -nodes -nocerts |
openssl rsa | openssl pkcs8 -topk8 -nocrypt -outform DER -out
ldap-privatekey.der

# derive a public key from the private key in the keystore (this may
be incorrect, but it does not seem to matter for ApacheDS)
openssl pkcs12 -in ldap.p12 -passin pass:changeit -nodes -nocerts |
openssl rsa -pubout -outform DER -out ldap-publickey.der

# import the server certificate to the truststore for V-Flex to use
# this is a self-signed (root) certificate, so you be asked to confirm
that you trust it
keytool -importcert -alias ldap -keystore .truststore -storepass
changeit -keypass changeit -file ldap.cer

To utilize the keys and certificate in ApacheDS:
1. browse to uid=admin,ou=system in the LDAP Browser
2. double-click on privateKey, click Load Data..., select
ldap-privatekey.der and click OK
3. double-click on publicKey, click Load Data..., select
ldap-publickey.der and click OK
4. double-click on userCertificate, click Load Certificate..., select
ldap.cer and click OK
5. disconnect from the server
6. stop the server
7. restart the server
8. connect to the server
9. accept the new certificate as trusted

-- 
Mat Gessel
http://www.asquare.net

On Tue, Jun 26, 2012 at 12:30 PM, Mat Gessel <ma...@gmail.com> wrote:
> However, I am unable to connect
> when I specify a self-signed certificate for the server (via
> uid=admin,ou=system).