summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Reams <jbreams@mongodb.com>2016-03-19 12:29:57 -0400
committerJonathan Reams <jbreams@mongodb.com>2016-04-18 11:01:16 -0400
commit21e94cbb8ae4b348b412aef8e46fd774902ee302 (patch)
tree65b71fd8008cc11820fa9020908b956d465c156d
parent9f3da9f28f1179ff0ee1171b6e714f553e793165 (diff)
downloadmongo-21e94cbb8ae4b348b412aef8e46fd774902ee302.tar.gz
SERVER-23044 Fall back to system CA certs if CA file isn't provided
(cherry picked from commit 6fa3f3c8b5f6592fec3151d124a40ca238a0b2d4)
-rw-r--r--SConstruct1
-rw-r--r--jstests/libs/trusted-ca.pem22
-rw-r--r--jstests/libs/trusted-client.pem49
-rw-r--r--jstests/libs/trusted-server.pem49
-rw-r--r--jstests/ssl/ssl_with_system_ca.js39
-rw-r--r--src/mongo/shell/shell_options.cpp10
-rw-r--r--src/mongo/shell/shell_options.h2
-rw-r--r--src/mongo/shell/shell_options_init.cpp4
-rw-r--r--src/mongo/util/net/ssl_manager.cpp163
-rw-r--r--src/mongo/util/net/ssl_manager.h10
-rw-r--r--src/mongo/util/net/ssl_options.cpp13
-rw-r--r--src/mongo/util/net/ssl_options.h6
12 files changed, 310 insertions, 58 deletions
diff --git a/SConstruct b/SConstruct
index dbf1fb5d824..9c423ff9ba0 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1401,6 +1401,7 @@ elif env.TargetOSIs('windows'):
'Psapi.lib',
'advapi32.lib',
'bcrypt.lib',
+ 'crypt32.lib',
'kernel32.lib',
'shell32.lib',
'version.lib',
diff --git a/jstests/libs/trusted-ca.pem b/jstests/libs/trusted-ca.pem
new file mode 100644
index 00000000000..2a0e139e184
--- /dev/null
+++ b/jstests/libs/trusted-ca.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDpjCCAo6gAwIBAgIDAghHMA0GCSqGSIb3DQEBBQUAMHwxHzAdBgNVBAMTFlRy
+dXN0ZWQgS2VybmVsIFRlc3QgQ0ExDzANBgNVBAsTBktlcm5lbDEQMA4GA1UEChMH
+TW9uZ29EQjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlv
+cmsxCzAJBgNVBAYTAlVTMB4XDTE2MDMzMTE0NTY1NVoXDTM2MDMzMTE0NTY1NVow
+fDEfMB0GA1UEAxMWVHJ1c3RlZCBLZXJuZWwgVGVzdCBDQTEPMA0GA1UECxMGS2Vy
+bmVsMRAwDgYDVQQKEwdNb25nb0RCMRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREw
+DwYDVQQIEwhOZXcgWW9yazELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCePFHZTydC96SlSHSyu73vw//ddaE33kPllBB9DP2L7yRF
+6D/blFmno9fSM+Dfg64VfGV+0pCXPIZbpH29nzJu0DkvHzKiWK7P1zUj8rAHaX++
+d6k0yeTLFM9v+7YE9rHoANVn22aOyDvTgAyMmA0CLn+SmUy6WObwMIf9cZn97Znd
+lww7IeFNyK8sWtfsVN4yRBnjr7kKN2Qo0QmWeFa7jxVQptMJQrY8k1PcyVUOgOjQ
+ocJLbWLlm9k0/OMEQSwQHJ+d9weUbKjlZ9ExOrm4QuuA2tJhb38baTdAYw3Jui4f
+yD6iBAGD0Jkpc+3YaWv6CBmK8NEFkYJD/gn+lJ75AgMBAAGjMTAvMAwGA1UdEwQF
+MAMBAf8wHwYDVR0RBBgwFoIJbG9jYWxob3N0ggkxMjcuMC4wLjEwDQYJKoZIhvcN
+AQEFBQADggEBADYikjB6iwAUs6sglwkE4rOkeMkJdRCNwK/5LpFJTWrDjBvBQCdA
+Y5hlAVq8PfIYeh+wEuSvsEHXmx7W29X2+p4VuJ95/xBA6NLapwtzuiijRj2RBAOG
+1EGuyFQUPTL27DR3+tfayNykDclsVDNN8+l7nt56j8HojP74P5OMHtn+6HX5+mtF
+FfZMTy0mWguCsMOkZvjAskm6s4U5gEC8pYEoC0ZRbfUdyYsxZe/nrXIFguVlVPCB
+XnfB/0iG9t+VH5cUVj1LP9skXTW4kXfhQmljUuo+EVBNR6n2nfTnpoC65WeAgHV4
+V+s9mJsUv2x72KtKYypqEVT0gaJ1WIN9N1s=
+-----END CERTIFICATE-----
diff --git a/jstests/libs/trusted-client.pem b/jstests/libs/trusted-client.pem
new file mode 100644
index 00000000000..dec32375c1b
--- /dev/null
+++ b/jstests/libs/trusted-client.pem
@@ -0,0 +1,49 @@
+-----BEGIN CERTIFICATE-----
+MIIDnTCCAoWgAwIBAgIDA1clMA0GCSqGSIb3DQEBBQUAMHwxHzAdBgNVBAMTFlRy
+dXN0ZWQgS2VybmVsIFRlc3QgQ0ExDzANBgNVBAsTBktlcm5lbDEQMA4GA1UEChMH
+TW9uZ29EQjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlv
+cmsxCzAJBgNVBAYTAlVTMB4XDTE2MDMzMTE2MDY0OVoXDTM2MDMzMTE2MDY0OVow
+gYAxIzAhBgNVBAMTGlRydXN0ZWQgS2VybmVsIFRlc3QgQ2xpZW50MQ8wDQYDVQQL
+EwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIxFjAUBgNVBAcTDU5ldyBZb3JrIENp
+dHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKI9cGBnH5wcthvFT1FdfQTw1EvOgtfBHVEMRFZH
+bupMnAqP69id0bf7SdBWzx4A1f1ws1RkeL5ot2u5T9NwsFzGvRBQ5onFtDnC3eKB
+OwapCk2B82mlx4xZBjewg+NbxoRJBUWGqB0LykaVUHxM6BGgwExNAyXQ9syPSyNZ
+NIr+zDrLdTfjKklmDkv9jSCB/T3t80kQPY+04u98buUe7wGM0WQFbVNoYrSkZ6Ja
+O+G8bpXP4hXIXsxOHucjBeJc1KR+lxEMw3wInZ2KjjMv7HsFIIOQg5pkMDXibSU6
+cNUZTA2MrzZ+t7TeAQyOTzfGlaatfvJYxU7v4u0W5jxeV60CAwEAAaMjMCEwHwYD
+VR0RBBgwFoIJbG9jYWxob3N0ggkxMjcuMC4wLjEwDQYJKoZIhvcNAQEFBQADggEB
+AHI6Rfq/UqAoPxiz5bqby2FnGOrskotgXhn1JkZLGCfllx5WgMuLnu1bvjoym567
+HySqAXQOqEWm6XRU7SVOA+69e4OLWX+HSKjFRuG5Ip67UpihZMgyLKuGRBwfnbXj
+14o+xbWjXCgVZEI7vzT7q/7/W1mXj680fHs93Zog561Id4Tf3DYkOoMawSfeF4iu
+8hcYjlJYjFb3ZvM1wokicmEwtY0+YbBGVo8xh5jYdfCLzYLxc3CpP5eXJtMvGE/x
+RnyiY3f7hkUZMibnREPS6kpQVEh36DT21C0OB8s7TcMU7yMKgVdqL1udmEkiKXTj
+H7v/s+7d54O0tr5+IysCAoA=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEAoj1wYGcfnBy2G8VPUV19BPDUS86C18EdUQxEVkdu6kycCo/r
+2J3Rt/tJ0FbPHgDV/XCzVGR4vmi3a7lP03CwXMa9EFDmicW0OcLd4oE7BqkKTYHz
+aaXHjFkGN7CD41vGhEkFRYaoHQvKRpVQfEzoEaDATE0DJdD2zI9LI1k0iv7MOst1
+N+MqSWYOS/2NIIH9Pe3zSRA9j7Ti73xu5R7vAYzRZAVtU2hitKRnolo74bxulc/i
+FchezE4e5yMF4lzUpH6XEQzDfAidnYqOMy/sewUgg5CDmmQwNeJtJTpw1RlMDYyv
+Nn63tN4BDI5PN8aVpq1+8ljFTu/i7RbmPF5XrQIDAQABAoIBAGg9iYKnP4wSdn+J
+WtkwdC9EfWLnoPH3RlrYwt+crgskhe3TYvmfDSxk7JxL6m+god1hGBfVJi9RIOi5
+/Cwib25s0vU0xasnuBCUv/PUjJRO8Cu0nyz2Myxd1rzZUSQ3x2kfcZ+mUUW4WZLY
+RQpYb5ND8coUgT0+8hOkzeY8XqIe5c4VrX16mA+uoIMsr4QHxe0pl59oY57V3Der
++gsaGuWZ5hDvfuoCOx03Cuc1pTx0T8ZHdliu/xe+np3ETFdQ/1cyJMAJW3w15qKt
+L6AfkeRaMAgqxs2zU1rgPdJddRS7MaSJnpDtMjeyJpeNCMDJ/h3ihgSM1SM1QCtY
+tcnWdIECgYEA1/SVGV9McAvtVtQA1D7kPEo0ifCG8frUfGy2yK9aasFHhLS3JXXY
+4R0Fy/pOwdKNtnN3ZKd0Y0wcmlwPepg2HKlUFJdjqEKZctMzOscy3n08F4AV2rLc
+48q2XLLIQNN/JuqcaeRgQByvP6YL0YuqqsAPiRhTeYgJxp4c+JgbmDUCgYEAwFL7
+jzYwmud3HEgrfpXxDoWpemlKqCqe0cUix0OtR8XfCukZ5lbnC7Mu/FtqBitVdQYd
+2r1nRK66fTJejblNd1E4TG0sIwucI5B24I7XeG78r2kECnFT+vBE8BA6c/y8nTjz
+grWVMeR3n7WFxaTL/VW/kapW2YddWPq1Jh4q4JkCgYB2QBk8kXBbkkxd1Sy3C9ES
+KlfmiGx8KCseDrFv5oUOG9O7mPEIdCVT7v5zmRZzD4ZFt6hS11bl4JFw/KQFLz/C
+Jf5CYDtTsVQxCfDtaJI0PkMfYyWUYYiOuztsOwFobeccOi931HPX510W7yddkKrd
+YNmg6k8bJyCjP4UBotjJWQKBgElP2KDQ0VpbHWZkhF/unEMi5GXLOTA9fukLsqQu
+wiD35nvsO3k4az5kgWalGhdb8Wl4eWzmgjUGPgR3bN+tYUA4b7OCci6xwEU2Tnpv
+OOeptxzOdUHdzVt8t2qjZQTNtMBh80FCIqswIgF5WpLqrO/W/f1y50Roe0bt2pu7
+KDERAoGAbhEL6OCfX6Pf5hCggb4ymm9zmAndRKHAAJ2WQ2p6v+r1vm838n6y8r7Q
+Fqc3B7NIDDYzX4oyQZepOnHNF/UPEyVyGvJ8LBDruyiuAdGakVEvSHZ+ml4LnS06
+msP5hsHh9s4ptVcaF3/mNllBys+FwEWvLewgfVPJrDBNINFvYZ8=
+-----END RSA PRIVATE KEY-----
diff --git a/jstests/libs/trusted-server.pem b/jstests/libs/trusted-server.pem
new file mode 100644
index 00000000000..caaee422a44
--- /dev/null
+++ b/jstests/libs/trusted-server.pem
@@ -0,0 +1,49 @@
+-----BEGIN CERTIFICATE-----
+MIIDnTCCAoWgAwIBAgIDCWhIMA0GCSqGSIb3DQEBBQUAMHwxHzAdBgNVBAMTFlRy
+dXN0ZWQgS2VybmVsIFRlc3QgQ0ExDzANBgNVBAsTBktlcm5lbDEQMA4GA1UEChMH
+TW9uZ29EQjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlv
+cmsxCzAJBgNVBAYTAlVTMB4XDTE2MDMzMTE2MDUyM1oXDTM2MDMzMTE2MDUyM1ow
+gYAxIzAhBgNVBAMTGlRydXN0ZWQgS2VybmVsIFRlc3QgU2VydmVyMQ8wDQYDVQQL
+EwZLZXJuZWwxEDAOBgNVBAoTB01vbmdvREIxFjAUBgNVBAcTDU5ldyBZb3JrIENp
+dHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAJwOsMO+MhWmHcSOdjFrZYjPMOt8uIqJ1pR/JI/E
+hTdUq7fXPHZNhUTzwX1JZB+QkXhnJiAf2ZQOnl7R49vudoPdOZo6bJQP8/Hy5F79
+B8Nw9xrcPuzGBRK3IpY7j9gnAOC5jvN2zh+nHoqNhPmarpKgbDeLosABiDFSHiCE
+degHziJ0Tj0AJ6GRbeHeTvv5K4lLwMzyYnpkG0cMpLvLIUwJa22Vp8PujMcmjX9W
+ASmSXJmcszYKjaRc7HB6ronIEZWy//PSXlvuk8xYaM40HkGy2gN6wV+2Z45QdDds
+NxUuu56TzJ7z7as/vYXXsIc/TSmvM02S01JWUjWeVGc1sb8CAwEAAaMjMCEwHwYD
+VR0RBBgwFoIJbG9jYWxob3N0ggkxMjcuMC4wLjEwDQYJKoZIhvcNAQEFBQADggEB
+AAKLZiQxz3NYvc04GDMRIUDfR50RMw4SuXXgGYTpPUP/akOes11+u5iKhgyKQ+ca
+TttX8mwwvNjQFN8hjBodsrWK9avMUenJBk+Y2ztzLSpKAmC7NUUM6sFB1D3yocsG
+aH5EuyH/dcAdb9z5vYurriRfd1ldmyGAqvA6lKGp1zxTAi0WWbYIZia0LyVoH98p
+x0s+amrSMvkVqIK+qV+CVqW2dNLe+kREjGxzGidCSfHZrHncuTX8/10xHUbAQW0z
+EWF6epmm+jniwgh2Zs/xe7+eY1Nzfq0ly06MVKCs1/lZ0vhAHGZ7V6yBX5zig02x
+VAHb45KqzmYGwKErO7ZFY2I=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAnA6ww74yFaYdxI52MWtliM8w63y4ionWlH8kj8SFN1Srt9c8
+dk2FRPPBfUlkH5CReGcmIB/ZlA6eXtHj2+52g905mjpslA/z8fLkXv0Hw3D3Gtw+
+7MYFErciljuP2CcA4LmO83bOH6ceio2E+ZqukqBsN4uiwAGIMVIeIIR16AfOInRO
+PQAnoZFt4d5O+/kriUvAzPJiemQbRwyku8shTAlrbZWnw+6MxyaNf1YBKZJcmZyz
+NgqNpFzscHquicgRlbL/89JeW+6TzFhozjQeQbLaA3rBX7ZnjlB0N2w3FS67npPM
+nvPtqz+9hdewhz9NKa8zTZLTUlZSNZ5UZzWxvwIDAQABAoIBAQCQFHQY1NHy8OKM
+5aaz697bV8dns0fCCI7HnTdJUPxZYGAGJL8azmmbhp1+qbK5/cSA8GLfx+ge7PxE
+uO3x0RE0n5weC5DRhoUIPeOg22Y+iF5sOyoReqWWaOSS5bzhqOkDke4sU+TsjmQB
+MbWyqaBBmcEv60jAkumF97X++azOIm1EqTXfSu1K7gqtiL9H9T8vIYOOuTAduOsD
+el/v5QQbWb3e/NLhcmzHL6rPcR/9jCn1rJ9HAhAqm6eKZS2cAgTGLLtCUhumVliO
+bEIm2fcQ5h+BDZc5EF/SURKvUaFx/xTIQ5s1oEKN8iN+kIYzgbZ/Ds/GOo7nWVmy
+1KZswK05AoGBANBvT/vSpI7vokmph+GifjToHeinceg3pssf8mHw8xv3H0mZxBkt
+CJq6rFwKwMH8K9tQfBqp4hfVgfdAWZyKqqo1Mtecohzb9D0GLYZ6Of18pAZK/aEt
+L8ADuGYbLAFAS10z4djBSqlud82d194zSgfLP3FYRsj5Ni8w9bPuMOKVAoGBAL+r
+gd1/B+kkbO/NAprjXAFT91Wjf+YMQgM8vOMXlq7LlGeGQSb0zVZpdDtZ3ohqdu1i
+38y0G/CvBLddm8VkC3/fhfO8xW8PjdRBbF87j1k4HerAxcLOO91z+MHFMbUryOJc
+U0aAzJB3B4E491xaXTL8jZLYxmgJtc4jBcLKzmIDAoGBAKXf39w9Hx5tUE6k7vE+
+uodqLdsn3nt6Rm+iRedxtFcODEUrbKbIcu+IHYDGQe5eu5w2af1iMv7auCpHeMke
+hYEdAxAZo92poa4qy3IYtSuo1HP5m+x3pGd/znDbsOJyA0fx8QrpkHxT4F2u/srj
+MEgRlLSkFvj7cwaNRQvjQ94dAoGAA2+4wVbgtm5fwaDkVhCTeradrZxj06UOne49
+2Lh4jCO8QmrmyiMDd3QmkFXZJor6HOFz78Ce657Hr93uyAg2KJHCXg9ZXtdhjJer
+sL1poYjfCHFyWj7GVf8ZS6gUbxIc5OoQ2CfBAyoPKWLzFGXOW/apNyPJ0t2xs8Nu
+/AIU1y8CgYEAyUhyJe8XaDOjoR9D1freHY6Vt9NkofDpYfWL4+y/kGD45yCDBXj0
+LYAD89/Qog1MbPN8FGrgMu2b3dI0i+iZlWduvQRn71QepT6wiB84ivxjECSpZGoH
+2F0SM1MVAK/f4Dm9H9Kaukq2BpsN8Uhvzg2EUFg1mLJ+OBArgT524Ys=
+-----END RSA PRIVATE KEY-----
diff --git a/jstests/ssl/ssl_with_system_ca.js b/jstests/ssl/ssl_with_system_ca.js
new file mode 100644
index 00000000000..cdb7f71ea82
--- /dev/null
+++ b/jstests/ssl/ssl_with_system_ca.js
@@ -0,0 +1,39 @@
+((function() {
+ 'use strict';
+ const HOST_TYPE = getBuildInfo().buildEnvironment.target_os;
+
+ if (HOST_TYPE == "windows") {
+ runProgram(
+ "certutil.exe", "-addstore", "-user", "-f", "CA", "jstests\\libs\\trusted-ca.pem");
+ }
+
+ var testWithCerts = function(serverPem) {
+ jsTest.log(`Testing with SSL certs $ {
+ serverPem
+ }`);
+ // allowSSL instead of requireSSL so that the non-SSL connection succeeds.
+ var conn = MongoRunner.runMongod(
+ {sslMode: 'requireSSL', sslPEMKeyFile: "jstests/libs/" + serverPem});
+
+ // Should not be able to authenticate with x509.
+ // Authenticate call will return 1 on success, 0 on error.
+ var argv =
+ ['./mongo', '--ssl', '--port', conn.port, '--eval', ('db.runCommand({buildInfo: 1})')];
+ if (HOST_TYPE != "windows") {
+ // On Linux we override the default path to the system CA store to point to our
+ // "trusted" CA. On Windows, this CA will have been added to the user's trusted CA list
+ argv.unshift("env", "SSL_CERT_FILE=jstests/libs/trusted-ca.pem");
+ }
+ var exitStatus = runMongoProgram.apply(null, argv);
+ assert.eq(exitStatus, 0, "successfully connected with SSL");
+
+ MongoRunner.stopMongod(conn.port);
+ };
+
+ assert.throws(function() {
+ testWithCerts("server.pem", "client.pem");
+ });
+ assert.doesNotThrow(function() {
+ testWithCerts("trusted-server.pem", "trusted-client.pem");
+ });
+})());
diff --git a/src/mongo/shell/shell_options.cpp b/src/mongo/shell/shell_options.cpp
index 0ff0d8963ef..c5d5dd09487 100644
--- a/src/mongo/shell/shell_options.cpp
+++ b/src/mongo/shell/shell_options.cpp
@@ -380,14 +380,4 @@ Status storeMongoShellOptions(const moe::Environment& params,
return Status::OK();
}
-
-Status validateMongoShellOptions(const moe::Environment& params) {
-#ifdef MONGO_CONFIG_SSL
- Status ret = validateSSLMongoShellOptions(params);
- if (!ret.isOK()) {
- return ret;
- }
-#endif
- return Status::OK();
-}
}
diff --git a/src/mongo/shell/shell_options.h b/src/mongo/shell/shell_options.h
index 513abec8211..a163ca2a8db 100644
--- a/src/mongo/shell/shell_options.h
+++ b/src/mongo/shell/shell_options.h
@@ -97,6 +97,4 @@ bool handlePreValidationMongoShellOptions(const moe::Environment& params,
const std::vector<std::string>& args);
Status storeMongoShellOptions(const moe::Environment& params, const std::vector<std::string>& args);
-
-Status validateMongoShellOptions(const moe::Environment& params);
}
diff --git a/src/mongo/shell/shell_options_init.cpp b/src/mongo/shell/shell_options_init.cpp
index ff6c0792ca5..e1374ec4691 100644
--- a/src/mongo/shell/shell_options_init.cpp
+++ b/src/mongo/shell/shell_options_init.cpp
@@ -47,10 +47,6 @@ MONGO_STARTUP_OPTIONS_VALIDATE(MongoShellOptions)(InitializerContext* context) {
if (!ret.isOK()) {
return ret;
}
- ret = validateMongoShellOptions(moe::startupOptionsParsed);
- if (!ret.isOK()) {
- return ret;
- }
return Status::OK();
}
diff --git a/src/mongo/util/net/ssl_manager.cpp b/src/mongo/util/net/ssl_manager.cpp
index e1cca289a99..9ceb7533866 100644
--- a/src/mongo/util/net/ssl_manager.cpp
+++ b/src/mongo/util/net/ssl_manager.cpp
@@ -59,6 +59,12 @@
#ifdef MONGO_CONFIG_SSL
#include <openssl/evp.h>
#include <openssl/x509v3.h>
+
+#ifdef _WIN32
+#include <openssl/x509_vfy.h>
+#include <openssl/pkcs7.h>
+#include <wincrypt.h>
+#endif
#endif
using std::endl;
@@ -269,7 +275,12 @@ private:
/*
* Set up an SSL context for certificate validation by loading a CA
*/
- bool _setupCA(SSL_CTX* context, const std::string& caFile);
+ Status _setupCA(SSL_CTX* context, const std::string& caFile);
+
+ /*
+ * Set up an SSL context for certificate validation by loading the system's CA store
+ */
+ Status _setupSystemCA(SSL_CTX* context);
/*
* Import a certificate revocation list into an SSL context
@@ -631,12 +642,10 @@ Status SSLManager::initSSLContext(SSL_CTX* context,
}
}
- if (!params.sslCAFile.empty()) {
- // Set up certificate validation with a certificate authority
- if (!_setupCA(context, params.sslCAFile)) {
- return Status(ErrorCodes::InvalidSSLConfiguration, "Can not set up CA file.");
- }
- }
+ const auto status =
+ params.sslCAFile.empty() ? _setupSystemCA(context) : _setupCA(context, params.sslCAFile);
+ if (!status.isOK())
+ return status;
if (!params.sslCRLFile.empty()) {
if (!_setupCRL(context, params.sslCRLFile)) {
@@ -779,27 +788,148 @@ bool SSLManager::_setupPEM(SSL_CTX* context,
return true;
}
-bool SSLManager::_setupCA(SSL_CTX* context, const std::string& caFile) {
+Status SSLManager::_setupCA(SSL_CTX* context, const std::string& caFile) {
// Set the list of CAs sent to clients
STACK_OF(X509_NAME)* certNames = SSL_load_client_CA_file(caFile.c_str());
if (certNames == NULL) {
- error() << "cannot read certificate authority file: " << caFile << " "
- << getSSLErrorMessage(ERR_get_error()) << endl;
- return false;
+ return Status(ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "cannot read certificate authority file: " << caFile << " "
+ << getSSLErrorMessage(ERR_get_error()));
}
SSL_CTX_set_client_CA_list(context, certNames);
// Load trusted CA
if (SSL_CTX_load_verify_locations(context, caFile.c_str(), NULL) != 1) {
- error() << "cannot read certificate authority file: " << caFile << " "
- << getSSLErrorMessage(ERR_get_error()) << endl;
- return false;
+ return Status(ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "cannot read certificate authority file: " << caFile << " "
+ << getSSLErrorMessage(ERR_get_error()));
}
+
// Set SSL to require peer (client) certificate verification
// if a certificate is presented
SSL_CTX_set_verify(context, SSL_VERIFY_PEER, &SSLManager::verify_cb);
_sslConfiguration.hasCA = true;
- return true;
+ return Status::OK();
+}
+
+#ifdef _WIN32
+// This imports the certificates in a given Windows certificate store into an X509_STORE for
+// openssl to use during certificate validation.
+Status importCertStoreToX509_STORE(LPWSTR storeName, DWORD storeLocation, X509_STORE* verifyStore) {
+ HCERTSTORE systemStore =
+ CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, NULL, storeLocation, storeName);
+ if (systemStore == NULL) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "error opening system CA store: " << errnoWithDescription()};
+ }
+ auto systemStoreGuard = MakeGuard([systemStore]() { CertCloseStore(systemStore, 0); });
+
+ CERT_BLOB p7Data = {0, NULL};
+ // We call this the first time to get the size of the PKCS7 object that will be generated
+ if (CertSaveStore(systemStore,
+ (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING), // Save it as X509 certs/CRLs
+ // encoded as PKCS7 objects
+ CERT_STORE_SAVE_AS_PKCS7, // Save as a PKCS7 encoded object
+ CERT_STORE_SAVE_TO_MEMORY, // Save cert store to memory
+ &p7Data,
+ 0) == 0) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "error getting size of PKCS7 object from system CA store"
+ << errnoWithDescription()};
+ }
+
+ std::unique_ptr<BYTE[]> pbDataPtr(new BYTE[p7Data.cbData]);
+ p7Data.pbData = pbDataPtr.get();
+
+ // Then we call it again to actually create the PKCS7 object.
+ if (CertSaveStore(systemStore,
+ (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING), // Save it as X509 certs/CRLs
+ // encoded as PKCS7 objects
+ CERT_STORE_SAVE_AS_PKCS7, // Save as a PKCS7 encoded object
+ CERT_STORE_SAVE_TO_MEMORY, // Save cert store to memory
+ &p7Data,
+ 0) == 0) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "error getting system CA store: " << errnoWithDescription()};
+ }
+
+ auto bioDeleter = [](BIO* b) { BIO_free_all(b); };
+ std::unique_ptr<BIO, decltype(bioDeleter)> p7Bio(BIO_new_mem_buf(p7Data.pbData, p7Data.cbData),
+ bioDeleter);
+ if (!p7Bio) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ "error creating BIO for loading system CA cert store"};
+ }
+ BIO_set_close(p7Bio.get(), BIO_NOCLOSE);
+
+ auto pkcs7Deleter = [](PKCS7* p) { PKCS7_free(p); };
+ std::unique_ptr<PKCS7, decltype(pkcs7Deleter)> p7(d2i_PKCS7_bio(p7Bio.get(), NULL),
+ pkcs7Deleter);
+ if (!p7) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ "error parsing PKCS7 object from system CA cert store"};
+ }
+
+ if ((OBJ_obj2nid(p7->type) != NID_pkcs7_signed) || (p7->d.sign->cert == NULL)) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ "invalid pkcs7 object while loading system certificates"};
+ }
+
+ STACK_OF(X509)* systemCACerts = p7->d.sign->cert;
+ for (auto i = 0; i < sk_X509_num(systemCACerts); i++) {
+ if (X509_STORE_add_cert(verifyStore, sk_X509_value(systemCACerts, i)) != 1) {
+ const auto errCode = ERR_peek_last_error();
+ if (ERR_GET_LIB(errCode) != ERR_LIB_X509 ||
+ ERR_GET_REASON(errCode) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "Error adding certificate to X509 store: "
+ << ERR_reason_error_string(errCode)};
+ }
+ }
+ }
+
+ STACK_OF(X509_CRL)* systemCRLs = p7->d.sign->crl;
+ for (auto i = 0; i < sk_X509_CRL_num(systemCRLs); i++) {
+ if (X509_STORE_add_crl(verifyStore, sk_X509_CRL_value(systemCRLs, i)) != 1) {
+ const auto errCode = ERR_peek_last_error();
+ if (ERR_GET_LIB(errCode) != ERR_LIB_X509 ||
+ ERR_GET_REASON(errCode) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "Error adding CRL to X509 store: "
+ << ERR_reason_error_string(errCode)};
+ }
+ }
+ }
+
+ return Status::OK();
+}
+#endif
+
+Status SSLManager::_setupSystemCA(SSL_CTX* context) {
+#ifndef _WIN32
+ // On non-Windows platforms, the OpenSSL libraries should have been configured with default
+ // locations for CA certificates.
+ if (SSL_CTX_set_default_verify_paths(context) != 1) {
+ return {
+ ErrorCodes::InvalidSSLConfiguration,
+ str::stream() << "error loading system CA certificates "
+ << "(default certificate file: " << X509_get_default_cert_file() << ", "
+ << "default certificate path: " << X509_get_default_cert_dir() << ")"};
+ }
+ return Status::OK();
+#else
+
+ X509_STORE* verifyStore = SSL_CTX_get_cert_store(context);
+ if (!verifyStore) {
+ return {ErrorCodes::InvalidSSLConfiguration,
+ "no X509 store found for SSL context while loading system certificates"};
+ }
+
+ auto status = importCertStoreToX509_STORE(L"root", CERT_SYSTEM_STORE_CURRENT_USER, verifyStore);
+ if (!status.isOK())
+ return status;
+ return importCertStoreToX509_STORE(L"CA", CERT_SYSTEM_STORE_CURRENT_USER, verifyStore);
+#endif
}
bool SSLManager::_setupCRL(SSL_CTX* context, const std::string& crlFile) {
@@ -933,8 +1063,7 @@ bool SSLManager::_hostNameMatch(const char* nameToMatch, const char* certHostNam
StatusWith<boost::optional<std::string>> SSLManager::parseAndValidatePeerCertificate(
SSL* conn, const std::string& remoteHost) {
- // only set if a CA cert has been provided
- if (!_sslConfiguration.hasCA)
+ if (!_sslConfiguration.hasCA && isSSLServer)
return {boost::none};
X509* peerCert = SSL_get_peer_certificate(conn);
diff --git a/src/mongo/util/net/ssl_manager.h b/src/mongo/util/net/ssl_manager.h
index d539cb15efd..ea3802ef67e 100644
--- a/src/mongo/util/net/ssl_manager.h
+++ b/src/mongo/util/net/ssl_manager.h
@@ -70,22 +70,20 @@ public:
};
struct SSLConfiguration {
- SSLConfiguration() : serverSubjectName(""), clientSubjectName(""), hasCA(false) {}
+ SSLConfiguration() : serverSubjectName(""), clientSubjectName("") {}
SSLConfiguration(const std::string& serverSubjectName,
const std::string& clientSubjectName,
- const Date_t& serverCertificateExpirationDate,
- bool hasCA)
+ const Date_t& serverCertificateExpirationDate)
: serverSubjectName(serverSubjectName),
clientSubjectName(clientSubjectName),
- serverCertificateExpirationDate(serverCertificateExpirationDate),
- hasCA(hasCA) {}
+ serverCertificateExpirationDate(serverCertificateExpirationDate) {}
bool isClusterMember(StringData subjectName) const;
BSONObj getServerStatusBSON() const;
std::string serverSubjectName;
std::string clientSubjectName;
Date_t serverCertificateExpirationDate;
- bool hasCA;
+ bool hasCA = false;
};
class SSLManagerInterface {
diff --git a/src/mongo/util/net/ssl_options.cpp b/src/mongo/util/net/ssl_options.cpp
index 650c0a7495e..2d29e4704f2 100644
--- a/src/mongo/util/net/ssl_options.cpp
+++ b/src/mongo/util/net/ssl_options.cpp
@@ -312,9 +312,6 @@ Status storeSSLServerOptions(const moe::Environment& params) {
if (sslGlobalParams.sslPEMKeyFile.size() == 0) {
return Status(ErrorCodes::BadValue, "need sslPEMKeyFile when SSL is enabled");
}
- if (sslGlobalParams.sslWeakCertificateValidation && sslGlobalParams.sslCAFile.empty()) {
- return Status(ErrorCodes::BadValue, "need sslCAFile with sslWeakCertificateValidation");
- }
if (!sslGlobalParams.sslCRLFile.empty() && sslGlobalParams.sslCAFile.empty()) {
return Status(ErrorCodes::BadValue, "need sslCAFile with sslCRLFile");
}
@@ -385,14 +382,4 @@ Status storeSSLClientOptions(const moe::Environment& params) {
return Status::OK();
}
-Status validateSSLMongoShellOptions(const moe::Environment& params) {
- // Users must specify either a CAFile or allowInvalidCertificates if ssl=true.
- if (params.count("ssl") && params["ssl"].as<bool>() == true && !params.count("ssl.CAFile") &&
- !params.count("ssl.allowInvalidCertificates")) {
- return Status(ErrorCodes::BadValue,
- "need to either provide sslCAFile or specify sslAllowInvalidCertificates");
- }
- return Status::OK();
-}
-
} // namespace mongo
diff --git a/src/mongo/util/net/ssl_options.h b/src/mongo/util/net/ssl_options.h
index c5e39908bef..e897656ed25 100644
--- a/src/mongo/util/net/ssl_options.h
+++ b/src/mongo/util/net/ssl_options.h
@@ -103,10 +103,4 @@ Status canonicalizeSSLServerOptions(moe::Environment* params);
Status validateSSLServerOptions(const moe::Environment& params);
Status storeSSLClientOptions(const moe::Environment& params);
-
-/**
- * Used by the Mongo shell to validate that the SSL options passed are acceptable and
- * do not conflict with one another.
- */
-Status validateSSLMongoShellOptions(const moe::Environment& params);
}