VERIFY_PEER_IDENTITY_DNS does not work

Description

Using the DataStax C++ Driver for Cassandra, if the cluster contact point is specified as a domain name (e.g., server1.example.com), TLS is used, the domain has a valid certificate with the domain name specified (as either commonName or DNS-type subjectAltName), and SSL is configured with CASS_SSL_VERIFY_PEER_IDENTITY_DNS, the driver is unable to connect to the contact point, reporting "Unable to establish a control connection to host 10.25.16.6 because of the following error: Underlying connection error: Error verifying peer certificate: Peer certificate subject name does not match" in cluster_connector.cpp.

Debugging reveals that the code in OpenSslVerifyIdentity::match_dns() is being passed a hostname_ which is just the empty string "".

Analysis

In the resolver, Resolver::on_resolve https://github.com/datastax/cpp-driver/blob/master/src/resolver.hpp#L111 uses the response from the resolver to call init_addresses(). This builds an Address from each ai_addr (IP address) in the response, and pushes them all onto the list of addresses. It does not preserve the hostname that corresponds to the address - the constructed Address has just "" as the server_name.

If the client requests peer identity verification (either CASS_SSL_VERIFY_PEER_IDENTITY which verifies the IP against the SANs if present, else the server_name against the CN, or CASS_SSL_VERIFY_PEER_IDENTITY_DNS which verifies the server_name against the SANs if present, else the server_name against the CN), then server name matching will never work - unless you somehow have a cert for the name "".

This is handled better in SocketConnector::on_resolve https://github.com/datastax/cpp-driver/blob/master/src/socket_connector.cpp#L292 ("// Keep the server name for debugging" :)), which explicitly sets the address_.server_name() into the resolved_address - but that's too late; the control connection doesn't do this, so we can't actually get a successful connection.

The fix is to copy the requested domain name into the Address in Resolver::on_resolve, so it can be used for peer identity verification. To avoid regression, the code for CASS_SSL_VERIFY_PEER_IDENTITY should be altered so it always checks the IP address in the CN case, even if a server_name is present.

Docs

Incidentally, the docs are not very clear that CASS_SSL_VERIFY_PEER_IDENTITY | CASS_SSL_VERIFY_PEER_IDENTITY_DNS means just VERIFY_PEER_IDENTITY will be done (these are alternatives). They're also confusing for CASS_SSL_VERIFY_PEER_IDENTITY wrt the CN behaviour. It would be good to improve these (see https://github.com/datastax/cpp-driver/blob/master/src/ssl/ssl_openssl_impl.cpp#L473 and #L264):

  • CASS_SSL_VERIFY_PEER_IDENTITY: If the cert has any SANs, it checks that the IP address matches one of the SANs. Else (i.e., the cert has no SANs), it checks that the server address string-matches the CN.

  • CASS_SSL_VERIFY_PEER_IDENTITY_DNS: If the cert has any SANs, it checks that the server hostname matches one of the SANs. Else (i.e., the cert has no SANs), it checks that the server hostname string-matches the CN.

Environment

None

Pull Requests

None

Activity

Show:

Keith Wansbrough 
March 4, 2021 at 2:33 PM

Fix now available at . We’ve tested this locally and it resolves the issue.

Michael Penick 
January 22, 2021 at 2:25 PM

Thanks for the report.

Details

Assignee

Reporter

Labels

Reproduced in

Affects versions

Priority

Created January 19, 2021 at 12:45 PM
Updated January 25, 2022 at 2:00 AM