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:
Michael Penick
January 23, 2021, 1:25 AM

Thanks for the report.

Assignee

Unassigned

Reporter

Keith Wansbrough

Labels

PM Priority

None

Reproduced in

2.15.3

External issue ID

None

Doc Impact

None

Reviewer

None

Pull Request

None

Size

None

Affects versions

Priority

Major