Skip to content

LDAPS vulnerable to MITM - failure to validate hostname against CN or SAN in X509 Cert #258

Closed
@JPvRiel

Description

@JPvRiel

There are noted TLS/SSL limitations in the documented parts of the code and the info about encryption. Technically, TLS/SSL also provides the ability to authenticate servers by matching the hostname to a CN (common name) or a (SAN) Subject Alternative Name and from what I've seen, while net-ldap notes the certificate and trust chain limitations as insecure default, but it doesn't note the extra step needed to get to proper LDAP server authentication via LDAPS.

In order to verify certificates and enable other TLS options, the
  #   :tls_options hash can be passed alongside :simple_tls or :start_tls.
  #   This hash contains any options that can be passed to
  #   OpenSSL::SSL::SSLContext#set_params(). The most common options passed
  #   should be OpenSSL::SSL::SSLContext::DEFAULT_PARAMS, or the :ca_file option,
  #   which contains a path to a Certificate Authority file (PEM-encoded).

The above advice is not sufficient. It only assures that a server has a valid cert which was signed by a trusted CA, but it does not provide proof that it's the correct server E.g. evil.example.net with a cert issued as CN=evil.example.net could still impersonate ldap.example.net to steal credentials.

In addition to the above suggtestion setting a more secure and sane TLS/SSL context that validates certs , the net-ldap lib should also, probably by default, add and make use of verify_certificate_identity. I've browsed connection.rb and don't see anything that checks the hostname (FQDN) is authenticated against the certficate.

  def self.wrap_with_ssl(io, tls_options = {})
    raise Net::LDAP::NoOpenSSLError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL

    ctx = OpenSSL::SSL::SSLContext.new

    # By default, we do not verify certificates. For a 1.0 release, this should probably be changed at some point.
    # See discussion in https://github.com/ruby-ldap/ruby-net-ldap/pull/161
    ctx.set_params(tls_options) unless tls_options.empty?

    conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
    conn.connect

    # Doesn't work:
    # conn.sync_close = true

    conn.extend(GetbyteForSSLSocket) unless conn.respond_to?(:getbyte)
    conn.extend(FixSSLSocketSyncClose)

    conn
  end 

Given ruby essentially 'wraps' OpenSSL, this Hostname_validation reference also highlights the issue, with a choice extract

One common mistake made by users of OpenSSL is to assume that OpenSSL will validate the hostname in the server's certificate. Versions prior to 1.0.2 did not perform hostname validation. Version 1.0.2 and up contain support for hostname validation, but they still require the user to call a few functions to set it up.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions