У меня есть база данных PostgreSQL 9.6.11 в Amazon Linux, в которой с января 2012 года настроен 2048-битный SSL-сертификат сервера с подстановочными знаками и удаленные соединения на основе пароля (без клиентских сертификатов). После недавнего обновления сертификата ( Comodo, теперь Sectigo),Я больше не могу устанавливать удаленные соединения psql или JDBC с этой базой данных через SSL.
Моя цель - иметь возможность подключаться к этой базе данных PostgreSQL удаленно через psql, а также через JDBC.
Начиная с ключа сервера (который не известен "не изменилось, так как у меня работал удаленный доступ), я попытался выполнить полную серию шагов, чтобы убедиться, что мои ключи, сертификаты, брандмауэр и база данных настроены правильно.
Я, должно быть, что-то пропустил, так как я ' m не может подключиться удаленно через psql или JDBC.
Что я пропустил, что могло вызвать сбой этих удаленных подключений?
Действия по устранению неполадок
Как пользователь postgres :
# cd /var/lib/pgsql96/data
postgresql. conf
Я попытался ограничить набор шифров, чтобы попытаться принудительно использовать TLSv1.2 для всех соединений SSL. Поскольку разницы в поведении клиентов не было, я закомментировал ssl_ciphers и ssl_prefer_server_ciphers, чтобы разрешить значения по умолчанию.
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
Этот файл был настроен так, чтобы разрешать только общедоступный IP-адрес локального хоста и удаленного хоста, которым я являюсь тестирование. Я не хочу требовать сертификаты клиентов, только шифрование с требуемым паролем.
hostssl all all 11.222.11.222/32 password # localhost
hostssl all all 34.84.31.82/32 password # remote host
Я проверил пути сертификации через ssltest и обнаружил, что есть два доступных пути ( Путь № 1 ] и Путь # 2 ):
Из документации по PostgreSQL 9.6. Безопасные соединения TCP / IP с SSL :
Первый сертификат в server.crt должен быть сервером свидетельство потому что он должен соответствовать закрытому ключу сервера. Сертификаты "промежуточные" центры сертификации также могут быть добавлены к файл. Это позволяет избежать необходимости хранить промежуточные сертификаты на клиентах, предполагая корневой и промежуточный сертификаты были созданы с расширениями v3_ca. Это позволяет легче истечение срока действия промежуточных сертификатов.
Нет необходимости добавлять корневой сертификат в server.crt. Вместо этого у клиентов должен быть корневой сертификат сервера цепочка сертификатов.
Сборка и проверка цепочки сертификатов для Пути №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
Я проверил отпечатки пальцев каждого отдельного сертификата на Пути №1, чтобы подтвердить их идентичность:
# 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
А также изучил текстовые версии сертификатов для подтверждения что промежуточный и корневой сертификаты имеют расширение v3_ca (сертификат сервера с подстановочными знаками не имеет этого расширения):
# 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
...
Проверьте цепочку сертификатов для Пути №1 с помощью OpenSSL:
# openssl verify -verbose -CAfile 3_root_usertrust-selfsigned.crt -untrusted 2_intermediate_sectigo.crt 1_wildcard_server.crt
1_wildcard_server.crt: OK
Создайте связанный сервер и промежуточный сертификат для Пути №1 :
# cat 1_wildcard_server.crt > server.crt
# cat 2_intermediate_sectigo.crt >> server.crt
Создайте связанные промежуточные и корневой сертификаты (с расширением v3_ca) для Пути №1 (хотя это потребуется только при запросе клиентских сертификатов):
# cat 2_intermediate_sectigo.crt > root.crt
# cat 3_root_usertrust-selfsigned.crt >> root.crt
Сборка и проверка цепочки сертификатов для Пути №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
Я проверил отпечатки пальцев каждого отдельного сертификата в Пути № 2, чтобы подтвердить их идентичность:
# 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
А также изучил текстовые версии сертификатов, чтобы подтвердить, что промежуточный и корневой сертификаты имеют версию 3. _ca расширение (сертификат сервера с подстановочными знаками не имеет этого расширения):
# 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
...
Проверьте цепочку сертификатов для Пути № 2 с помощью OpenSSL (из этой статьи ):
# openssl verify -verbose -CAfile 4_root_addtrustroot-selfsigned.crt -untrusted 3_intermediate_usertrust.crt 2_intermediate_sectigo.crt
2_intermediate_sectigo.crt: OK
Создайте связанный сервер и промежуточный сертификат для Путь №2:
# cat 1_wildcard_server.crt > server.crt
# cat 2_intermediate_sectigo.crt >> server.crt
# cat 3_intermediate_usertrust.crt >> server.crt
Создайте связанные промежуточный и корневой сертификаты (с расширением v3_ca) для Пути №2 (хотя это потребуется только при запросе клиентских сертификатов):
# cat 2_intermediate_sectigo.crt > root.crt
# cat 3_intermediate_usertrust.crt >> root.crt
# cat 4_root_addtrustroot-selfsigned.crt >> root.crt
Подтвержденный ключ и разрешения сертификата (как в этот вопрос ).
# 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
Подтверждено, что ключ сервера в порядке, следуя инструкциям от Comodo .
# openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
# openssl rsa -check -noout -in server.key
RSA key ok
Подтверждено, что модули сертификата и закрытого ключа идентичны.
# openssl rsa -modulus -noout -in server.key
Modulus=[REDACTED]
# openssl x509 -modulus -noout -in server.crt
Modulus=[REDACTED]
Протестировано Список отзыва сертификатов и подтвержден издатель:
# 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-----
Запущена служба PostgreSQL.
# service postgresql96 start
Starting postgresql96 service: [ OK ]
Проверено, что в файлах журнала нет ошибок.
# 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
Успешно подключено к базе данных через SSL с localhost с sslmode require и с verify-full (с использованием 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
Получил и визуально проверил цепочку сертификатов SSL удаленно через Java, используя комбинацию этого метода , этого метода , этого метода и этот метод . Это подтверждает, что порт 5432 открыт для этого хоста на брандмауэре и что сертификат и цепочка можно получить через 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
Я подтвердил, что указанные выше корневые сертификаты (AddTrust External CA Root) находятся в хранилище ключей Java по умолчанию как ] рекомендуется здесь (а также подтверждено, что они также находятся в хранилище ключей Windows по умолчанию):
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
....
Попытка подключиться к PostgreSQL через openssl с удаленного хоста (как в этот вопрос ).
# 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
Попытка удаленного подключения через клиент Windows psql (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
По какой-то причине клиент psql отправляет предупреждение TLSv1, «unknown ca»:
# tail pg_log/postgresql-Wed.log
LOG: could not accept SSL connection: tlsv1 [alert][15] unknown ca
Кроме того, если я укажу корневой сертификат:
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
или если я оставлю этот параметр пустым:
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
Однако,если я укажу несуществующий файл для этого параметра, я смогу успешно подключиться (с помощью 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
unknown_ca
Получена действительная цепочка сертификатов или частичная цепочка, но сертификат не был принят, потому что сертификат CA не мог может быть обнаружен или не может быть сопоставлен с известным надежным центром сертификации. Этот сообщение всегда фатально.
Попытка подключиться через Java-клиент с 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
По какой-то причине клиент Java выдает предупреждение SSLv3 , «сертификат неизвестен» , хотя это не один из включенных протоколов:
# tail pg_log/postgresql-Wed.log
LOG: could not accept SSL connection: sslv3 alert certificate unknown
certificate_unknown
При обработке файла возникла другая (неуказанная) проблема. сертификат, что делает его неприемлемым.
В документации драйвера JDBC PostgreSQL указано, что клиент Java (по умолчанию) будет попытаться использовать verify-full
для сертификата сервера, что может быть причиной здесь возникает другая ошибка, чем в клиенте psql:
Простейшим является ssl = true, передача этого в драйвер вызовет драйвер для проверки сертификата SSL и проверки имя хоста (то же, что и
verify-full
). Обратите внимание, это отличается от libpq по умолчанию используется не проверяющее соединение SSL.
Вышеупомянутые ошибки (и успех при указании несуществующего корневого сертификата с помощью sslmode = require
), похоже, указывают на некоторую проблему с проверкой CA для сертификат.
Примечание: Я использовал сценарий, представленный в этом ответе , чтобы сгенерировать новые сертификаты и снова выполнил указанные выше тесты с идентичными результатами.
На Windows, по умолчанию root.crt
и root.crl
хранятся в %APPDATA%\postgresql
(этот поток указал мне в правильном направлении).
Когда я удалил эти файлы, я смог успешно соединиться с удаленным сервером через psql без использования каких-либо параметров ssl (по умолчанию ssl автоматически согласовывается с sslmode=require
):
C:\>"Program Files\PostgreSQL\9.6\bin\psql.exe" "postgresql://mydbuser@[REDACTED].org:5432/mydb"
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
Как и ожидалось, когда я пытаюсь заставить sslmode=verify-ca
или sslmode=verify-full
, psql не удается соединиться:
C:\>"Program Files\PostgreSQL\9.6\bin\psql.exe" "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=verify-ca"
psql: root certificate file "C:\Users\[USERNAME]\AppData\Roaming/postgresql/root.crt" does not exist
Either provide the file or change sslmode to disable server certificate verification.
C:\>"Program Files\PostgreSQL\9.6\bin\psql.exe" "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=verify-full"
psql: root certificate file "C:\Users\[USERNAME]\AppData\Roaming/postgresql/root.crt" does not exist
Either provide the file or change sslmode to disable server certificate verification.
И далее, когда я пытаюсь подключиться через JDBC, я получаю ту же ошибку (потому что по умолчанию JDBC имеет значение sslmode=verify-full
):
org.postgresql.util.PSQLException: Could not open SSL root certificate file C:\Users\[USERNAME]\AppData\Roaming\postgresql\root.crt.
at org.postgresql.ssl.LibPQFactory.<init>(LibPQFactory.java:120)
at org.postgresql.core.SocketFactoryFactory.getSslSocketFactory(SocketFactoryFactory.java:61)
at org.postgresql.ssl.MakeSSL.convert(MakeSSL.java:33)
at org.postgresql.core.v3.ConnectionFactoryImpl.enableSSL(ConnectionFactoryImpl.java:435)
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:94)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:192)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49)
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:195)
at org.postgresql.Driver.makeConnection(Driver.java:454)
at org.postgresql.Driver.connect(Driver.java:256)
...
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: java.io.FileNotFoundException: C:\Users\[USERNAME]\AppData\Roaming\postgresql\root.crt (The system cannot find the file specified)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at org.postgresql.ssl.LibPQFactory.<init>(LibPQFactory.java:117)
... 38 more
Когда я помещаю только корневой сертификат верхнего уровня (или оба корневых сертификата верхнего уровня для Path #1 или Path #2) в C:\Users\[USERNAME]\AppData\Roaming\postgresql\root\root. crt
, я могу успешно подключиться к Java (никаких проблем с использованием шаблонного сертификата для verify-full
! ):
Connecting with URL: jdbc:postgresql://[REDACTED].org:5432/mydb
PostgreSQL JDBC Driver 42.2.5
Trying to establish a protocol version 3 connection to [REDACTED].org:5432
converting regular socket connection to ssl
Canonical host name for [REDACTED].org is [REDACTED].org
Server name validation pass for [REDACTED].org, subjectAltName *.[REDACTED].org
Аналогично, когда я делаю то же самое на своем Linux psql клиенте:
# cat certs/path_1/3_root_usertrust-selfsigned.crt > ~/.postgresql/root.crt
# 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.
n4l_live=> \q
В качестве проверки на вменяемость, если только сертификаты для Path #1 находятся на сервере. crt, но я пытаюсь проверить-full
с корнем для Path #2:
# cat certs/path_2/4_root_addtrustroot-selfsigned.crt > .postgresql/root.crt
# psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=verify-full"
psql: SSL error: certificate verify failed
А затем я также добавляю корневой сертификат для Path #1:
# cat certs/path_1/3_root_usertrust-selfsigned.crt >> .postgresql/root.crt
# 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.
n4l_live=> \q
Моим ошибочным представлением в вопросе было то, что:
Это было подкреплено тем фактом, что если C:\Users\[USERNAME]\AppData\Roaming\postgresql\root\root. crt
существует, нет никаких сообщений о том, где находится этот файл (на моем радаре даже не было возможности посмотреть в эту папку).
Чтобы добавить дополнительные CRL, мне нужно было скачать и преобразовать из DER в PEM:
wget http://crl.usertrust.com/AddTrustExternalCARoot.crl
openssl crl -inform DER -in AddTrustExternalCARoot.crl -outform PEM -out AddTrustExternalCARoot_CRL.pem
wget http://crl.usertrust.com/USERTrustRSACertificationAuthority.crl
openssl crl -inform DER -in USERTrustRSACertificationAuthority.crl -outform PEM -out USERTrustRSACertificationAuthority_CRL.pem
cat USERTrustRSACertificationAuthority_CRL.pem AddTrustExternalCARoot_CRL.pem > root.crl
Но потом я обнаружил, что если я скопирую этот корневой каталог. crl
(CRL для промежуточных сертификатов) в ~/.postgresql
, то мои клиентские соединения не будут работать с той же ошибкой, с которой я начал:
# cp ../data/root.crl ~/.postgresql
# psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=verify-full"
psql: SSL error: certificate verify failed
, в конце концов, я не смог заставить CRL работать для удаленных соединений, поэтому я удалил root.crl
на клиентах для упрощения конфигурации. Теперь у меня есть успешные верификации-полные
соединения как с psql, так и с Java. Подробную запись в CRL смотрите в этом родственном вопросе.
То, что я узнал:
C:\Users\[USERNAME]\AppData\Roaming\postgresql\root. crt
, и будет принимать корневой сертификат либо Path #1, либо Path #2 для verify-full
. C:\Users\[USERNAME]\AppData\Roaming\postgresql\root.crl
(или ~/.postgresql/root.crl
в Linux) OKroot. crl
присутствует на клиенте, он должен содержать все правильные CRL для каждого пути проверки, разрешенного сервером. Если предоставлен root.crl
, но один или более корневых ЦС не имеют ассоциированной CRL Distribution Point, то соединения могут не работать с помощью сообщения о проверке сертификата с ошибкой
. Я обнаружил, что (в моем случае) ни один из корневых CA-сертификатов не имеет связанного с ним CRL, что может вызвать ошибку OpenSSL:
# psql "postgresql://mydbuser@[REDACTED].org:5432/mydb?ssl=true&sslmode=verify-full"
psql: SSL error: certificate verify failed
Эквивалентная команда openssl, подтверждающая эту ошибку, равна:
# openssl verify -crl_check -CAfile root.crt -CRLfile root.crl server.crt
server.crt: OU = Domain Control Validated, OU = PositiveSSL Wildcard, CN = *.[REDACTED].org
error 3 at 0 depth lookup:unable to get certificate CRL
И если вышеуказанная ошибка действительно ответственна за эту ошибку, то причина, по которой я смог использовать root. crl
с моим предыдущим сертификатом Comodo заключается в том, что корневой сертификат CA имел CRL Distribution Point, поэтому эта ошибка никогда не возникала. В краткосрочной перспективе моим решением будет просто удалить root.crl
, в результате чего будет установлено рабочее соединение.
Промежуточный сертификат должен быть в server.crt
Я не уверен, нужно ли его добавлять в root.crt
. Пожалуйста, обратитесь к PostgreSQL Documentation
Edit:
I just created a script to generated all you need to setup SSL with full verification. Можете ли вы запустить его и подтвердить, что он работает?
#!/bin/bash
rm -rf /tmp/pg-ssl
mkdir -p /tmp/pg-ssl
openssl req -new -nodes -text -out root.csr -keyout root.key -subj "/CN=root.yourdomain.com"
chmod og-rwx root.key
openssl x509 -req -in root.csr -text -days 3650 -extfile /etc/ssl/openssl.cnf -extensions v3_ca -signkey root.key -out root.crt
openssl req -new -nodes -text -out intermediate.csr -keyout intermediate.key -subj "/CN=intermediate.yourdomain.com"
chmod og-rwx intermediate.key
openssl x509 -req -in intermediate.csr -text -days 1825 -extfile /etc/ssl/openssl.cnf -extensions v3_ca -CA root.crt -CAkey root.key -CAcreateserial -out intermediate.crt
openssl req -new -nodes -text -out server.csr -keyout server.key -subj "/CN=dbhost.yourdomain.com"
chmod og-rwx server.key
openssl x509 -req -in server.csr -text -days 365 -CA intermediate.crt -CAkey intermediate.key -CAcreateserial -out server.crt
cat server.crt intermediate.crt > bundle.crt
echo "ssl = true"
echo "ssl_cert_file = '/tmp/pg-ssl/bundle.crt'"
echo "ssl_key_file = '/tmp/pg-ssl/server.key'"
echo "add server ip in hosts file <IP> dbhost.yourdomain.com"
echo "copy root.crt to client"
echo 'connect with psql "postgresql://dev@dbhost.yourdomain.com:5432/dev?ssl=true&sslmode=verify-full&sslrootcert=/tmp/pg-ssl/root.crt"'
Убедитесь, что сервер перезагрузился и скопировал root.crt
клиенту, который psql
может проверить идентичность сервера. В целях тестирования файл /etc/hosts
на клиенте должен быть изменен, чтобы сделать CN действительным с точки зрения клиента.