PostgreSQL connectivity with JDBC over SSL

July 22, 2007

First, I configured the PostgreSQL server for SSL by changing two parameters in the file /var/lib/postgresql/7.4/main/postgresql.conf.

tcpip_socket = true
ssl = true

I generated a private key and self-signed certificate for the PostgreSQL server. ANY is a placeholder for a pass phrase (it won’t be needed any further, because automatic database server start-up requires that we store an unencrypted private key); HOST is a placeholder for my VPS host name.

# openssl req -new -text -out pg_server.req
Enter PEM pass phrase: ANY
Common Name (eg, YOUR name) []: HOST.vps.budgetdedicated.com
# openssl rsa -in privkey.pem -out pg_server.key
# openssl req -x509 -in pg_server.req -text -key pg_server.key -out pg_server.crt
# chmod og-rwx pg_server.key
# rm privkey.pem pg_server.req

Next, I switched to my client machine (an iMac G5, which runs Mac OS X, OpenSSL 0.9.7l, Java 1.5, and Eclipse 3.3 among other things) and generated a private key and self-signed certificate for its use (and for client certificate verification on the server).

$ openssl req -new -text -out pg_client.req
Enter PEM pass phrase: ANY
Common Name (eg, YOUR name) []: mymac
$ openssl rsa -in privkey.pem -out pg_client.key
$ openssl req -x509 -in pg_client.req -text -key pg_client.key -out pg_client.crt
$ chmod og-rwx pg_client.key
$ rm privkey.pem pg_client.req

I used scp for copying the certificate files pg_server.crt and pg_client.crt to both machines. I then installed the various cryptographic instruments in the PostgreSQL data directory and restarted the server.

# su postgres
# mv /var/lib/postgresql/7.4/main/root.crt root.crt.save
# cp pg_server.key /var/lib/postgresql/7.4/main/server.key
# cp pg_server.crt /var/lib/postgresql/7.4/main/server.crt
# cp pg_client.crt /var/lib/postgresql/7.4/main/root.crt
# /etc/init.d/postgresql-7.4 restart

On the client, the equivalent step consists of adding the server certificate to the Java key store (default password applies).

$ sudo su -
# export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home
# openssl x509 -in pg_server.crt -out pg_server.crt.der -outform der
# keytool -keystore $JAVA_HOME/lib/security/cacerts -alias pg_server \\
          -import -file pg_server.crt.der

I wrote a Java test case in Eclipse, and then installed and added the PostgreSQL JDBC 3 driver to the project build path. As before, HOST and PASSWORD are placeholders for my VPS host name and guava’s PostgreSQL password respectively.

package guava.junit;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
import org.junit.Test;
import static org.junit.Assert.*;

public class JdbcRemotePostgreSqlTest {

  @Test public void connection() throws Exception {
    Class.forName("org.postgresql.Driver").newInstance();

    final String     url        = "jdbc:postgresql://HOST.vps.budgetdedicated.com/guava";
    final Properties properties = new Properties();
    properties.put("user",     "guava");
    properties.put("password", "PASSWORD");
    properties.put("ssl",      "true");

    Connection connection = DriverManager.getConnection(url, properties);
    assertFalse(connection.isClosed());

    connection.close();
  }
}

The test case succeeded, and the following remote authentication steps are in effect:

  • JDBC client validates PostgreSQL server certificate
  • PostgreSQL server checks IP address of (JDBC) client
  • PostgreSQL server requires password from (JDBC) client (digest over SSL)

As for client certificate validation by the PostgeSQL server, I’m still a bit puzzled. Since there is a root.crt (with a copy of pg_client.crt) on the server, I would expect that the server enforces this check, but so far the Java program does not yet know nor convey the right client credential. Further inspection of debugging information suggests that the server sends a Certificate request (as it should), and the client replies with zero Client certificates (as it also should, but why does the server let this pass?). Anyway, I’ll call it a day for now, and the setup is probably already quite secure as is :)

I’ve also deleted all of the aforementioned files pg_* on both machines (those copies are no longer needed).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: