Skip to content

enable TLS hostname validation #279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Aug 24, 2016
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
84ab4c2
fix iptables blackholing for macOS
Aug 23, 2016
7b2bb02
new fixture CA, now with private key
Aug 23, 2016
2137361
vagrant fix for macOS v Linux?
Aug 23, 2016
38b6147
helper should use the new CA
Aug 23, 2016
b42e931
rubocop fix
Aug 23, 2016
22eaf7c
cherry pick from https://github.com/ruby-ldap/ruby-net-ldap/pull/259
JPvRiel-SB Jan 14, 2016
d7b36d1
check that the encryption hash is defined before using it
Aug 23, 2016
748f1b9
add tests for cert/hostname mismatch
Aug 23, 2016
9bab5a5
stupid portforwarding tricks for local testing
Aug 23, 2016
381fdf4
omit example
Aug 23, 2016
fd1c823
doc tweak
Aug 23, 2016
7593af1
too many markdown syntaxes
Aug 23, 2016
052f90d
remove stale reference to gem
Aug 23, 2016
ca4e390
extra ldap object for multiple host tests
Aug 23, 2016
c6a465f
add multi-host SSL checks
Aug 23, 2016
1300bc0
include "localhost" as valid cert name
Aug 23, 2016
440ce7f
tidy up the TLS tests
Aug 23, 2016
199f429
fix up to look like https://github.com/ruby-ldap/ruby-net-ldap/pull/2…
Aug 23, 2016
caf1911
remove useless test CA
Aug 23, 2016
c801132
only use tcp/9389 with vagrant, use the right exception for bad TLS c…
Aug 23, 2016
80bab6c
handle both exceptions
Aug 23, 2016
eeb7a6d
single vs multiple hosts throw different exceptions
Aug 23, 2016
c5f2126
more TLS tests around merging vs not merging the default options
Aug 23, 2016
d2ba5e6
fix bogus multi-host check
Aug 23, 2016
41881aa
remove vagrant port override, because $INTEGRATION_PORT
Aug 23, 2016
19f9c7d
more no-merge-default-opts tests, done properly
Aug 23, 2016
3c18b1e
more docs about vagrant setup
Aug 23, 2016
0f51b56
add script to generate fixture
Aug 23, 2016
02a29ea
use script-generated fixture CA
Aug 23, 2016
7de6335
describe where fixture CA comes from; also indent
Aug 23, 2016
a890f03
linter quoting complaint
Aug 23, 2016
3aebc3d
test that no tls_options means we get the system CA bundle
Aug 24, 2016
4e5a8e7
improve system store tests
Aug 24, 2016
0a8c099
use default tls opts for validation
Aug 24, 2016
8ed4dca
properly add the fixture CA to CI system store
Aug 24, 2016
efd354a
names matter
Aug 24, 2016
0926274
don't need the whole default hash for a verify?
Aug 24, 2016
72ba381
add docs on how to actually validate an LDAP server cert
Aug 24, 2016
435332d
whoops, DEFAULT_PARAMS is already a hash
Aug 24, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,10 @@ This task will run the test suite and the

rake rubotest

To run the integration tests against an LDAP server:

cd test/support/vm/openldap
vagrant up
cd ../../../..
INTEGRATION=openldap bundle exec rake rubotest
CI takes too long? If your local box supports
{Vagrant}[https://www.vagrantup.com/], you can run most of the tests
in a VM on your local box. For more details and setup instructions, see
{test/support/vm/openldap/README.md}[https://github.com/ruby-ldap/ruby-net-ldap/tree/master/test/support/vm/openldap/README.md]

== Release

Expand Down
20 changes: 14 additions & 6 deletions lib/net/ldap/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,15 @@ def open_connection(server)
hosts.each do |host, port|
begin
prepare_socket(server.merge(socket: @socket_class.new(host, port, socket_opts)), timeout)
if encryption
if encryption[:tls_options] &&
encryption[:tls_options][:verify_mode] &&
encryption[:tls_options][:verify_mode] == OpenSSL::SSL::VERIFY_NONE
warn "not verifying SSL hostname of LDAPS server '#{host}:#{port}'"
else
@conn.post_connection_check(host)
end
end
return
rescue Net::LDAP::Error, SocketError, SystemCallError,
OpenSSL::SSL::SSLError => e
Expand Down Expand Up @@ -392,12 +401,11 @@ def search(args = nil)
# should collect this into a private helper to clarify the structure
query_limit = 0
if size > 0
if paged
query_limit = (((size - n_results) < 126) ? (size -
n_results) : 0)
else
query_limit = size
end
query_limit = if paged
(((size - n_results) < 126) ? (size - n_results) : 0)
else
size
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No behavioral change, just fiddling with syntax

end

request = [
Expand Down
52 changes: 36 additions & 16 deletions script/install-openldap
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ chown -R openldap.openldap /var/lib/ldap
rm -rf $TMPDIR

# SSL
export CA_CERT="/etc/ssl/certs/cacert.pem"
export CA_KEY="/etc/ssl/private/cakey.pem"
export CA_INFO="/etc/ssl/ca.info"

sh -c "certtool --generate-privkey > /etc/ssl/private/cakey.pem"
# If you ever need to regenerate these...
# certtool --generate-privkey > /path/to/cakey.pem
# certtool --generate-self-signed \
# --load-privkey /path/to/cakey.pem
# --template /path/to/ca.info
# --outfile /path/to/cacert.pem
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be removed? Was there a previous fixture CA?

Copy link
Collaborator Author

@tmaher tmaher Aug 23, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there was a previous fixture CA, removed in this PR in caf1911. Oddly, it was just the CA cert, no private key. Travis ignored it completely and generated its own self-signed CA cert/key pair on every run. Because the Vagrant tests execute on a different host, it's easier to use a fixture keypair burned into the repo.

I left the commented-out lines in there in case the fixture CA needs to be regenerated, or in case future custom TLS tests require specific cert values. We could move the comment out into script/generate-fixture-ca or something if you like.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move the comment out into script/generate-fixture-ca or something if you like.

👍 I think that would be more clear and prevent someone (likely me) from accidentally removing it. Maybe leave a comment pointing to that script?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, it's now in script/generate-fixture-ca and requires an explicit flag to do the destructive thing. I validated the script by using it to replace the CA/key I'd previously added to the PR. Seems fine.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these be removed?


sh -c "cat > /etc/ssl/ca.info <<EOF
cn = rubyldap
ca
cert_signing_key
EOF"

# Create the self-signed CA certificate:
certtool --generate-self-signed \
--load-privkey /etc/ssl/private/cakey.pem \
--template /etc/ssl/ca.info \
--outfile /etc/ssl/certs/cacert.pem
cp "${SEED_PATH}/ca/cacert.pem" "${CA_CERT}"
cp "${SEED_PATH}/ca/cakey.pem" "${CA_KEY}"
cp "${SEED_PATH}/ca/ca.info" "${CA_INFO}"

# Make a private key for the server:
certtool --generate-privkey \
Expand All @@ -71,24 +71,36 @@ certtool --generate-privkey \
sh -c "cat > /etc/ssl/ldap01.info <<EOF
organization = Example Company
cn = ldap01.example.com
dns_name = ldap01.example.com
dns_name = ldap02.example.com
dns_name = localhost
tls_www_server
encryption_key
signing_key
expiration_days = 3650
EOF"

# The integration server may be accessed by IP address, in which case
# we want some of the IPs included in the cert. We skip loopback (127.0.0.1)
# because that's the IP we use in the integration test for cert name mismatches.
ADDRS=$(ifconfig -a | grep 'inet addr:' | cut -f 2 -d : | cut -f 1 -d ' ')
for ip in $ADDRS; do
if [ "x$ip" = 'x127.0.0.1' ]; then continue; fi
echo "ip_address = $ip" >> /etc/ssl/ldap01.info
done

# Create the server certificate
certtool --generate-certificate \
--load-privkey /etc/ssl/private/ldap01_slapd_key.pem \
--load-ca-certificate /etc/ssl/certs/cacert.pem \
--load-ca-privkey /etc/ssl/private/cakey.pem \
--load-ca-certificate "${CA_CERT}" \
--load-ca-privkey "${CA_KEY}" \
--template /etc/ssl/ldap01.info \
--outfile /etc/ssl/certs/ldap01_slapd_cert.pem

ldapmodify -Y EXTERNAL -H ldapi:/// <<EOF | true
dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
olcTLSCACertificateFile: ${CA_CERT}
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap01_slapd_cert.pem
Expand All @@ -110,6 +122,14 @@ chmod g+r /etc/ssl/private/ldap01_slapd_key.pem
chmod o-r /etc/ssl/private/ldap01_slapd_key.pem

# Drop packets on a secondary port used to specific timeout tests
iptables -A OUTPUT -p tcp -j DROP --dport 8389
iptables -A INPUT -p tcp -j DROP --dport 8389
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you provide more a link or some background for why mac os blackholes here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DigitalOcean has a good write-up of iptables theory.

In Travis CI, the test suite executes on the integration host itself. The -A OUTPUT bit means that the packets are dropped before the kernel even tries sending them anywhere. In contrast, with Vagrant, the test suite runs on the hypervisor and connects to a "remote" integration host. The hypervisor is unlikely to be doing any of its own output filtering, so the packets are sent to the guest VM. The guest kernel doesn't have anything listening on tcp/8389, so it sends a RST before even consulting the OUTPUT chain.

With the switch to INPUT, on Travis, there's no effective change. TCP SYN's to 8389 will make it through the OUTPUT chain intact and actually be sent to localhost:8389. At that point, the INPUT chain for that port will drop the SYN rather than send a RST. That means from the unit tests' perspective, this is a noop.

With Vagrant, now that the guest is dropping tcp/8389 on INPUT, the guest kernel will stop sending RST's and just ignore the connection attempt. That brings it in line with what Travis is doing, and is what we need to do the test.


# Forward a port for Vagrant
iptables -t nat -A PREROUTING -p tcp --dport 9389 -j REDIRECT --to-port 389

# fix up /etc/hosts for cert validation
grep ldap01 /etc/hosts || echo "127.0.0.1 ldap01.example.com" >> /etc/hosts
grep ldap02 /etc/hosts || echo "127.0.0.1 ldap02.example.com" >> /etc/hosts
grep bogus /etc/hosts || echo "127.0.0.1 bogus.example.com" >> /etc/hosts

service slapd restart
4 changes: 4 additions & 0 deletions test/fixtures/ca/ca.info
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
cn = rubyldap
ca
cert_signing_key
expiration_days = 7200
18 changes: 18 additions & 0 deletions test/fixtures/ca/cacert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC7zCCAdegAwIBAgIMV7ur2wQbbBBUX/gBMA0GCSqGSIb3DQEBCwUAMBMxETAP
BgNVBAMTCHJ1YnlsZGFwMB4XDTE2MDgyMzAxNTAxOVoXDTM2MDUxMDAxNTAxOVow
EzERMA8GA1UEAxMIcnVieWxkYXAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDIXIIUk/PJ8UnmthzX1ZC5pej7qwQDILA/o4/EkU1rBfGkHNhJihzOoW+1
QjixcxjVM8pZXM0+bkOr/UY4ymqQnnW7a8U6Rc1+4Mhz7jKtjChfjWkAX857alL7
2F5M1pUBvQ1WdXXFOwO0vyDT54UzkFMr/lvKXrd4/kNJYQE87+B0igICEDocFLO3
SchtH0YpSzE80b0Fn1O1noS3LU9Eo+XsMoBMHVVrKOb/Yzs5Z1hfPrHOpB+z3VTe
4/LcbbcMoc20Ypjq+kamuYo6uGoy0lzgmgwQgJtmxl8EhsIrZuUw80yJZqi3bLht
8UZbVM1dV1/Hh7danmlWqZnI579FAgMBAAGjQzBBMA8GA1UdEwEB/wQFMAMBAf8w
DwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQUZ4HlXJgf2tIxLhDOB07SC200XG8w
DQYJKoZIhvcNAQELBQADggEBAIee6oT01p6e300scQTo/VPELf14ebrZXDqtJ7HR
egHZRrSzyQgxnnyFfoazG9bmgX/xgDvH8CxW4Q7OHH2ybGA5z2FfK+uSAjKHPR2y
8EjAKfQUDo0CBlcU0otvk8KhyNmu3sbCO6QGlnDDnWo78UDOdfeflvCp4HH+wdnU
ZSKTxaJe7BbBPMm6VZGhqa4O7MOOiupcGUt0emsyA1mVixkhr+6/aO2FLdiXwclX
GhYBZg5xxbM5Hn8LbjfRsaqCjBpOXLKnuUGDQSQj1TtRFzRuiGU4tHpoBnQGCYNa
bhFP7hjfwcjKUSizHM89KugrVgpnDh6oKn+xrhSdcKTmlag=
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions test/fixtures/ca/cakey.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyFyCFJPzyfFJ5rYc19WQuaXo+6sEAyCwP6OPxJFNawXxpBzY
SYoczqFvtUI4sXMY1TPKWVzNPm5Dq/1GOMpqkJ51u2vFOkXNfuDIc+4yrYwoX41p
AF/Oe2pS+9heTNaVAb0NVnV1xTsDtL8g0+eFM5BTK/5byl63eP5DSWEBPO/gdIoC
AhA6HBSzt0nIbR9GKUsxPNG9BZ9TtZ6Ety1PRKPl7DKATB1Vayjm/2M7OWdYXz6x
zqQfs91U3uPy3G23DKHNtGKY6vpGprmKOrhqMtJc4JoMEICbZsZfBIbCK2blMPNM
iWaot2y4bfFGW1TNXVdfx4e3Wp5pVqmZyOe/RQIDAQABAoIBAALhQYVmMwTeEP/d
8kAv86qXdefYJ3CcEax4f2KF7CTzqut+9qTn9U4LB/4E+6ehTeQSoH/0U4boMtTQ
CShb0HhPrsWI4QbbZf7C4F66N8RC1Xm6IJ4+wksH1jWEgKZ+Fxo1S3HIsm6pUH5S
mPgyxbleA7QILe2UuvJkRTdSy5/ClGROTXAZfA7NE/yL+cUjAOyQfxs/SxcMwnxK
phGZaAfYRpvExtRO9CAdlmkC9RgYWOdC/r7wHehpY7fi/FqBd46w+AV3ougKGt9r
yOEcXVrJRQtDR5UWivUOs34MCPQa2T+XHn/WLgeWE6bNaw5SyLr4oolb10Iue+Hw
v23W5oECgYEA7rEE7/6rTkHodVI9wrYg007WDQmeR6Y0gwiX6oGQpftXExfHjHio
yr0qwbL/UOFkWfJ8ORNXa6hHIDfxI2Kkg7vgt8SaLK8c0zhszJpcYmAx63Kk+BUO
/S863Ptz28rGmXJxjo5GYUHR7rjvRefauV6SSUo9rbocFcyeV/UlXpUCgYEA1uPx
TSXt2MBRiGp+E4tNPj+16QaF+4ety3+a4vlsY2ALejkjC3I5Lf1s4b0SW6eEn/U2
PYFzm3FqsDqYhSas64b2s3Cw8x2yQ7rCD3SKGoiJqUSPwLkZjgUXC1gDaMkJXzEX
L9yBEBVfNRYCCk4EY/Wz1C5gJ4PFtLb8NbXGofECgYEAr506PsEmlItVVoxNuGZ7
vDxyrGD5PUoBtK6r5vOw0w4bQIbsYGOd/Jw1SxJBWuaaCLupveyHE0RaIFBIcHpx
BCNE8LALpvinwpfvJJIlipOv5sUQrx3/SzRmoJO46GtGtztGZVY0XfYpWPRjxxER
EfWMt7ORsbIOW9OSZLCO8AkCgYA1c/HcDOlDF2OwmTzPQ8FtEJABbPv6+18B1bYD
a6PIfGWee4P6HumWRQnGhS+B2QOmfmqFliPZsLanK4ww4tP0qlfHfuqlLufe7R/E
lGqd+wSzNDjF6cUvjJiU28nNUOSh5yYrY6A/DfHm1JihU5LIAqA+0WJdseuF7laC
TbshIQKBgGhwjXS/A0twYMTZwc/H/JGik8yBXK/GZ4BAlIv5hryRmKMbik8sLtEF
Lq/Jt9qsQ6Zob2XZFAi+vZJykvX0ySxngHEOkiHxwyQNQTEfBPifFPkOIKhVKt9t
D4w2FfF4Bai36Wdaa97VXiBBgafIe7z5VDJXRS2HK9SHuYH3kmJu
-----END RSA PRIVATE KEY-----
20 changes: 0 additions & 20 deletions test/fixtures/cacert.pem

This file was deleted.

Loading