Eu tenho um banco de dados PostgreSQL 9.6.11 no Amazon Linux que foi configurado com um certificado de servidor curinga SSL de 2048 bits e conexões remotas baseadas em senha (sem certificados de cliente) desde janeiro de 2012. Após uma atualização de certificado recente (Comodo, agora Sectigo) , não consigo mais estabelecer conexões remotas psql ou JDBC com esse banco de dados por SSL.
Meu objetivo é poder me conectar a esse banco de dados PostgreSQL remotamente via psql e também via JDBC.
A partir da chave do servidor (que não mudou desde que tive acesso remoto funcionando), tentei cobrir toda a série de etapas para verificar se minhas chaves, certificados, firewall e banco de dados estão configurados corretamente.
Devo ter perdido alguma coisa, pois não consigo me conectar remotamente via psql ou JDBC.
O que eu perdi que poderia estar causando a falha dessas conexões remotas?
Etapas de solução de problemas
Como usuário postgres :
# cd /var/lib/pgsql96/data
postgresql.conf
Eu tentei limitar o conjunto de cifras para tentar forçar o TLSv1.2 para todas as conexões SSL. Como não houve diferença no comportamento do cliente, comentei ssl_ciphers e ssl_prefer_server_ciphers para permitir os padrões.
ssl = on
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL:!SSLv2:!SSLv3:!TLSv1:!TLSv1.1'
#ssl_prefer_server_ciphers = on
ssl_cert_file = 'server.crt' # wildcard cert plus intermediate certs
ssl_key_file = 'server.key' # private key
#ssl_ca_file = 'root.crt' # commented out - do not require client certs
#ssl_crl_file = 'root.crl' # commented out - no client certificates
pg_hba.conf
Este arquivo foi configurado para permitir apenas o endereço IP público do host local e do host remoto que estou testando. Não quero exigir certificados de cliente, apenas criptografia com uma senha obrigatória.
hostssl all all 11.222.11.222/32 password # localhost
hostssl all all 34.84.31.82/32 password # remote host
Verifiquei os caminhos de certificação via ssltest e descobri que existem dois caminhos disponíveis ( Path #1 e Path #2 ):
Da documentação sobre conexões TCP/IP seguras do PostgreSQL 9.6 com SSL :
O primeiro certificado em server.crt deve ser o certificado do servidor porque deve corresponder à chave privada do servidor. Os certificados de autoridades de certificação "intermediárias" também podem ser anexados ao arquivo. Isso evita a necessidade de armazenar certificados intermediários nos clientes, supondo que os certificados raiz e intermediários foram criados com extensões v3_ca. Isso permite a expiração mais fácil de certificados intermediários.
Não é necessário adicionar o certificado raiz ao server.crt. Em vez disso, os clientes devem ter o certificado raiz da cadeia de certificados do servidor.
Montando e verificando a cadeia de certificados para o caminho nº 1
# ls -l
-rw------- 1 postgres postgres 2313 Aug 15 00:26 1_wildcard_server.crt
-rw------- 1 postgres postgres 2167 Aug 15 00:27 2_intermediate_sectigo.crt
-rw------- 1 postgres postgres 2094 Aug 15 00:27 3_root_usertrust-selfsigned.crt
Verifiquei as impressões digitais de cada certificado individual no Caminho #1 para confirmar sua identidade:
# openssl x509 -in 1_wildcard_server.crt -noout -sha256 -fingerprint
SHA256 Fingerprint=8C:69:06:8E:81:31:30:6E:DA:DD:C2:1C:38:83:73:67:97:3D:DB:37:78:B8:49:D7:7E:32:A8:3F:1F:8B:08:AB
# openssl x509 -in 2_intermediate_sectigo.crt -noout -sha256 -fingerprint
SHA256 Fingerprint=7F:A4:FF:68:EC:04:A9:9D:75:28:D5:08:5F:94:90:7F:4D:1D:D1:C5:38:1B:AC:DC:83:2E:D5:C9:60:21:46:76
# openssl x509 -in 3_root_usertrust-selfsigned.crt -noout -sha256 -fingerprint
SHA256 Fingerprint=E7:93:C9:B0:2F:D8:AA:13:E2:1C:31:22:8A:CC:B0:81:19:64:3B:74:9C:89:89:64:B1:74:6D:46:C3:D4:CB:D2
E também examinou as versões de texto dos certificados para confirmar se os certificados intermediário e raiz possuem a extensão v3_ca (o certificado do servidor curinga não possui essa extensão):
# openssl x509 -in 1_wildcard_server.crt -text
...
X509v3 Basic Constraints: critical
CA:FALSE
...
# openssl x509 -in 2_intermediate_sectigo.crt -text
...
X509v3 Basic Constraints: critical
CA:TRUE
...
# openssl x509 -in 3_root_usertrust-selfsigned.crt -text
...
X509v3 Basic Constraints: critical
CA:TRUE
...
Verifique a cadeia de certificados para o Caminho #1 com OpenSSL:
# openssl verify -verbose -CAfile 3_root_usertrust-selfsigned.crt -untrusted 2_intermediate_sectigo.crt 1_wildcard_server.crt
1_wildcard_server.crt: OK
Crie o servidor empacotado e o certificado intermediário para o Caminho #1:
# cat 1_wildcard_server.crt > server.crt
# cat 2_intermediate_sectigo.crt >> server.crt
Crie os certificados intermediários e raiz agrupados (aqueles com a extensão v3_ca) para o Caminho #1 (embora isso só seja necessário ao exigir certificados de cliente):
# cat 2_intermediate_sectigo.crt > root.crt
# cat 3_root_usertrust-selfsigned.crt >> root.crt
Montando e verificando a cadeia de certificados para o caminho nº 2
# ls -l
-rw------- 1 postgres postgres 2313 Aug 15 00:26 1_wildcard_server.crt
-rw------- 1 postgres postgres 2167 Aug 15 00:27 2_intermediate_sectigo.crt
-rw------- 1 postgres postgres 1956 Aug 15 00:35 3_intermediate_usertrust.crt
-rw------- 1 postgres postgres 1521 Aug 15 00:27 4_root_addtrustroot-selfsigned.crt
Verifiquei as impressões digitais de cada certificado individual no Caminho #2 para confirmar sua identidade:
# openssl x509 -in 1_wildcard_server.crt -noout -sha256 -fingerprint
SHA256 Fingerprint=8C:69:06:8E:81:31:30:6E:DA:DD:C2:1C:38:83:73:67:97:3D:DB:37:78:B8:49:D7:7E:32:A8:3F:1F:8B:08:AB
# openssl x509 -in 2_intermediate_sectigo.crt -noout -sha256 -fingerprint
SHA256 Fingerprint=7F:A4:FF:68:EC:04:A9:9D:75:28:D5:08:5F:94:90:7F:4D:1D:D1:C5:38:1B:AC:DC:83:2E:D5:C9:60:21:46:76
# openssl x509 -in 3_intermediate_usertrust.crt -noout -sha256 -fingerprint
SHA256 Fingerprint=1A:51:74:98:0A:29:4A:52:8A:11:07:26:D5:85:56:50:26:6C:48:D9:88:3B:EA:69:2B:67:B6:D7:26:DA:98:C5
# openssl x509 -in 4_root_addtrustroot-selfsigned.crt -noout -sha256 -fingerprint
SHA256 Fingerprint=68:7F:A4:51:38:22:78:FF:F0:C8:B1:1F:8D:43:D5:76:67:1C:6E:B2:BC:EA:B4:13:FB:83:D9:65:D0:6D:2F:F2
E também examinou as versões de texto dos certificados para confirmar se os certificados intermediário e raiz possuem a extensão v3_ca (o certificado do servidor curinga não possui essa extensão):
# openssl x509 -in 1_wildcard_server.crt -text
...
X509v3 Basic Constraints: critical
CA:FALSE
...
# openssl x509 -in 2_intermediate_sectigo.crt -text
...
X509v3 Basic Constraints: critical
CA:TRUE
...
# openssl x509 -in 3_intermediate_usertrust.crt -text
...
X509v3 Basic Constraints: critical
CA:TRUE
...
# openssl x509 -in 4_root_addtrustroot-selfsigned.crt -text
...
X509v3 Basic Constraints: critical
CA:TRUE
...
Verifique a cadeia de certificados para o caminho 2 com OpenSSL ( deste artigo ):
# openssl verify -verbose -CAfile 4_root_addtrustroot-selfsigned.crt -untrusted 3_intermediate_usertrust.crt 2_intermediate_sectigo.crt
2_intermediate_sectigo.crt: OK
Crie o servidor empacotado e o certificado intermediário para o Caminho #2:
# cat 1_wildcard_server.crt > server.crt
# cat 2_intermediate_sectigo.crt >> server.crt
# cat 3_intermediate_usertrust.crt >> server.crt
Crie os certificados intermediários e raiz agrupados (aqueles com a extensão v3_ca) para o caminho 2 (embora isso só seja necessário ao exigir certificados de cliente):
# cat 2_intermediate_sectigo.crt > root.crt
# cat 3_intermediate_usertrust.crt >> root.crt
# cat 4_root_addtrustroot-selfsigned.crt >> root.crt
Permissões de chave e certificado verificadas (como nesta pergunta ).
# ls -l *.key *.crt *.crl-bash-4.2$ ls -l *.key *.crt *.crl
-rw-r----- 1 postgres postgres 963 Aug 14 21:12 root.crl
-rw-r--r-- 1 postgres postgres 1521 Aug 15 01:27 root.crt
-rw-r--r-- 1 postgres postgres 6436 Aug 15 01:27 server.crt
-rw------- 1 postgres postgres 1679 May 28 19:33 server.key
Confirmado que a chave do servidor está correta, seguindo as instruções do Comodo .
# openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
# openssl rsa -check -noout -in server.key
RSA key ok
Confirmado que o certificado e os módulos de chave privada são idênticos.
# openssl rsa -modulus -noout -in server.key
Modulus=[REDACTED]
# openssl x509 -modulus -noout -in server.crt
Modulus=[REDACTED]
Testou a CRL e verificou o emissor:
# openssl crl -in root.crl -text
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
Last Update: May 28 00:12:38 2019 GMT
Next Update: Jun 1 00:12:38 2019 GMT
CRL extensions:
X509v3 Authority Key Identifier:
keyid:AD:BD:98:7A:34:B4:26:F7:FA:C4:26:54:EF:03:BD:E0:24:CB:54:1A
X509v3 CRL Number:
5275
Revoked Certificates:
Serial Number: 537B76564F297F14DC6943E922AD2C79
Revocation Date: Dec 14 15:58:30 2015 GMT
Serial Number: 46EAF096054CC5E3FA65EA6E9F42C664
Revocation Date: Dec 14 15:58:30 2015 GMT
Serial Number: 3ACDAB9C759886BCAF74E5DF81A9F4E8
Revocation Date: Dec 14 15:58:30 2015 GMT
Serial Number: 79174AA9141736FE15A7CA9F2CFF4588
Revocation Date: Apr 30 20:03:54 2018 GMT
Serial Number: 74C18753F7EEB4EA238D8416B5AC7646
Revocation Date: Oct 9 09:11:57 2018 GMT
Signature Algorithm: sha1WithRSAEncryption
38:3a:7d:3e:ee:be:48:e7:93:c3:91:0a:c3:47:46:11:87:83:
[TRIMMED]
5f:16:1a:38
-----BEGIN X509 CRL-----
MIICnTCCAYUCAQEwDQYJKoZIhvcNAQEFBQAwbzELMAkGA1UEBhMCU0UxFDASBgNV
[TRIMMED]
iEx7Li7fLtVPxbIU4aqaKU+15QEE37eJWRccBnuhqJqEDM+ML+k67Hj1yeLaXxYa
OA==
-----END X509 CRL-----
Serviço PostgreSQL iniciado.
# service postgresql96 start
Starting postgresql96 service: [ OK ]
Verificado que não houve erros nos arquivos de log.
# cat ../pgstartup.log
LOG: redirecting log output to logging collector process
HINT: Future log output will appear in directory "pg_log".
# cat pg_log/postgresql-Wed.log
LOG: database system was shut down at 2019-08-14 15:01:03 UTC
LOG: MultiXact member wraparound protections are now enabled
LOG: database system is ready to accept connections
LOG: autovacuum launcher started
Conectado com sucesso ao banco de dados via SSL do host local com sslmode require e com check -full (usando FQDN).
# psql "postgresql://mydbuser@localhost:5432/mydb?ssl=true&sslmode=require"
psql (9.6.11)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
mydb=> \q
# psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=verify-full"
Password: ********
psql (9.6.11)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
mydb=> \q
Recuperou e verificou visualmente a cadeia de certificados SSL remotamente via Java usando uma combinação deste método , este método , este método e este método . Isso confirma que a porta 5432 está aberta para este host no firewall e que o certificado e a cadeia podem ser recuperados via JDBC.
Supported Protocols: 5
SSLv2Hello
SSLv3
TLSv1
TLSv1.1
TLSv1.2
Enabled Protocols: 3
TLSv1
TLSv1.1
TLSv1.2
Enabled Cipher suites: 43
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
TLS_EMPTY_RENEGOTIATION_INFO_SCSV
Cert 1 (active):
Thumbprint SHA1 : B5:2D:43:A8:0F:C6:C3:39:1F:2D:BB:9C:30:A5:4B:8D:DF:5F:9B:F8
Fingerprint SHA256: 8c69068e8131306edaddc21c38837367973ddb3778b849d77e32a83f1f8b08ab
Subject: CN=*.[REDACTED].org,OU=PositiveSSL Wildcard,OU=Domain Control Validated
Issuer: CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB
Cert 2 (active):
Thumbprint SHA1 : 33:E4:E8:08:07:20:4C:2B:61:82:A3:A1:4B:59:1A:CD:25:B5:F0:DB
Fingerprint SHA256: 7fa4ff68ec04a99d7528d5085f94907f4d1dd1c5381bacdc832ed5c960214676
Subject: CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB
Issuer: CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US
Cert 3 (active):
Thumbprint SHA1 : 33:E4:E8:08:07:20:4C:2B:61:82:A3:A1:4B:59:1A:CD:25:B5:F0:DB
Fingerprint SHA256: 7fa4ff68ec04a99d7528d5085f94907f4d1dd1c5381bacdc832ed5c960214676
Subject: CN=Sectigo RSA Domain Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB
Issuer: CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US
Cert 4 (active):
Thumbprint SHA1 : EA:B0:40:68:9A:0D:80:5B:5D:6F:D6:54:FC:16:8C:FF:00:B7:8B:E3
Fingerprint SHA256: 1a5174980a294a528a110726d5855650266c48d9883bea692b67b6d726da98c5
Subject: CN=USERTrust RSA Certification Authority,O=The USERTRUST Network,L=Jersey City,ST=New Jersey,C=US
Issuer: CN=AddTrust External CA Root,OU=AddTrust External TTP Network,O=AddTrust AB,C=SE
I confirmed that the above root certificates (AddTrust External CA Root) are both in the default Java keystore as recommended here (and also confirmed that they are in the Windows keystore by default as well):
C:\Windows\System32>"C:\Program Files\Java\jdk1.8.0_212\jre\bin\keytool.exe" -keystore "C:\Program Files\Java\jdk1.8.0_212\jre\lib\security\cacerts" -storepass
changeit -list
Keystore type: jks
Keystore provider: SUN
Your keystore contains 95 entries
....
usertrustrsaca [jdk], Aug 25, 2016, trustedCertEntry,
Certificate fingerprint (SHA1): 2B:8F:1B:57:33:0D:BB:A2:D0:7A:6C:51:F7:0E:E9:0D:DA:B9:AD:8E
....
addtrustexternalca [jdk], Aug 25, 2016, trustedCertEntry,
Certificate fingerprint (SHA1): 02:FA:F3:E2:91:43:54:68:60:78:57:69:4D:F5:E4:5B:68:85:18:68
....
Attempted to connect to PostgreSQL via openssl from remote host (as in this question).
# openssl version
OpenSSL 1.1.0h 27 Mar 2018
# openssl s_client -connect [REDACTED].org:5432 -state -msg -showcerts -debug
CONNECTED(00000003)
SSL_connect:before/connect initialization
write to 0x2070760 [0x20fe520] (289 bytes => 289 (0x121))
0000 - 16 03 01 01 1c 01 00 01-18 03 03 0c 53 44 0c a3 ............SD..
[TRIMMED]
0110 - 03 01 03 02 03 03 02 01-02 02 02 03 00 0f 00 01 ................
0120 - 01 .
>>> TLS 1.2 [length 0005]
16 03 01 01 1c
>>> TLS 1.2 Handshake [length 011c], ClientHello
01 00 01 18 03 03 0c 53 44 0c a3 e2 21 36 f2 b0
[TRIMMED]
01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03
03 02 01 02 02 02 03 00 0f 00 01 01
SSL_connect:SSLv2/v3 write client hello A
read from 0x2070760 [0x2103a80] (7 bytes => 0 (0x0))
139650021263184:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 289 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1565797370
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
# tail pg_log/postgresql-Wed.log
LOG: invalid length of startup packet
Attempted to connect remotely via Windows psql client (9.6.5).
C:\Program Files\PostgreSQL\9.6\bin>psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=require"
psql: SSL error: certificate verify failed
For some reason, the psql client is sending an TLSv1 alert, "unknown ca":
# tail pg_log/postgresql-Wed.log
LOG: could not accept SSL connection: tlsv1 [alert][15] unknown ca
Additionally, if I specify the root certificate:
C:\Program Files\PostgreSQL\9.6\bin>psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=require&sslrootcert=root.crt"
psql: SSL error: certificate verify failed
or if I leave that parameter blank:
C:\Program Files\PostgreSQL\9.6\bin>psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=require&sslrootcert="
psql: SSL error: certificate verify failed
However, if I specify a non-existent file for that parameter, I am able to connect successfully (with sslmode=require):
C:\Program Files\PostgreSQL\9.6\bin>psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=require&sslrootcert=x"
Password:
psql (9.6.5, server 9.6.11)
WARNING: Console code page (437) differs from Windows code page (1252)
8-bit characters might not work correctly. See psql reference
page "Notes for Windows users" for details.
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
n4l_live=> \q
From the specification:
unknown_ca
A valid certificate chain or partial chain was received, but the certificate was not accepted because the CA certificate could not be located or couldn't be matched with a known, trusted CA. This message is always fatal.
Attempt to connect via Java client with postgresql-42.2.5.jar.
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1946)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:316)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:310)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1639)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:223)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1037)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:965)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1064)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1367)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1395)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1379)
at org.postgresql.ssl.MakeSSL.convert(MakeSSL.java:40)
... 36 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302)
at sun.security.validator.Validator.validate(Validator.java:262)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:330)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:237)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:132)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1621)
... 44 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392)
... 50 more
For some reason, the Java client is producing an SSLv3 alert, "certificate unknown", even though it is not one of the enabled protocols:
# tail pg_log/postgresql-Wed.log
LOG: could not accept SSL connection: sslv3 alert certificate unknown
From the specification:
certificate_unknown
Some other (unspecified) issue arose in processing the certificate, rendering it unacceptable.
The PostgreSQL JDBC driver documentation indicates that the Java client (by default) will attempt to use verify-full
for the server certificate, which may be the reason a different error is produced here than with the psql client:
The simplest being ssl=true, passing this into the driver will cause the driver to validate both the SSL certificate and verify the hostname (same as
verify-full
). Note this is different than libpq which defaults to a non-validating SSL connection.
The above failures (and the success when specifying a non-existent root certificate with sslmode=require
) seem to point to some problem with verifying the CA for the certificate.
Note: I used the script provided in this answer to generate new certificates and performed the above tests again, with identical results.
The intermediate certificate must be in
server.crt
i am not sure if you need to add it toroot.crt
. Please refer to PostgreSQL DocumentationEdit:
I just created a script to generate all you need to setup SSL with full verification. Can you please run it and confirm if it works ?
Make sure to restart the server and copy
root.crt
to the client thatpsql
can verify server identity. For testing purpose/etc/hosts
file on the client must be modified to make CN valid from client perspective.On Windows, the default
root.crt
androot.crl
are stored in%APPDATA%\postgresql
(this thread pointed me in the right direction).When I deleted these files, I was able to successfully connect to the remote server via psql without using any ssl parameters (defaults are to auto-negotiate ssl with
sslmode=require
):As expected, when I attempt to force
sslmode=verify-ca
orsslmode=verify-full
, psql fails to connect:And further, when I attempt to connect via JDBC, I get the same error (because JDBC defaults to
sslmode=verify-full
):When I place only the top-level root certificate (or both top-level root certificates for Path #1 or Path #2) in
C:\Users\[USERNAME]\AppData\Roaming\postgresql\root.crt
, I am able to successfully connect with Java (no problems using the wildcard certificate forverify-full
!):Likewise, when I do the same on my Linux psql client:
As a sanity check, if only the certificates for Path #1 are in server.crt, but I attempt to
verify-full
with the root for Path #2:And then I also append the root certificate for Path #1:
My misconceptions in my question were that:
This was reinforced by the fact that if
C:\Users\[USERNAME]\AppData\Roaming\postgresql\root.crt
exists, there are no messages indicating where that file is (it was not even on my radar to look in that folder).In order to add the additional CRLs, I needed to download and convert from DER to PEM:
But then I found that if I copy this
root.crl
(CRL for intermediate certificates) into~/.postgresql
, my client connections fail with the same error that I started with:I was ultimately unable to get CRL working for remote connections, so I deleted
root.crl
on the clients to simplify the configuration. I now have successfulverify-full
connections from both psql and Java. For a detailed write-up on CRLs, see this related question.What I've learned:
C:\Users\[USERNAME]\AppData\Roaming\postgresql\root.crt
, and will accept the root certificate of either Path #1 or Path #2 forverify-full
.C:\Users\[USERNAME]\AppData\Roaming\postgresql\root.crl
(or~/.postgresql/root.crl
on Linux) is OKroot.crl
is present on the client, it must contain all of the correct CRLs for each validation path allowed by the server.root.crl
is provided, but one or more root CA does not have an associated CRL Distribution Point, the connections may fail with acertificate verify failed
message.I found that (in my case) neither of the root CA certificates had a CRL associated with it, which may be triggering an OpenSSL bug:
The equivalent openssl command that confirms this bug is:
E se o bug acima é realmente responsável por esse erro, então a razão pela qual eu consegui usar
root.crl
com meu certificado Comodo anterior é que o certificado CA raiz tinha um ponto de distribuição CRL, então esse bug nunca foi acionado. A curto prazo, minha solução é simplesmente excluirroot.crl
, o que resulta em uma conexão funcional.