Add support for SSL CRL (Certificate Revocation List).
authorTatsuo Ishii <ishii@sraoss.co.jp>
Sat, 14 Mar 2020 02:54:38 +0000 (11:54 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Sat, 14 Mar 2020 02:54:38 +0000 (11:54 +0900)
Patch created by Umar Hayat, along with Japanese document by Tatsuo
Ishii.
Discussion: https://www.pgpool.net/pipermail/pgpool-hackers/2020-February/003505.html

13 files changed:
doc.ja/src/sgml/ssl.sgml
doc/src/sgml/ssl.sgml
src/config/pool_config_variables.c
src/include/pool_config.h
src/sample/pgpool.conf.sample-logical
src/sample/pgpool.conf.sample-raw
src/sample/pgpool.conf.sample-replication
src/sample/pgpool.conf.sample-slony
src/sample/pgpool.conf.sample-stream
src/test/regression/tests/024.cert_auth/cert.sh
src/test/regression/tests/024.cert_auth/test.sh
src/utils/pool_process_reporting.c
src/utils/pool_ssl.c

index 18e071475eae5aac4d3fc7a67a7856ff17ebf215..755d40f1b4a451d8aac9b7f09ef0c708207e527d 100644 (file)
     </listitem>
    </varlistentry>
 
+   <varlistentry id="guc-ssl-crl-file" xreflabel="ssl_crl_file">
+    <term><varname>ssl_crl_file</varname> (<type>string</type>)
+     <indexterm>
+      <primary><varname>ssl_crl_file</varname>設定パラメータ</primary>
+     </indexterm>
+    </term>
+    <listitem>
+     <para>
+      SSSLサーバ証明書失効リスト(CRL)が入っているファイルのパス名を設定します。
+      デフォルトは空で、この場合<acronym>CRL</acronym>ファイルは読み込まれません。
+     </para>
+
+     <para>
+      このパラメータはサーバ起動時にのみ設定可能です。
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry id="guc-ssl-ciphers" xreflabel="ssl_ciphers">
     <term><varname>ssl_ciphers</varname> (<type>string</type>)
      <indexterm>
index c7a2693176c18664bc8b823706f881e0e6599ce0..0b04b2448d689c6a69c53a937e9c5daad2ac4cc7 100644 (file)
     </listitem>
    </varlistentry>
 
+   <varlistentry id="guc-ssl-crl-file" xreflabel="ssl_crl_file">
+    <term><varname>ssl_crl_file</varname> (<type>string</type>)
+     <indexterm>
+      <primary><varname>ssl_crl_file</varname> configuration parameter</primary>
+     </indexterm>
+    </term>
+    <listitem>
+     <para>
+      Specifies the path to the file containing the SSL server
+      certificate revocation list (CRL). The default is empty,
+      meaning no <acronym>CRL</acronym> file is loaded.
+     </para>
+
+     <para>
+      This parameter can only be set at server start.
+     </para>
+    </listitem>
+   </varlistentry>
+
    <varlistentry id="guc-ssl-ciphers" xreflabel="ssl_ciphers">
     <term><varname>ssl_ciphers</varname> (<type>string</type>)
      <indexterm>
index 1c1736e54b71bf905a48afc7f71ed86f0fc3e577..30114da19a278c3add59186b3a1686ca18fecb58 100644 (file)
@@ -1069,6 +1069,16 @@ static struct config_string ConfigureNamesString[] =
                NULL, NULL, NULL, NULL
        },
 
+       {
+               {"ssl_crl_file", CFGCXT_INIT, SSL_CONFIG,
+                       "Path to the SSL certificate revocation list file",
+                       CONFIG_VAR_TYPE_STRING, false, 0
+               },
+               &g_pool_config.ssl_crl_file,
+               "",
+               NULL, NULL, NULL, NULL
+       },
+
        {
                {"ssl_ciphers", CFGCXT_INIT, SSL_CONFIG,
                        "Allowed SSL ciphers.",
index ec1bbf7db2111b8fea5ec1b4b839f2a534990108..a14ead1c4cb342cd14f0036ccc00c78be18bfd3e 100644 (file)
@@ -362,6 +362,7 @@ typedef struct
        char       *ssl_ca_cert;        /* path to root (CA) certificate */
        char       *ssl_ca_cert_dir;    /* path to directory containing CA
                                                                         * certificates */
+       char       *ssl_crl_file;       /* path to the SSL certificate revocation list file */
        char       *ssl_ciphers;        /* allowed ssl ciphers */
        bool            ssl_prefer_server_ciphers; /*Use SSL cipher preferences, rather than the client's*/
        char       *ssl_ecdh_curve; /* the curve to use in ECDH key exchange */
index 44060d8a105f3d7c82c4d2d48c6a0378a58b3618..6158ed89eec61630bfed47faed003b01a901a8c5 100644 (file)
@@ -128,6 +128,9 @@ ssl = off
 #ssl_ca_cert_dir = ''
                                    # Directory containing CA root certificate(s)
                                    # (change requires restart)
+#ssl_crl_file = ''
+                                   # Path to the SSL certificate revocation list file
+                                   # (change requires restart)
 
 ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
                                    # Allowed SSL ciphers
index 3c7845d0f0fa4df7dd2c5358216c8611e2ca7d14..de25b5697e6dd07ff197209a01970940cf98040d 100644 (file)
@@ -129,6 +129,9 @@ ssl = off
 #ssl_ca_cert_dir = ''
                                    # Directory containing CA root certificate(s)
                                    # (change requires restart)
+#ssl_crl_file = ''
+                                   # Path to the SSL certificate revocation list file
+                                   # (change requires restart)
 
 ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
                                    # Allowed SSL ciphers
index ce5e4daf632db5df2d792794f624ae8736710f3e..b17912918cd63a5184bc67d6259c522cfc466401 100644 (file)
@@ -124,6 +124,9 @@ ssl = off
 #ssl_ca_cert_dir = ''
                                    # Directory containing CA root certificate(s)
                                    # (change requires restart)
+#ssl_crl_file = ''
+                                   # Path to the SSL certificate revocation list file
+                                   # (change requires restart)
 
 ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
                                    # Allowed SSL ciphers
index f34b40fbbaaba6370e71ff0195df2bbf23704afd..ef840938fd33a611e7b9fa0864317b5c8c7ac766 100644 (file)
@@ -125,6 +125,9 @@ ssl = off
 #ssl_ca_cert_dir = ''
                                    # Directory containing CA root certificate(s)
                                    # (change requires restart)
+#ssl_crl_file = ''
+                                   # Path to the SSL certificate revocation list file
+                                   # (change requires restart)
 
 ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
                                    # Allowed SSL ciphers
index 847424020a304d99061eb71a44b617a1ff8ade2f..2cc7bda592607bcbf25f5b17640c946ea64ffdde 100644 (file)
@@ -129,6 +129,9 @@ ssl = off
 #ssl_ca_cert_dir = ''
                                    # Directory containing CA root certificate(s)
                                    # (change requires restart)
+#ssl_crl_file = ''
+                                   # Path to the SSL certificate revocation list file
+                                   # (change requires restart)
 
 ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
                                    # Allowed SSL ciphers
index e3634323e2f08366be5a45806745f7bb247e6d74..673d6980a57adecf264cbf683ba94544d81c4949 100755 (executable)
@@ -1,10 +1,72 @@
 #!/usr/bin/env bash
 
+[ -e "index.txt" ] && rm "index.txt"
+touch index.txt
+echo '1000' > serial
+echo 'unique_subject = yes/no' > index.txt.attr
+echo '1000' >  crlnumber
+if [ -d "certrecord" ]; then rm -Rf certrecord; fi
+mkdir certrecord
+if [ -d "newcerts" ]; then rm -Rf newcerts; fi
+mkdir newcerts
+
+cat > crl_openssl.conf <<EOF
+
+[ ca ]
+default_ca = CA_default
+
+[ CA_default ]
+dir               = .
+database          = index.txt
+serial            = serial
+certs             = newcerts
+new_certs_dir     = certrecord
+
+default_md        = sha256
+crlnumber         = crlnumber
+default_crl_days  = 365
+
+name_opt          = ca_default
+cert_opt          = ca_default
+default_days      = 375
+preserve          = no
+policy            = policy_loose
+
+# The root key and root certificate.
+private_key       = root.key
+certificate       = root.crt
+
+[ policy_loose ]
+# Allow the intermediate CA to sign a more diverse range of certificates.
+# See the POLICY FORMAT section of the `ca` man page.
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+[req]
+distinguished_name  = req_distinguished_name
+
+[req_distinguished_name]
+
+EOF
+
 # Create root cert
-openssl req -new -x509 -nodes -out root.crt -keyout root.key -days 365 -subj /CN=MyRootCA
+openssl req -new -x509 -nodes -out root.crt -keyout root.key -config crl_openssl.conf -days 365 -subj /CN=MyRootCA
 # PostgreSQL/Pgpool cert
-openssl req -new -out server.req -keyout server.key -nodes -subj "/CN=postgresql"
-openssl x509 -req -in server.req -CAkey root.key -CA root.crt -days 365 -CAcreateserial -out server.crt
+openssl req -new -out server.req -keyout server.key -config crl_openssl.conf -nodes -subj "/CN=postgresql"
+openssl ca -batch -in server.req -config crl_openssl.conf -days 375 -notext -md sha256 -out server.crt
+
 # Frontend Cert
-openssl req -new -out postgresql.req -keyout frontend.key -nodes -subj "/CN=$USER"
-openssl x509 -req -in postgresql.req -CAkey root.key -CA root.crt -days 365 -CAcreateserial -out frontend.crt
+openssl req -new -out frontend.req -keyout frontend.key -config crl_openssl.conf -nodes -subj "/CN=$USER"
+openssl ca -batch -in frontend.req -config crl_openssl.conf -days 375 -notext -md sha256 -out frontend.crt
+
+# Generate clean CRL (No revocation so far)
+openssl ca -gencrl -config crl_openssl.conf -out server.crl -cert root.crt -keyfile root.key
+# Revoke Frontend Cert
+openssl ca -revoke frontend.crt -config crl_openssl.conf -keyfile root.key -cert root.crt -out root.crl
+# Generate CRL after revocation
+openssl ca -gencrl -config crl_openssl.conf -out server_revoked.crl -cert root.crt -keyfile root.key
index 6fc59b656af0ca5edb1bed5090a93a3b191d6afe..1ff6ab435f77c88ccc585fc463a657ec20df7c4a 100755 (executable)
@@ -14,6 +14,7 @@ export PGDATABASE=test
 dir=`pwd`
 SSL_KEY=$dir/server.key
 SSL_CRT=$dir/server.crt
+SSL_CRL=$dir/server.crl
 ROOT_CRT=$dir/root.crt
 FRONTEND_KEY=$dir/frontend.key
 FRONTEND_CRT=$dir/frontend.crt
@@ -52,6 +53,7 @@ wait_for_pgpool_startup
 
 export PGSSLCERT=$FRONTEND_CRT
 export PGSSLKEY=$FRONTEND_KEY
+export PGSSLROOTCERT=$ROOT_CRT
 
 $PSQL -h localhost -c "select 1" test
 
@@ -65,4 +67,80 @@ fi
 echo "Checking cert auth between Pgpool-II and frontend was ok."
 
 ./shutdownall
+
+
+# Starting CRL verfication
+# Adding valid CRL file in pgpool.conf file.
+echo "ssl_crl_file = '$SSL_CRL'" >> etc/pgpool.conf
+
+# Check pgpool configuration is updated successfully
+grep "server.crl" etc/pgpool.conf
+if [ $? != 0 ];then
+    echo "pgpool.conf is not updated with CRL file."
+    ./shutdownall
+    exit 1
+fi
+
+# Start Server and PgPool
+./startall
+
+export PGPORT=$PGPOOL_PORT
+
+wait_for_pgpool_startup
+
+export PGSSLCERT=$FRONTEND_CRT
+export PGSSLKEY=$FRONTEND_KEY
+export PGSSLROOTCERT=$ROOT_CRT
+
+$PSQL -h localhost -c "select 1" test
+
+grep "SSL certificate authentication for user" log/pgpool.log|grep successful
+if [ $? != 0 ];then
+    echo "Checking cert auth between Pgpool-II and frontend with clean CRL failed."
+    ./shutdownall
+    exit 1
+fi
+
+echo "Checking cert auth between Pgpool-II and frontend with clean CRL was ok."
+
+./shutdownall
+
+
+# Adding CRL file with revoked certification entry in pgpool.conf file.
+echo "Updating pgpool.conf with revoked CRL file"
+
+sed -i 's/server.crl/server_revoked.crl/' etc/pgpool.conf
+
+# Check pgpool configuration is updated successfully
+grep "server_revoked.crl" etc/pgpool.conf
+if [ $? != 0 ];then
+    echo "pgpool.conf is not updated with revoked CRL file."
+    ./shutdownall
+    exit 1
+fi
+
+# Start Server and PgPool
+./startall
+
+export PGPORT=$PGPOOL_PORT
+
+wait_for_pgpool_startup
+
+export PGSSLCERT=$FRONTEND_CRT
+export PGSSLKEY=$FRONTEND_KEY
+export PGSSLROOTCERT=$ROOT_CRT
+
+$PSQL -h localhost -c "select 1" test
+
+grep "certificate verify failed" log/pgpool.log
+if [ $? != 0 ];then
+    echo "Checking cert auth between Pgpool-II and frontend with revoked entry in CRL failed."
+    ./shutdownall
+    exit 1
+fi
+
+echo "Checking cert auth between Pgpool-II and frontend with revoked entry in CRL was ok."
+
+./shutdownall
+
 exit 0
index 25728b0ed66e0b756c08e5a60a8c61f65ed3e14d..126de0e6cfaedcda399cf2f4acc14361514ff6af 100644 (file)
@@ -259,6 +259,11 @@ get_config(int *nrows)
        StrNCpy(status[i].desc, "directory containing CA root certificate(s)", POOLCONFIG_MAXDESCLEN);
        i++;
 
+       StrNCpy(status[i].name, "ssl_crl_file", POOLCONFIG_MAXNAMELEN);
+       snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_crl_file);
+       StrNCpy(status[i].desc, "path to the SSL certificate revocation list file", POOLCONFIG_MAXDESCLEN);
+       i++;
+
        StrNCpy(status[i].name, "ssl_ciphers", POOLCONFIG_MAXNAMELEN);
        snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ciphers);
        StrNCpy(status[i].desc, "allowed SSL ciphers", POOLCONFIG_MAXDESCLEN);
index 346477e34fdf58cda95c94cd1144bbdfb9931f4b..59f4dcf9a4fc93434d9bf570835904c92c142e47 100644 (file)
@@ -5,7 +5,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2016     PgPool Global Development Group
+ * Copyright (c) 2003-2020     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -675,7 +675,47 @@ SSL_ServerSide_init(void)
                                                        pool_config->ssl_ca_cert, SSLerrmessage(ERR_get_error()))));
                        goto error;
                }
+       }
+
+       /*----------
+        * Load the Certificate Revocation List (CRL).
+        * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html
+        *----------
+        */
+       if (pool_config->ssl_crl_file && strlen(pool_config->ssl_crl_file))
+       {
+               X509_STORE *cvstore = SSL_CTX_get_cert_store(context);
+
+               if (cvstore)
+               {
+                       /* Set the flags to check against the complete CRL chain */
+                       if (X509_STORE_load_locations(cvstore, pool_config->ssl_crl_file, NULL) == 1)
+                       {
+                               /* OpenSSL 0.9.6 does not support X509_V_FLAG_CRL_CHECK */
+#ifdef X509_V_FLAG_CRL_CHECK
+                               X509_STORE_set_flags(cvstore,
+                                                                        X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
+#else
+                               ereport(LOG,
+                                               (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                                errmsg("SSL certificate revocation list file \"%s\" ignored",
+                                                               pool_config->ssl_crl_file),
+                                                errdetail("SSL library does not support certificate revocation lists.")));
+#endif
+                       }
+                       else
+                       {
+                               ereport(WARNING,
+                                               (errcode(ERRCODE_CONFIG_FILE_ERROR),
+                                                errmsg("could not load SSL certificate revocation list file \"%s\": %s",
+                                                               pool_config->ssl_crl_file, SSLerrmessage(ERR_get_error()))));
+                               goto error;
+                       }
+               }
+       }
 
+       if (pool_config->ssl_ca_cert && strlen(pool_config->ssl_ca_cert))
+       {
                /*
                 * Always ask for SSL client cert, but don't fail if it's not
                 * presented.  We might fail such connections later, depending on what