web-dev-qa-db-fra.com

Comment examiner le certificat SSL du serveur PostgreSQL?

Supposons qu'un serveur PostgreSQL soit en cours d'exécution et que SSL soit activé. En utilisant les outils Linux et PostgreSQL "standard", comment puis-je examiner son certificat SSL?

J'espère une sortie similaire à ce que vous obtiendriez en exécutant openssl x509 -text .... Et j'espère une réponse en ligne de commande à une ou deux lignes pour ne pas avoir à utiliser un renifleur de paquets.

Je n'ai pas accès au serveur PostgreSQL, donc je ne peux pas regarder directement ses fichiers de configuration.

Je n'ai pas de connexion de superutilisateur, donc je ne peux pas obtenir la valeur de ssl_cert_file paramètre puis pg_read_file dessus.

En utilisant openssl s_client -connect ... ne fonctionne pas car PostgreSQL ne semble pas vouloir faire immédiatement la prise de contact SSL.

D'un rapide coup d'œil à la documentation psql, je n'ai pas pu trouver un paramètre de ligne de commande qui lui fasse afficher ces informations au démarrage. (Bien qu'il me montre certaines informations chiffrées.)

14
csd

Il semble que l'outil s_client D'OpenSSL ait ajouté la prise en charge Postgres en utilisant le -starttls Dans 1.1.1, vous pouvez donc désormais utiliser toute la puissance des outils de ligne de commande d'OpenSSL sans scripts d'aide supplémentaires:

openssl s_client -starttls postgres -connect my.postgres.Host:5432 # etc...

Références:

7
Adam Batkin

Suite à l'idée dans le commentaire de Craig Ringer:

Une option consiste à patcher openssl s_client pour établir une liaison avec le protocole PostgreSQL. Vous pouvez probablement aussi le faire avec Java, en passant un SSLSocketFactory personnalisé à PgJDBC. Je ne suis pas sûr qu'il existe des options simples.

... J'ai écrit une simple fabrique de sockets SSL. J'ai copié le code de la classe NonValidatingFactory de PgJDBC et j'ai ajouté du code pour imprimer les certificats.

Voici à quoi cela ressemblait, quand tout a été dit et fait:

import Java.security.GeneralSecurityException;
import Java.security.cert.X509Certificate;
import Java.sql.Connection;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.postgresql.ds.PGSimpleDataSource;
import org.postgresql.ssl.WrappedFactory;

public class ShowPostgreSQLCert {
    public static void main(String[] args) throws Throwable {
        PGSimpleDataSource ds = new PGSimpleDataSource();
        ds.setServerName( ... );
        ds.setSsl(true);
        ds.setUser( ... );
        ds.setDatabaseName( ... );
        ds.setPassword( ... );
        ds.setSslfactory(DumperFactory.class.getName());
        try (Connection c = ds.getConnection()) { }
    }

    public static class DumperFactory extends WrappedFactory {
        public DumperFactory(String arg) throws GeneralSecurityException {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { new DumperTM() }, null);
            _factory = ctx.getSocketFactory();
        }
    }

    public static class DumperTM implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        public void checkClientTrusted(X509Certificate[] certs, String authType) { }
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            for (int i=0; i<certs.length; ++i) {
                System.out.println("Cert " + (i+1) + ":");
                System.out.println("    Subject: " + certs[i].getSubjectX500Principal().getName());
                System.out.println("    Issuer: " + certs[i].getIssuerX500Principal().getName());
            }
        }
    }
}
10
csd

Si vous ne voulez pas vous soucier d'installer Java et de compiler, et que vous avez déjà python, vous pouvez essayer ceci python: https : //github.com/thusoy/postgres-mitm/blob/master/postgres_get_server_cert.py

Je l'utilise pour vérifier les dates de certificats:

postgres_get_server_cert.py example.com:5432 | openssl x509 -noout -dates

Ou pour le certificat complet sous forme de texte:

postgres_get_server_cert.py example.com:5432 | openssl x509 -noout -text
7
mivk

réponse de csd m'a vraiment sauvé. Voici une procédure plus détaillée pour ceux d'entre nous qui ne connaissent pas ou ont oublié Java.

  1. Assurez-vous que votre serveur peut compiler Java. Essayez la commande "which javac", si elle génère quelque chose comme "... no javac in ...", vous devez installer un JDK (JRE ne fonctionnera pas, il a "Java" mais pas "javac").

  2. Installez postgresql-jdbc si vous ne l'avez pas déjà. Pour RHEL6, la commande est "yum install postgresql-jdbc". Déterminez où les fichiers jar sont installés. Il y en aura plusieurs, un pour chaque version. J'ai utilisé "/usr/share/Java/postgresql-jdbc3.jar".

  3. Copiez le code de csd et insérez les informations de base de données (l'autre réponse), ou utilisez ma version légèrement modifiée à la fin de cette réponse. Enregistrez-le dans un fichier appelé exactement "ShowPostgreSQLCert.Java". Les majuscules/minuscules sont importantes, appelez-le autrement et cela ne se compilera pas.

  4. Dans le répertoire contenant le fichier ShowPostgreSQLCert.Java, exécutez la commande suivante (modifiez l'emplacement de postgresql-jdbc3.jar si nécessaire): "javac -cp /usr/share/Java/postgresql-jdbc3.jar ShowPostgreSQLCert.Java". Vous devriez maintenant avoir 3 fichiers .class dans le même répertoire.

  5. Enfin, exécutez la commande suivante: "Java -cp.:/Usr/share/Java/postgresql-jdbc3.jar ShowPostgreSQLCert". Le "." après "-cp" signifie qu'il devrait chercher dans le répertoire courant les fichiers .class. Vous pouvez insérer le chemin d'accès complet aux fichiers de classe ici, n'oubliez pas de garder le ":" entre le chemin et l'emplacement du fichier .jar.

  6. Si vous devez exécuter la commande sur une autre machine, vous devez avoir le même fichier jar installé (postgresql-jdbc3.jar), ou vous pouvez probablement le copier à partir du serveur sur lequel vous avez compilé les fichiers .class. Ensuite, copiez simplement les fichiers .class et exécutez la commande à partir de 5. après avoir modifié les chemins.

J'ai légèrement modifié le code afin que vous puissiez transmettre des informations de base de données sur la ligne de commande au lieu de les compiler dans le fichier .class. Il suffit de l'exécuter sans aucun argument et il affichera un message indiquant les arguments qu'il attend. Le code + modifications de csd est:

import Java.security.GeneralSecurityException;
import Java.security.cert.X509Certificate;
import Java.sql.Connection;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.postgresql.ds.PGSimpleDataSource;
import org.postgresql.ssl.WrappedFactory;

public class ShowPostgreSQLCert {
    public static void main(String[] args) throws Throwable {
        PGSimpleDataSource ds = new PGSimpleDataSource();
        if( args.length != 4 ) {
            System.out.println("Not enough arguments. Usage: ShowPostgreSQLCert ServerName User DatabaseName Password");
            System.exit(1);
        }
        ds.setServerName( args[0] );
        ds.setSsl(true);
        ds.setUser( args[1] );
        ds.setDatabaseName( args[2] );
        ds.setPassword( args[3] );
        ds.setSslfactory(DumperFactory.class.getName());
        try (Connection c = ds.getConnection()) { }
    }

    public static class DumperFactory extends WrappedFactory {
        public DumperFactory(String arg) throws GeneralSecurityException {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { new DumperTM() }, null);
            _factory = ctx.getSocketFactory();
        }
    }

    public static class DumperTM implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        public void checkClientTrusted(X509Certificate[] certs, String authType) { }
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            for (int i=0; i<certs.length; ++i) {
                System.out.println("Cert " + (i+1) + ":");
                System.out.println("    Subject: " + certs[i].getSubjectX500Principal().getName());
                System.out.println("    Issuer: " + certs[i].getIssuerX500Principal().getName());
            }
        }
    }
}
3
vidarsk

J'ai ajouté du code de https://stackoverflow.com/questions/3313020/write-x509-certificate-into-pem-formatted-string-in-Java pour sortir les certificats en tant que PEM, et supprimé la nécessité de spécifier une base de données, un nom d'utilisateur ou un mot de passe (ils ne sont pas nécessaires pour obtenir le certificat).

Grâce à cela, j'ai pu vérifier qu'un redémarrage de PostgreSQL ne semble malheureusement pas nécessaire pour passer à un nouveau certificat.

N'étant pas un développeur Java, mes étapes pour construire et exécuter ne sont probablement pas si bonnes, mais elles fonctionnent, tant que vous pouvez trouver un jdbc postgresql

# locate postgresql | grep jar
/path/to/a/lib/postgresql-9.1-901-1.jdbc4.jar   <-- this one will do
...

Compiler:

javac -cp /path/to/a/lib/postgresql-9.1-901-1.jdbc4.jar ./ShowPostgreSQLCert.Java

Courir:

Java -cp /path/to/a/lib/postgresql-9.1-901-1.jdbc4.jar:. ShowPostgreSQLCert 127.0.0.1

Exemple de sortie:

Cert 1:
    Subject: CN=...
    Issuer: CN=...
    Not Before: Fri Oct 21 11:14:06 NZDT 2016
    Not After: Sun Oct 21 11:24:00 NZDT 2018
-----BEGIN CERTIFICATE-----
MIIHEjCCBfqgAwIBAgIUUbiRZjruNAEo2j1QPqBh6GzcNrwwDQYJKoZIhvcNAQEL
...
IcIXcVQxPzVrpIDT5G6jArVt+ERLEWs2V09iMwY7//CQb0ivpVg=
-----END CERTIFICATE-----

Cert 2:
...

La source:

import Java.security.GeneralSecurityException;
import Java.security.cert.X509Certificate;
import Java.sql.Connection;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.postgresql.ds.PGSimpleDataSource;
import org.postgresql.ssl.WrappedFactory;

import javax.xml.bind.DatatypeConverter;
import Java.security.cert.X509Certificate;
import Java.io.StringWriter;

public class ShowPostgreSQLCert {
    public static void main(String[] args) throws Throwable {
        PGSimpleDataSource ds = new PGSimpleDataSource();
        if( args.length != 1 ) {
            System.out.println("Not enough arguments.");
            System.out.println("Usage: ShowPostgreSQLCert ServerName");
            System.exit(1);
        }
        ds.setServerName( args[0] );
        ds.setSsl(true);
        ds.setUser( "" );
        ds.setDatabaseName( "" );
        ds.setPassword( "" );
        ds.setSslfactory(DumperFactory.class.getName());
        try (Connection c = ds.getConnection()) { }
        catch (org.postgresql.util.PSQLException e) {
            // Don't actually want to login
        }
    }

    public static class DumperFactory extends WrappedFactory {
        public DumperFactory(String arg) throws GeneralSecurityException {
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { new DumperTM() }, null);
            _factory = ctx.getSocketFactory();
        }
    }

    public static String certToString(X509Certificate cert) {
        StringWriter sw = new StringWriter();
        try {
            sw.write("-----BEGIN CERTIFICATE-----\n");
            sw.write(DatatypeConverter.printBase64Binary(cert.getEncoded()).replaceAll("(.{64})", "$1\n"));
            sw.write("\n-----END CERTIFICATE-----\n");
        } catch (Java.security.cert.CertificateEncodingException e) {
            e.printStackTrace();
        }
        return sw.toString();
    }

    public static class DumperTM implements X509TrustManager {
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
        public void checkClientTrusted(X509Certificate[] certs, String authType) { }
        public void checkServerTrusted(X509Certificate[] certs, String authType) {
            for (int i=0; i<certs.length; ++i) {

                System.out.println("Cert " + (i+1) + ":");
                System.out.println("    Subject: " + certs[i].getSubjectX500Principal().getName());
                System.out.println("    Issuer: " + certs[i].getIssuerX500Principal().getName());
                System.out.println("    Not Before: " + certs[i].getNotBefore().toString());
                System.out.println("    Not After: " + certs[i].getNotAfter().toString());

                System.out.println(certToString(certs[i]));
            }
        }
    }
}
1
Cameron Kerr