commit eb5ddc1d8909fe322ddeb1ec4bf9118bb9544667 Author: Jacob Champion Date: Wed May 11 10:33:33 2022 -0700 squash! Log details for client certificate failures - Add a maximum Subject length to prevent malicious client certs from spamming the logs. - Add the certificate serial number to the output, for disambiguation if the Subject gets truncated unhelpfully. diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index 1683f9cc9e..3ccc23ba62 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -1094,6 +1094,8 @@ verify_cb(int ok, X509_STORE_CTX *ctx) const char *errstring; X509 *cert; char *certname = NULL; + char *truncated = NULL; + char *serialno = NULL; if (ok) { @@ -1108,14 +1110,56 @@ verify_cb(int ok, X509_STORE_CTX *ctx) cert = X509_STORE_CTX_get_current_cert(ctx); if (cert) + { + size_t namelen; + ASN1_INTEGER *sn; + BIGNUM *b; + + /* + * Get the Subject for logging, but don't let maliciously huge certs + * flood the logs. + * + * Common Names are 64 chars max, so for a common case where the CN is + * the last field, we can still print the longest possible CN with a + * 7-character prefix (".../CN=[64 chars]"), for a reasonable limit of + * 71 characters. + */ +#define MAXLEN 71 certname = X509_NAME_to_cstring(X509_get_subject_name(cert)); + namelen = strlen(certname); + + if (namelen > MAXLEN) + { + /* + * Keep the end of the Subject, not the beginning, since the most + * specific field is likely to give users the most information. + */ + truncated = certname + namelen - MAXLEN; + truncated[0] = truncated[1] = truncated[2] = '.'; + } +#undef MAXLEN + + /* + * Pull the serial number, too, in case a Subject is still ambiguous. + * This mirrors be_tls_get_peer_serial(). + */ + sn = X509_get_serialNumber(cert); + b = ASN1_INTEGER_to_BN(sn, NULL); + serialno = BN_bn2dec(b); + + BN_free(b); + } ereport(COMMERROR, (errmsg("client certificate verification failed at depth %d: %s", depth, errstring), /* only print detail if we have a certificate to print */ - certname && errdetail("failed certificate's subject: %s", certname))); + certname && errdetail("failed certificate had subject '%s', serial number %s", + truncated ? truncated : certname, + serialno ? serialno : _("unknown")))); + if (serialno) + OPENSSL_free(serialno); if (certname) pfree(certname); diff --git a/src/test/ssl/conf/client-long.config b/src/test/ssl/conf/client-long.config new file mode 100644 index 0000000000..0e92a8fbfe --- /dev/null +++ b/src/test/ssl/conf/client-long.config @@ -0,0 +1,14 @@ +# An OpenSSL format CSR config file for creating a client certificate with a +# long Subject. + +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] +# Common Names are 64 characters max +CN = ssl-123456789012345678901234567890123456789012345678901234567890 +OU = Some Organizational Unit +O = PostgreSQL Global Development Group + +# no extensions in client certs diff --git a/src/test/ssl/ssl/client-long.crt b/src/test/ssl/ssl/client-long.crt new file mode 100644 index 0000000000..a1db55b5c3 --- /dev/null +++ b/src/test/ssl/ssl/client-long.crt @@ -0,0 +1,69 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 2315418733629425152 (0x2022051214444600) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = Test CA for PostgreSQL SSL regression test client certs + Validity + Not Before: May 12 21:44:47 2022 GMT + Not After : Sep 27 21:44:47 2049 GMT + Subject: O = PostgreSQL Global Development Group, OU = Some Organizational Unit, CN = ssl-123456789012345678901234567890123456789012345678901234567890 + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d8:31:99:e1:e2:55:1b:81:4f:09:46:43:5a:0c: + d8:cd:5c:91:00:88:fe:8e:21:61:c3:bd:05:87:71: + 0d:81:e2:03:b8:f2:d5:65:5e:9f:28:fc:06:d5:22: + e4:08:fd:54:38:69:7e:2b:9e:c0:36:ab:19:0e:5a: + 4e:08:03:d6:93:23:93:0d:0c:a2:b0:4a:06:bf:7e: + d6:ed:71:18:7f:fc:43:79:64:81:4f:8e:41:7a:cf: + 82:5a:38:22:b5:5c:a9:aa:19:15:0d:27:b8:c6:95: + 6e:27:97:d1:d0:f2:4d:fb:13:69:54:18:62:da:80: + b7:38:48:fd:41:92:20:e8:64:db:e9:41:f5:f3:fa: + f2:3c:3d:70:b1:f4:41:8b:d1:fa:a4:34:20:f1:b5: + dc:8e:73:99:26:0f:32:3d:15:63:03:27:f5:31:7d: + ff:6b:01:39:24:55:81:35:40:72:b6:20:39:02:e4: + de:cf:df:19:ee:ba:b6:65:41:21:66:1c:ab:ae:72: + 82:a0:f5:fb:07:ae:f8:f6:b1:8c:f9:f0:b1:e7:e4: + 76:77:fa:25:d6:11:1b:51:75:0a:8e:e0:e7:6a:68: + 3c:46:22:78:01:df:40:e2:7a:f6:c1:b4:2d:8c:74: + 94:13:83:0b:af:6a:bd:22:78:59:d0:90:d3:32:b0: + db:cf + Exponent: 65537 (0x10001) + Signature Algorithm: sha256WithRSAEncryption + ae:be:6b:d5:4c:60:53:33:f2:92:6b:b9:65:d2:fa:cb:c4:c0: + 65:b4:90:d7:20:58:d2:78:6c:47:04:64:0d:de:ba:88:f2:bd: + 53:a4:fa:2b:6f:a9:2f:c5:5c:ea:2a:28:bf:d5:8e:b4:74:3a: + a2:13:f7:81:26:af:77:8d:1c:1d:19:85:6a:ec:08:b1:9e:16: + 93:49:a3:7e:da:4e:b8:f1:69:d6:1c:a8:f1:df:d0:62:b6:c4: + 9b:7a:8d:7b:9a:a5:9f:94:bd:87:c8:a9:a1:8b:c5:b5:fe:73: + 94:ad:8a:1c:91:73:f5:e8:59:31:9d:73:18:01:11:34:25:4c: + f1:45:10:2b:25:2e:64:1e:46:ca:b6:65:6e:c9:5f:e8:ff:fd: + 06:c7:39:e1:85:16:c4:fd:a9:af:9a:ff:44:9e:83:79:77:c8: + cc:01:5f:5d:3f:00:15:59:42:94:04:40:f7:8f:60:a5:7d:0b: + 56:b5:eb:c8:33:7a:d0:25:09:f3:c4:09:99:80:90:dc:0b:48: + 83:36:18:7a:a7:1d:60:74:dd:f1:e4:b6:f4:fe:70:84:37:54: + e4:db:d1:38:ff:8b:8c:44:de:45:e2:45:e0:17:f2:73:68:0c: + ef:3c:59:0f:60:43:49:fe:5e:c6:f9:cd:aa:2c:b8:db:f9:51: + d5:be:2c:cf +-----BEGIN CERTIFICATE----- +MIIDWjCCAkICCCAiBRIUREYAMA0GCSqGSIb3DQEBCwUAMEIxQDA+BgNVBAMMN1Rl +c3QgQ0EgZm9yIFBvc3RncmVTUUwgU1NMIHJlZ3Jlc3Npb24gdGVzdCBjbGllbnQg +Y2VydHMwHhcNMjIwNTEyMjE0NDQ3WhcNNDkwOTI3MjE0NDQ3WjCBnDEsMCoGA1UE +CgwjUG9zdGdyZVNRTCBHbG9iYWwgRGV2ZWxvcG1lbnQgR3JvdXAxITAfBgNVBAsM +GFNvbWUgT3JnYW5pemF0aW9uYWwgVW5pdDFJMEcGA1UEAwxAc3NsLTEyMzQ1Njc4 +OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2 +Nzg5MDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgxmeHiVRuBTwlG +Q1oM2M1ckQCI/o4hYcO9BYdxDYHiA7jy1WVenyj8BtUi5Aj9VDhpfiuewDarGQ5a +TggD1pMjkw0MorBKBr9+1u1xGH/8Q3lkgU+OQXrPglo4IrVcqaoZFQ0nuMaVbieX +0dDyTfsTaVQYYtqAtzhI/UGSIOhk2+lB9fP68jw9cLH0QYvR+qQ0IPG13I5zmSYP +Mj0VYwMn9TF9/2sBOSRVgTVAcrYgOQLk3s/fGe66tmVBIWYcq65ygqD1+weu+Pax +jPnwsefkdnf6JdYRG1F1Co7g52poPEYieAHfQOJ69sG0LYx0lBODC69qvSJ4WdCQ +0zKw288CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEArr5r1UxgUzPykmu5ZdL6y8TA +ZbSQ1yBY0nhsRwRkDd66iPK9U6T6K2+pL8Vc6ioov9WOtHQ6ohP3gSavd40cHRmF +auwIsZ4Wk0mjftpOuPFp1hyo8d/QYrbEm3qNe5qln5S9h8ipoYvFtf5zlK2KHJFz +9ehZMZ1zGAERNCVM8UUQKyUuZB5GyrZlbslf6P/9Bsc54YUWxP2pr5r/RJ6DeXfI +zAFfXT8AFVlClARA949gpX0LVrXryDN60CUJ88QJmYCQ3AtIgzYYeqcdYHTd8eS2 +9P5whDdU5NvROP+LjETeReJF4Bfyc2gM7zxZD2BDSf5exvnNqiy42/lR1b4szw== +-----END CERTIFICATE----- diff --git a/src/test/ssl/ssl/client-long.key b/src/test/ssl/ssl/client-long.key new file mode 100644 index 0000000000..5b455a021f --- /dev/null +++ b/src/test/ssl/ssl/client-long.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA2DGZ4eJVG4FPCUZDWgzYzVyRAIj+jiFhw70Fh3ENgeIDuPLV +ZV6fKPwG1SLkCP1UOGl+K57ANqsZDlpOCAPWkyOTDQyisEoGv37W7XEYf/xDeWSB +T45Bes+CWjgitVypqhkVDSe4xpVuJ5fR0PJN+xNpVBhi2oC3OEj9QZIg6GTb6UH1 +8/ryPD1wsfRBi9H6pDQg8bXcjnOZJg8yPRVjAyf1MX3/awE5JFWBNUBytiA5AuTe +z98Z7rq2ZUEhZhyrrnKCoPX7B6749rGM+fCx5+R2d/ol1hEbUXUKjuDnamg8RiJ4 +Ad9A4nr2wbQtjHSUE4MLr2q9InhZ0JDTMrDbzwIDAQABAoIBADwJykpIqIny5xgU +QzAG0U52nm4fnVGrQ5MwMxDh/HZNZes+xLRaCqk/FEasYdd9Qp5H7Zn/hDGqYlLy +ESl4p2ZFQtkk4SlD5YvYladq+PrR+4sCtkZ5owWQCwsy+7CSAywRux7kIRRE+0pT +hxkXsUBAq8eG3i0AAeHHo01KX4kptlJ5d1pFKKAPThTUHCT4VPHg8r59IdsNy6wC ++0E5ZRWsVUePy+ERuarX/um896hgbaiDJLFk02Orlc87+OBmRwO8J+KoUOEcAiTO +OZqGGaDEn5Y2mEdp2cCmq7+Izcklaha6CPsoV8+O2HK8PKvBIQmlgbDmal4/RNqr +JFqYz0ECgYEA+5z74Tmj+tzH57lcdMqVpndG39N8spBe8JbiFL16qOb6gRDytXjc +hY6IQo4JStpJulnPBZ5JQSbSBgCOzYWJJVBnnwMJKjNCd1th4znjxxMOe4LiDTtw +D3hQtzBU9FlI2sjWEUKf1xCyi9N41ApQC5eDWWd/0GN9+xAsxRjLL00CgYEA2/aH +4kNVsBHQ7vmv+sNsWeIgKg7PC7hRjcCYQG9ylBbBnFtv5XJYicXwqorqngzJPoGw +gB7iaSWL1UNAOSWRSFYe+woPpkY7n6Pbq211nzqV1avAdVrLylJwyE+EOQgTS30D +8BHv0I714PMd/QLK5NSUEr1IRtCfLeMpcSg6YYsCgYEAv3O86KxeTMTvyy9s3WVE +p4y8vhUDHi/iPbjhQBzJF3nhhJGrzE+xpGJG5jWDdpRQY15wuvqtDMkIKA8GmfWQ +3Hao0gKSV6z3VzCOdEKZQeILNAnsDVt7shm/eRRqoB7L48XLtQh37UJESUbY+qb6 +L0fTZxTs2VjLBF1TY4mxGUUCgYEA1PLENKnJkA5/fowd8aA2CoKfbvgtPARyd9Bn +1aHPhEzPnabsGm7sBl2qFAEvCFoKjkgR7sd3nCHsUUetKmYTU7uEfLcN1YSS/oct +CLaMs92M53JCfZqsRrAvXc2VjX0i6Ocb49QJnph4tBHKC4MjmAuxWr8C9QPNxyfv +nAw9EOcCgYBYzejUzp6xiv5YzpwIncIF0A5E6VITcsW+LOR/FZOUPso0X2hQoIEs +wx8HjKCGfvX6628vnaWJC099hTmOzVwpEgik5zOmeAmZ//gt2I53Yg/loQUzH0CD +iXxrg/4Up7Yxx897w11ukOZv2xwmAFO1o52Q8k7d5FiMfEIzAkS3Pg== +-----END RSA PRIVATE KEY----- diff --git a/src/test/ssl/sslfiles.mk b/src/test/ssl/sslfiles.mk index cc023667af..5f67aba795 100644 --- a/src/test/ssl/sslfiles.mk +++ b/src/test/ssl/sslfiles.mk @@ -33,7 +33,7 @@ SERVERS := server-cn-and-alt-names \ server-multiple-alt-names \ server-no-names \ server-revoked -CLIENTS := client client-dn client-revoked client_ext +CLIENTS := client client-dn client-revoked client_ext client-long # # To add a new non-standard key, add it to SPECIAL_KEYS and then add a recipe diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl index ecc7bd2bce..4c7a8bd7a2 100644 --- a/src/test/ssl/t/001_ssltests.pl +++ b/src/test/ssl/t/001_ssltests.pl @@ -668,7 +668,7 @@ $node->connect_fails( expected_stderr => qr/SSL error: sslv3 alert certificate revoked/, log_like => [ qr/client certificate verification failed at depth 0: certificate revoked/, - qr/failed certificate's subject: \/CN=ssltestuser/, + qr/failed certificate had subject '\/CN=ssltestuser', serial number 2315134995201656577/, ], # revoked certificates should not authenticate the user log_unlike => [qr/connection authenticated:/],); @@ -715,7 +715,16 @@ $node->connect_fails( expected_stderr => qr/SSL error: tlsv1 alert unknown ca/, log_like => [ qr/client certificate verification failed at depth 0: unable to get local issuer certificate/, - qr/failed certificate's subject: \/CN=ssltestuser/, + qr/failed certificate had subject '\/CN=ssltestuser', serial number 2315134995201656576/, + ]); + +$node->connect_fails( + "$common_connstr sslmode=require sslcert=ssl/client-long.crt " . sslkey('client-long.key'), + "logged client certificate Subjects are truncated if they're too long", + expected_stderr => qr/SSL error: tlsv1 alert unknown ca/, + log_like => [ + qr/client certificate verification failed at depth 0: unable to get local issuer certificate/, + qr/failed certificate had subject '\.\.\.\/CN=ssl-123456789012345678901234567890123456789012345678901234567890', serial number 2315418733629425152/, ]); # Use an invalid cafile here so that the next test won't be able to verify the @@ -730,7 +739,7 @@ $node->connect_fails( expected_stderr => qr/SSL error: tlsv1 alert unknown ca/, log_like => [ qr/client certificate verification failed at depth 1: unable to get local issuer certificate/, - qr/failed certificate's subject: \/CN=Test CA for PostgreSQL SSL regression test client certs/, + qr/failed certificate had subject '\/CN=Test CA for PostgreSQL SSL regression test client certs', serial number 2315134995201656577/, ]); # test server-side CRL directory @@ -743,7 +752,7 @@ $node->connect_fails( expected_stderr => qr/SSL error: sslv3 alert certificate revoked/, log_like => [ qr/client certificate verification failed at depth 0: certificate revoked/, - qr/failed certificate's subject: \/CN=ssltestuser/, + qr/failed certificate had subject '\/CN=ssltestuser', serial number 2315134995201656577/, ]); done_testing(); diff --git a/src/test/ssl/t/SSL/Backend/OpenSSL.pm b/src/test/ssl/t/SSL/Backend/OpenSSL.pm index 1546b5081b..cdfd14fcdf 100644 --- a/src/test/ssl/t/SSL/Backend/OpenSSL.pm +++ b/src/test/ssl/t/SSL/Backend/OpenSSL.pm @@ -88,7 +88,7 @@ sub init "client.key", "client-revoked.key", "client-der.key", "client-encrypted-pem.key", "client-encrypted-der.key", "client-dn.key", - "client_ext.key"); + "client_ext.key", "client-long.key"); foreach my $keyfile (@keys) { copy("ssl/$keyfile", "$cert_tempdir/$keyfile")