From e583419d679ce65ca5087028ad38b51e3709815c Mon Sep 17 00:00:00 2001 From: "eugene.livis" <elivis@basistech.com> Date: Mon, 13 Nov 2023 18:53:36 -0500 Subject: [PATCH] More work --- .../datamodel/CaseDatabaseFactory.java | 39 +++++++++++++++---- .../datamodel/CaseDbConnectionInfo.java | 16 +++++++- .../sleuthkit/datamodel/SleuthkitCase.java | 16 ++++++-- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java index 8eb7eee9f..fb4900d22 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java @@ -39,17 +39,37 @@ class CaseDatabaseFactory { private static final Logger logger = Logger.getLogger(CaseDatabaseFactory.class.getName()); private final SQLHelper dbQueryHelper; private final DbCreationHelper dbCreationHelper; - - // ssl=true: enables SSL encryption. - // DefaultJavaSSLFactory: uses Java's default truststore to validate server certificate. - // sslmode=verify-ca: verifies that the server we are connecting to is trusted by CA. - final static String SSL_VERIFY_URL = "?ssl=true&sslfactory=org.postgresql.ssl.DefaultJavaSSLFactory&sslmode=verify-ca"; - + // ssl=true: enables SSL encryption. // NonValidatingFactory avoids hostname verification. // sslmode=require: This mode makes the encryption mandatory and also requires the connection to fail if it can't be encrypted. // In this mode, the JDBC driver accepts all server certificates, including self-signed ones. final static String SSL_NONVERIFY_URL = "?ssl=true&sslfactory=org.postgresql.ssl.NonValidatingFactory&sslmode=require"; + + // ssl=true: enables SSL encryption. + // DefaultJavaSSLFactory: uses Java's default truststore to validate server certificate. + // sslmode=verify-ca: verifies that the server we are connecting to is trusted by CA. + final static String SSL_VERIFY_DEFAULT_URL = "?ssl=true&sslfactory=org.postgresql.ssl.DefaultJavaSSLFactory&sslmode=verify-ca"; + + /** + * Creates JDBC URL string for implementations that use custom keystore to + * validate PostgreSQL CA-signed SSL certificates. The class that performs + * SSL certificate validation must extend org.postgresql.ssl.WrappedFactory + * and generally must follow the same logic. + * + * ssl=true: enables SSL encryption. sslmode=verify-ca: verifies that the + * server we are connecting to is trusted by CA. + * + * @param customSslValidationClassName full canonical name of a Java class + * that performs custom SSL certificate + * validation. + * + * @return JDBS URL string used to connect to PosgreSQL server via CA-signed + * SSL certificate. + */ + static String getCustomPostrgesSslVerificationUrl(String customSslValidationClassName) { + return "?ssl=true&sslfactory=" + customSslValidationClassName + "&sslmode=verify-ca"; + } /** * Create a new SQLite case @@ -726,7 +746,12 @@ Connection getConnection(String databaseName) throws TskCoreException { if (info.isSslEnabled()) { if (info.isSslVerify()) { - url.append(SSL_VERIFY_URL); + if (info.getCustomSslValidationClassName().isBlank()) { + url.append(SSL_VERIFY_DEFAULT_URL); + } else { + // use custom SSL certificate validation class + url.append(getCustomPostrgesSslVerificationUrl(info.getCustomSslValidationClassName())); + } } else { url.append(SSL_NONVERIFY_URL); } diff --git a/bindings/java/src/org/sleuthkit/datamodel/CaseDbConnectionInfo.java b/bindings/java/src/org/sleuthkit/datamodel/CaseDbConnectionInfo.java index 4cf918dfe..2aa4d17ca 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CaseDbConnectionInfo.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CaseDbConnectionInfo.java @@ -36,6 +36,7 @@ public class CaseDbConnectionInfo { private DbType dbType; private boolean sslEnabled = false; private boolean sslVerify = false; + private String customSslValidationClassName; /** * The intent of this class is to hold any information needed to connect to @@ -62,6 +63,7 @@ public CaseDbConnectionInfo(String hostNameOrIP, String portNumber, String userN throw new IllegalArgumentException("SQLite database type invalid for CaseDbConnectionInfo. CaseDbConnectionInfo should be used only for remote database types."); } this.dbType = dbType; + this.customSslValidationClassName = ""; } /** @@ -80,8 +82,11 @@ public CaseDbConnectionInfo(String hostNameOrIP, String portNumber, String userN * @param dbType the database type * @param sslEnabled a flag whether SSL is enabled * @param sslVerify 'true' if SSL certificate needs to be CA verified. 'false' if self-signed certificates should be accepted. + * @param customSslValidationClassName full canonical name of a Java class + * that performs custom SSL certificate + * validation. */ - public CaseDbConnectionInfo(String hostNameOrIP, String portNumber, String userName, String password, DbType dbType, boolean sslEnabled, boolean sslVerify) { + public CaseDbConnectionInfo(String hostNameOrIP, String portNumber, String userName, String password, DbType dbType, boolean sslEnabled, boolean sslVerify, String customSslValidationClassName) { this.hostNameOrIP = hostNameOrIP; this.portNumber = portNumber; this.userName = userName; @@ -92,6 +97,7 @@ public CaseDbConnectionInfo(String hostNameOrIP, String portNumber, String userN throw new IllegalArgumentException("SQLite database type invalid for CaseDbConnectionInfo. CaseDbConnectionInfo should be used only for remote database types."); } this.dbType = dbType; + this.customSslValidationClassName = customSslValidationClassName; } public DbType getDbType() { @@ -149,4 +155,12 @@ public boolean isSslVerify() { public void setSslVerify(boolean sslVerify) { this.sslVerify = sslVerify; } + + public String getCustomSslValidationClassName() { + return customSslValidationClassName; + } + + public void setCustomSslValidationClassName(String customSslValidationClassName) { + this.customSslValidationClassName = customSslValidationClassName; + } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index e2047be0a..6eceb161a 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -1,7 +1,7 @@ /* * Sleuth Kit Data Model * - * Copyright 2011-2021 Basis Technology Corp. + * Copyright 2011-2023 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -296,7 +296,12 @@ public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException String connectionURL = "jdbc:postgresql://" + info.getHost() + ":" + info.getPort() + "/postgres"; if (info.isSslEnabled()) { if (info.isSslVerify()) { - connectionURL += CaseDatabaseFactory.SSL_VERIFY_URL; + if (info.getCustomSslValidationClassName().isBlank()) { + connectionURL += CaseDatabaseFactory.SSL_VERIFY_DEFAULT_URL; + } else { + // use custom SSL certificate validation class + connectionURL += CaseDatabaseFactory.getCustomPostrgesSslVerificationUrl(info.getCustomSslValidationClassName()); + } } else { connectionURL += CaseDatabaseFactory.SSL_NONVERIFY_URL; } @@ -13407,7 +13412,12 @@ private final class PostgreSQLConnections extends ConnectionPool { + URLEncoder.encode(dbName, StandardCharsets.UTF_8.toString()); if (info.isSslEnabled()) { if (info.isSslVerify()) { - connectionURL += CaseDatabaseFactory.SSL_VERIFY_URL; + if (info.getCustomSslValidationClassName().isBlank()) { + connectionURL += CaseDatabaseFactory.SSL_VERIFY_DEFAULT_URL; + } else { + // use custom SSL certificate validation class + connectionURL += CaseDatabaseFactory.getCustomPostrgesSslVerificationUrl(info.getCustomSslValidationClassName()); + } } else { connectionURL += CaseDatabaseFactory.SSL_NONVERIFY_URL; } -- GitLab