/* * Copyright (c) 2004, PostgreSQL Global Development Group * See the LICENSE file in the project root for more information. */ package org.postgresql.test.ssl; import org.postgresql.test.TestUtil; import junit.framework.TestCase; import junit.framework.TestSuite; import java.io.File; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Map; import java.util.Properties; import java.util.TreeMap; public class SslTest extends TestCase { /** * Tries to connect to the database. * * @param connstr Connection string for the database * @param expected Expected values. the first element is a String holding the expected message of * PSQLException or null, if no exception is expected, the second indicates weather ssl is * to be used (Boolean) */ protected void driver(String connstr, Object[] expected) throws SQLException { Connection conn = null; String exmsg = (String) expected[0]; try { conn = DriverManager.getConnection(connstr, TestUtil.getUser(), TestUtil.getPassword()); if (exmsg != null) { fail("Exception did not occur: " + exmsg); } // ResultSet rs = conn.createStatement().executeQuery("select ssl_is_used()"); assertTrue(rs.next()); assertEquals("ssl_is_used: ", ((Boolean) expected[1]).booleanValue(), rs.getBoolean(1)); conn.close(); } catch (SQLException ex) { if (conn != null) { conn.close(); } if (exmsg == null) { // no exception is excepted fail("Exception thrown: " + ex.getMessage()); } else { assertTrue("expected: " + exmsg + " actual: " + ex.getMessage(), ex.getMessage().matches(exmsg)); return; } } } protected String certdir; protected String connstr; protected String sslmode; protected int protocol; protected boolean goodclient; protected boolean goodserver; protected String prefix; protected Object[] expected; private String makeConnStr(String sslmode, boolean goodclient, boolean goodserver, int protocol) { return connstr + "&protocolVersion=" + protocol + "&sslmode=" + sslmode + "&sslcert=" + certdir + "/" + prefix + (goodclient ? "goodclient.crt" : "badclient.crt") + "&sslkey=" + certdir + "/" + prefix + (goodclient ? "goodclient.pk8" : "badclient.pk8") + "&sslrootcert=" + certdir + "/" + prefix + (goodserver ? "goodroot.crt" : "badroot.crt") + "&loglevel=" + TestUtil.getLogLevel(); } public SslTest(String name, String certdir, String connstr, String sslmode, int protocol, boolean goodclient, boolean goodserver, String prefix, Object[] expected) { super(name); this.certdir = certdir; this.connstr = connstr; this.sslmode = sslmode; this.protocol = protocol; this.goodclient = goodclient; this.goodserver = goodserver; this.prefix = prefix; this.expected = expected; } static TestSuite getSuite(Properties prop, String param) { File certDirFile = TestUtil.getFile(prop.getProperty("certdir")); String certdir = certDirFile.getAbsolutePath(); String sconnstr = prop.getProperty(param); String sprefix = prop.getProperty(param + "prefix"); String[] sslModes = {"disable", "allow", "prefer", "require", "verify-ca", "verify-full"}; TestSuite suite = new TestSuite(); Map<String, Object[]> expected = expectedmap.get(param); if (expected == null) { expected = defaultexpected; } for (String sslMode : sslModes) { suite.addTest(new SslTest(param + "-" + sslMode + "GG2", certdir, sconnstr, sslMode, 2, true, true, sprefix, expected.get(sslMode + "GG"))); suite.addTest(new SslTest(param + "-" + sslMode + "GG3", certdir, sconnstr, sslMode, 3, true, true, sprefix, expected.get(sslMode + "GG"))); suite.addTest(new SslTest(param + "-" + sslMode + "GB2", certdir, sconnstr, sslMode, 2, true, false, sprefix, expected.get(sslMode + "GB"))); suite.addTest(new SslTest(param + "-" + sslMode + "GB3", certdir, sconnstr, sslMode, 3, true, false, sprefix, expected.get(sslMode + "GB"))); suite.addTest(new SslTest(param + "-" + sslMode + "BG2", certdir, sconnstr, sslMode, 2, false, true, sprefix, expected.get(sslMode + "BG"))); suite.addTest(new SslTest(param + "-" + sslMode + "BG3", certdir, sconnstr, sslMode, 3, false, true, sprefix, expected.get(sslMode + "BG"))); } return suite; } protected void runTest() throws Throwable { driver(makeConnStr(sslmode, goodclient, goodserver, protocol), expected); } static Map<String, Map<String, Object[]>> expectedmap; static TreeMap<String, Object[]> defaultexpected; // For some strange reason, the v2 driver begins these error messages by "Connection rejected: " // but the v3 does not. // Also, for v2 there are two spaces after FATAL:, and the message ends with "\n.". static String PG_HBA_ON = "(Connection rejected: )?FATAL: ?no pg_hba.conf entry for host .*, user .*, database .*, SSL on(?s-d:.*)"; static String PG_HBA_OFF = "(Connection rejected: )?FATAL: ?no pg_hba.conf entry for host .*, user .*, database .*, SSL off(?s-d:.*)"; static String FAILED = "The connection attempt failed."; static String BROKEN = "SSL error: (Broken pipe|Received fatal alert: unknown_ca|Connection reset)"; static String SSLMODE = "Invalid sslmode value: (allow|prefer)"; // static String UNKNOWN = "SSL error: Broken pipe"; // static String UNKNOWN = "SSL error: Received fatal alert: unknown_ca"; static String ANY = ".*"; static String VALIDATOR = "SSL error: sun.security.validator.ValidatorException: PKIX path (building|validation) failed:.*"; static String HOSTNAME = "The hostname .* could not be verified."; static { defaultexpected = new TreeMap<String, Object[]>(); defaultexpected.put("disableGG", new Object[]{null, Boolean.FALSE}); defaultexpected.put("disableGB", new Object[]{null, Boolean.FALSE}); defaultexpected.put("disableBG", new Object[]{null, Boolean.FALSE}); defaultexpected.put("allowGG", new Object[]{SSLMODE, Boolean.TRUE}); defaultexpected.put("allowGB", new Object[]{SSLMODE, Boolean.TRUE}); defaultexpected.put("allowBG", new Object[]{SSLMODE, Boolean.TRUE}); defaultexpected.put("preferGG", new Object[]{SSLMODE, Boolean.TRUE}); defaultexpected.put("preferGB", new Object[]{SSLMODE, Boolean.TRUE}); defaultexpected.put("preferBG", new Object[]{SSLMODE, Boolean.TRUE}); defaultexpected.put("requireGG", new Object[]{null, Boolean.TRUE}); defaultexpected.put("requireGB", new Object[]{null, Boolean.TRUE}); defaultexpected.put("requireBG", new Object[]{null, Boolean.TRUE}); defaultexpected.put("verify-caGG", new Object[]{null, Boolean.TRUE}); defaultexpected.put("verify-caGB", new Object[]{ANY, Boolean.TRUE}); defaultexpected.put("verify-caBG", new Object[]{null, Boolean.TRUE}); defaultexpected.put("verify-fullGG", new Object[]{null, Boolean.TRUE}); defaultexpected.put("verify-fullGB", new Object[]{ANY, Boolean.TRUE}); defaultexpected.put("verify-fullBG", new Object[]{null, Boolean.TRUE}); expectedmap = new TreeMap<String, Map<String, Object[]>>(); TreeMap<String, Object[]> work; work = (TreeMap) defaultexpected.clone(); work.put("disableGG", new Object[]{null, Boolean.FALSE}); work.put("disableGB", new Object[]{null, Boolean.FALSE}); work.put("disableBG", new Object[]{null, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferGG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferGB", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("requireGG", new Object[]{ANY, Boolean.TRUE}); work.put("requireGB", new Object[]{ANY, Boolean.TRUE}); work.put("requireBG", new Object[]{ANY, Boolean.TRUE}); work.put("verify-caGG", new Object[]{ANY, Boolean.TRUE}); work.put("verify-caGB", new Object[]{ANY, Boolean.TRUE}); work.put("verify-caBG", new Object[]{ANY, Boolean.TRUE}); work.put("verify-fullGG", new Object[]{ANY, Boolean.TRUE}); work.put("verify-fullGB", new Object[]{ANY, Boolean.TRUE}); work.put("verify-fullBG", new Object[]{ANY, Boolean.TRUE}); expectedmap.put("ssloff8", work); work = (TreeMap) work.clone(); expectedmap.put("ssloff9", work); work = (TreeMap) defaultexpected.clone(); work.put("disableGG", new Object[]{null, Boolean.FALSE}); work.put("disableGB", new Object[]{null, Boolean.FALSE}); work.put("disableBG", new Object[]{null, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferGG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferGB", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("requireGG", new Object[]{PG_HBA_ON, Boolean.TRUE}); work.put("requireGB", new Object[]{PG_HBA_ON, Boolean.TRUE}); work.put("requireBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-caGG", new Object[]{PG_HBA_ON, Boolean.TRUE}); work.put("verify-caGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-caBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-fullGG", new Object[]{PG_HBA_ON, Boolean.TRUE}); work.put("verify-fullGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-fullBG", new Object[]{BROKEN, Boolean.TRUE}); expectedmap.put("sslhostnossl8", work); work = (TreeMap) work.clone(); expectedmap.put("sslhostnossl9", work); work = (TreeMap) defaultexpected.clone(); work.put("disableGG", new Object[]{null, Boolean.FALSE}); work.put("disableGB", new Object[]{null, Boolean.FALSE}); work.put("disableBG", new Object[]{null, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("requireGG", new Object[]{null, Boolean.TRUE}); work.put("requireGB", new Object[]{null, Boolean.TRUE}); work.put("requireBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-caGG", new Object[]{null, Boolean.TRUE}); work.put("verify-caGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-caBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-fullGG", new Object[]{null, Boolean.TRUE}); work.put("verify-fullGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-fullBG", new Object[]{BROKEN, Boolean.TRUE}); expectedmap.put("sslhostgh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslhostgh9", work); work = (TreeMap) work.clone(); work.put("disableGG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableGB", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableBG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.FALSE}); expectedmap.put("sslhostsslgh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslhostsslgh9", work); work = (TreeMap) defaultexpected.clone(); work.put("disableGG", new Object[]{null, Boolean.FALSE}); work.put("disableGB", new Object[]{null, Boolean.FALSE}); work.put("disableBG", new Object[]{null, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.FALSE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("preferGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.FALSE}); work.put("requireGG", new Object[]{null, Boolean.TRUE}); work.put("requireGB", new Object[]{null, Boolean.TRUE}); work.put("requireBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-caGG", new Object[]{null, Boolean.TRUE}); work.put("verify-caGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-caBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-fullGG", new Object[]{HOSTNAME, Boolean.TRUE}); work.put("verify-fullGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-fullBG", new Object[]{BROKEN, Boolean.TRUE}); expectedmap.put("sslhostbh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslhostbh9", work); work = (TreeMap) work.clone(); work.put("disableGG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableGB", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableBG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.FALSE}); expectedmap.put("sslhostsslbh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslhostsslbh9", work); work = (TreeMap) defaultexpected.clone(); work.put("disableGG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableGB", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableBG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("requireGG", new Object[]{null, Boolean.TRUE}); work.put("requireGB", new Object[]{null, Boolean.TRUE}); work.put("requireBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-caGG", new Object[]{null, Boolean.TRUE}); work.put("verify-caGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-caBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-fullGG", new Object[]{null, Boolean.TRUE}); work.put("verify-fullGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-fullBG", new Object[]{BROKEN, Boolean.TRUE}); expectedmap.put("sslhostsslcertgh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslhostsslcertgh9", work); work = (TreeMap) defaultexpected.clone(); work.put("disableGG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableGB", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableBG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("requireGG", new Object[]{null, Boolean.TRUE}); work.put("requireGB", new Object[]{null, Boolean.TRUE}); work.put("requireBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-caGG", new Object[]{null, Boolean.TRUE}); work.put("verify-caGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-caBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-fullGG", new Object[]{HOSTNAME, Boolean.TRUE}); work.put("verify-fullGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-fullBG", new Object[]{BROKEN, Boolean.TRUE}); expectedmap.put("sslhostsslcertbh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslhostsslcertbh9", work); work = (TreeMap) defaultexpected.clone(); work.put("disableGG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableGB", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("disableBG", new Object[]{PG_HBA_OFF, Boolean.FALSE}); work.put("allowGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("allowBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferGB", new Object[]{SSLMODE, Boolean.TRUE}); work.put("preferBG", new Object[]{SSLMODE, Boolean.TRUE}); work.put("requireGG", new Object[]{null, Boolean.TRUE}); work.put("requireGB", new Object[]{null, Boolean.TRUE}); work.put("requireBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-caGG", new Object[]{null, Boolean.TRUE}); work.put("verify-caGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-caBG", new Object[]{BROKEN, Boolean.TRUE}); work.put("verify-fullGG", new Object[]{null, Boolean.TRUE}); work.put("verify-fullGB", new Object[]{VALIDATOR, Boolean.TRUE}); work.put("verify-fullBG", new Object[]{BROKEN, Boolean.TRUE}); expectedmap.put("sslcertgh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslcertgh9", work); work = (TreeMap) work.clone(); work.put("verify-fullGG", new Object[]{HOSTNAME, Boolean.TRUE}); expectedmap.put("sslcertbh8", work); work = (TreeMap) work.clone(); expectedmap.put("sslcertbh9", work); } }