Обсуждение: JDBC SSL with postgresql
I was interested in this[1] work on SSL client certs for JDBC, but I see the author stopped working on your project. I hope the list can give me a quick clue, because i've been banging my head against this all day. 1: http://github.com/ringerc/pkcs12provider First of all, I should mention that my client cert authentication is working fine with libpq/psql. So I'm satisfied that the certs and keys are in order. The problem is when I try to use JDBC it doesn't pick up my client cert. I have two files, truststore and keystore. $ file truststore keystore truststore: Java KeyStore keystore: Java KeyStore truststore has only my self-signed root CA cert. keystore has the root CA cert and my signed client certificate. Using a trivial JDBC test class and this command line: java -cp /usr/share/java/postgresql.jar:. -Djavax.net.ssl.keyStore=./keystore -Djavax.net.ssl.trustStore=./truststore TestJdbc I get this exception: Exception in thread "main" org.postgresql.util.PSQLException: FATAL: connection requires a valid client certificate Which is half good, because I know that it's validating the trust chain from the server to the root CA, but half bad because it's not sending the client cert. I know it's opening the keystore with my client cert in it, because I verified it with strace. Do I need to use a SSL socket factory class to make this work, or is it supposed to work out of the box and if so how? -jwb
On 3/06/2010 8:46 AM, Jeffrey Baker wrote: > I was interested in this[1] work on SSL client certs for JDBC, but I > see the author stopped working on your project. I hope the list can > give me a quick clue, because i've been banging my head against this > all day. > > 1: http://github.com/ringerc/pkcs12provider I stopped working on it because it's unnecessary if Java is configured correctly using the standard, built-in SSLSocketFactory and the system properties controlling it, as documented in the README in that directory. Unfortunately, that's only true with current Pg server versions if the same root signed the server and client certificates, or if you have only one client cert installed in your KeyStore. Otherwise, Java doesn't know which client cert to send. > truststore has only my self-signed root CA cert. keystore has the > root CA cert and my signed client certificate. Using a trivial JDBC > test class and this command line: > > java -cp /usr/share/java/postgresql.jar:. > -Djavax.net.ssl.keyStore=./keystore > -Djavax.net.ssl.trustStore=./truststore TestJdbc > > I get this exception: > > Exception in thread "main" org.postgresql.util.PSQLException: FATAL: > connection requires a valid client certificate This code (attached) might help you out. I've been meaning to push it to gitgub. > Which is half good, because I know that it's validating the trust > chain from the server to the root CA, but half bad because it's not > sending the client cert. I know it's opening the keystore with my > client cert in it, because I verified it with strace. > > Do I need to use a SSL socket factory class to make this work, or is > it supposed to work out of the box and if so how? You'll need a custom SSLSocketFactory (like the one included in PgClientCertDemo) if you want to target current 8.x versions reliably. Make it configurable, though, because with 9.x Pg versions you won't need it, and using a custom SSLSocketFactory makes it practically impossible for the user to use PKCS#11 hardware keys and the like. -- Craig Ringer
Вложения
On 3/06/2010 8:46 AM, Jeffrey Baker wrote: > I was interested in this[1] work on SSL client certs for JDBC, but I > see the author stopped working on your project. I hope the list can > give me a quick clue, because i've been banging my head against this > all day. > > 1: http://github.com/ringerc/pkcs12provider I stopped working on it because it's unnecessary if Java is configured correctly using the standard, built-in SSLSocketFactory and the system properties controlling it, as documented in the README in that directory. Unfortunately, that's only true with current Pg server versions if the same root signed the server and client certificates, or if you have only one client cert installed in your KeyStore. Otherwise, Java doesn't know which client cert to send. > truststore has only my self-signed root CA cert. keystore has the > root CA cert and my signed client certificate. Using a trivial JDBC > test class and this command line: > > java -cp /usr/share/java/postgresql.jar:. > -Djavax.net.ssl.keyStore=./keystore > -Djavax.net.ssl.trustStore=./truststore TestJdbc > > I get this exception: > > Exception in thread "main" org.postgresql.util.PSQLException: FATAL: > connection requires a valid client certificate This code might help you out. I've been meaning to push it to gitgub. Sources: http://www.postnewspapers.com.au/~craig/PgClientCertDemo.zip Executable: http://www.postnewspapers.com.au/~craig/PgClientCertDemo.jar > Which is half good, because I know that it's validating the trust > chain from the server to the root CA, but half bad because it's not > sending the client cert. I know it's opening the keystore with my > client cert in it, because I verified it with strace. > > Do I need to use a SSL socket factory class to make this work, or is > it supposed to work out of the box and if so how? You'll need a custom SSLSocketFactory (like the one included in PgClientCertDemo) if you want to target current 8.x versions reliably. Make it configurable, though, because with 9.x Pg versions you won't need it, and using a custom SSLSocketFactory makes it practically impossible for the user to use PKCS#11 hardware keys and the like. -- Craig Ringer
On Wed, Jun 2, 2010 at 7:26 PM, Craig Ringer <craig@postnewspapers.com.au> wrote: > On 3/06/2010 8:46 AM, Jeffrey Baker wrote: >> >> I was interested in this[1] work on SSL client certs for JDBC, but I >> see the author stopped working on your project. I hope the list can >> give me a quick clue, because i've been banging my head against this >> all day. >> >> 1: http://github.com/ringerc/pkcs12provider > > I stopped working on it because it's unnecessary if Java is configured > correctly using the standard, built-in SSLSocketFactory and the system > properties controlling it, as documented in the README in that directory. > > Unfortunately, that's only true with current Pg server versions if the same > root signed the server and client certificates, or if you have only one > client cert installed in your KeyStore. Otherwise, Java doesn't know which > client cert to send. Thanks for the info. I have complete control of both ends, and both the server and client are signed by my self-signed root cert. I think perhaps the problem here is that I'm trying to tackle the entire Java SSL infrastructure in one go; I knew nothing about it this morning. I read somewhere that the keystore has to include both the client cert and the root cert that signed it. Is that not true? I've tried it both ways: added root cert, then added client cert (this is the way it's documented in the keytool manual page, the way I interpret it), and only adding the client cert to the keystore. It doesn't seem to work either way. > This code (attached) might help you out. I've been meaning to push it to > gitgub. Thanks again, these classes do seem like they would solve the problem, if I can't figure out the standard way of doing things. >> Which is half good, because I know that it's validating the trust >> chain from the server to the root CA, but half bad because it's not >> sending the client cert. I know it's opening the keystore with my >> client cert in it, because I verified it with strace. >> >> Do I need to use a SSL socket factory class to make this work, or is >> it supposed to work out of the box and if so how? > > You'll need a custom SSLSocketFactory (like the one included in > PgClientCertDemo) if you want to target current 8.x versions reliably. Make > it configurable, though, because with 9.x Pg versions you won't need it, and > using a custom SSLSocketFactory makes it practically impossible for the user > to use PKCS#11 hardware keys and the like. Not a requirement in this project. I want to distribute a WAR file to a third party "cloud" that can access my database, and I want to use client certs that expire in one day rather than distributing passwords. Smart cards and whatnot would be slick for users but don't really apply in virtuality. -jwb
On Wed, Jun 2, 2010 at 5:46 PM, Jeffrey Baker <jwbaker@gmail.com> wrote: > I was interested in this[1] work on SSL client certs for JDBC, but I > see the author stopped working on your project. I hope the list can > give me a quick clue, because i've been banging my head against this > all day. Just to update the list, I did figure this out. Turns out I hadn't imported my private key into the keystore file. Which, in turn, is a ridiculous pain in the butt because keytool can only deal with private keys it generated, or those in PKCS#12 files, and in fact only in PKCS#12 files protected with passwords. Furthermore once the key is in the keystore it must also have a password there (keystore password as well as key password) or the implementation will refuse to use it! # openssl pkcs12 -export -out client.pkcs12 -in client.cert -inkey client.key # keytool -importkeystore -deststorepass changeit -destkeystore client.jks -srckeystore client.pkcs12 -srcstorepass changeit -srcstoretype PKCS12 -alias 1 -destkeypass changeit and $ java -Djavax.net.ssl.keyStore=./client.jks -Djavax.net.ssl.keyStorePassword=changeit -Djavax.net.ssl.trustStore=./truststore Given all that, it works! -jwb
On 3/06/2010 11:06 AM, Jeffrey Baker wrote: > Thanks for the info. > > I have complete control of both ends, and both the server and client > are signed by my self-signed root cert. I think perhaps the problem > here is that I'm trying to tackle the entire Java SSL infrastructure > in one go; I knew nothing about it this morning. I read somewhere > that the keystore has to include both the client cert and the root > cert that signed it. Is that not true? No, it's not strictly true, but it's a good idea. However, "include" is pretty broad. When you get a reply from your certificate authority containing the signed certificate, it should include the full certificate chain in that reply. If it doesn't, you should append the CA cert and any other intermediate certs to the reply before importing it with keytool. So, when you use keytool to list your keystore, you should only see one entry (alias). The certificate part of that entry should preferably include the full certificate chain up to the CA certificate, though. Your truststore should contain only trustedCertificate aliases for the CA certs you trust to identify peers. > I've tried it both ways: > added root cert, then added client cert (this is the way it's > documented in the keytool manual page, the way I interpret it), and > only adding the client cert to the keystore. It doesn't seem to work > either way. Concatenate all certs in the chain into one file, and import that. -- Craig Ringer
On 3/06/2010 12:08 PM, Jeffrey Baker wrote: > On Wed, Jun 2, 2010 at 5:46 PM, Jeffrey Baker<jwbaker@gmail.com> wrote: >> I was interested in this[1] work on SSL client certs for JDBC, but I >> see the author stopped working on your project. I hope the list can >> give me a quick clue, because i've been banging my head against this >> all day. > > Just to update the list, I did figure this out. Turns out I hadn't > imported my private key into the keystore file. Which, in turn, is a > ridiculous pain in the butt because keytool can only deal with private > keys it generated, or those in PKCS#12 files, and in fact only in > PKCS#12 files protected with passwords. It's often easier to just point the keyStore directly at a PKCS#12 file using the javax.net.ssl.trustStoreType=pkcs12 system property. > Furthermore once the key is > in the keystore it must also have a password there (keystore password > as well as key password) or the implementation will refuse to use it! And both passwords must be the SAME. > # openssl pkcs12 -export -out client.pkcs12 -in client.cert -inkey client.key > # keytool -importkeystore -deststorepass changeit -destkeystore > client.jks -srckeystore client.pkcs12 -srcstorepass changeit > -srcstoretype PKCS12 -alias 1 -destkeypass changeit Generally, you are better off using keytool to generate the key and a certificate request, getting that certificate request signed by the CA, and importing the reply into your keystore. -- Craig Ringer