diff options
-rw-r--r-- | SConstruct | 1 | ||||
-rw-r--r-- | jstests/libs/trusted-ca.pem | 22 | ||||
-rw-r--r-- | jstests/libs/trusted-client.pem | 49 | ||||
-rw-r--r-- | jstests/libs/trusted-server.pem | 49 | ||||
-rw-r--r-- | jstests/ssl/ssl_with_system_ca.js | 39 | ||||
-rw-r--r-- | src/mongo/shell/shell_options.cpp | 10 | ||||
-rw-r--r-- | src/mongo/shell/shell_options.h | 2 | ||||
-rw-r--r-- | src/mongo/shell/shell_options_init.cpp | 4 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager.cpp | 163 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_manager.h | 10 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.cpp | 13 | ||||
-rw-r--r-- | src/mongo/util/net/ssl_options.h | 6 |
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); } |