def kms_request(self, kms_context): """Complete a KMS request. :Parameters: - `kms_context`: A :class:`MongoCryptKmsContext`. :Returns: None """ endpoint = kms_context.endpoint message = kms_context.message host, port = parse_host(endpoint, _HTTPS_PORT) # Enable strict certificate verification, OCSP, match hostname, and # SNI using the system default CA certificates. ctx = get_ssl_context( None, # certfile None, # keyfile None, # passphrase None, # ca_certs CERT_REQUIRED, # cert_reqs None, # crlfile True, # match_hostname True) # check_ocsp_endpoint opts = PoolOptions(connect_timeout=_KMS_CONNECT_TIMEOUT, socket_timeout=_KMS_CONNECT_TIMEOUT, ssl_context=ctx) conn = _configured_socket((host, port), opts) try: conn.sendall(message) while kms_context.bytes_needed > 0: data = conn.recv(kms_context.bytes_needed) kms_context.feed(data) finally: conn.close()
def _parse_ssl_options(options): """Parse ssl options.""" use_ssl = options.get('ssl') if use_ssl is not None: validate_boolean('ssl', use_ssl) certfile = options.get('ssl_certfile') keyfile = options.get('ssl_keyfile') passphrase = options.get('ssl_pem_passphrase') ca_certs = options.get('ssl_ca_certs') cert_reqs = options.get('ssl_cert_reqs') match_hostname = options.get('ssl_match_hostname', True) crlfile = options.get('ssl_crlfile') ssl_kwarg_keys = [k for k in options if k.startswith('ssl_') and options[k]] if use_ssl == False and ssl_kwarg_keys: raise ConfigurationError("ssl has not been enabled but the " "following ssl parameters have been set: " "%s. Please set `ssl=True` or remove." % ', '.join(ssl_kwarg_keys)) if ssl_kwarg_keys and use_ssl is None: # ssl options imply ssl = True use_ssl = True if use_ssl is True: ctx = get_ssl_context( certfile, keyfile, passphrase, ca_certs, cert_reqs, crlfile) return ctx, match_hostname return None, match_hostname
def _parse_ssl_options(options): """Parse ssl options.""" use_ssl = options.get('ssl') if use_ssl is not None: validate_boolean('ssl', use_ssl) certfile = options.get('ssl_certfile') keyfile = options.get('ssl_keyfile') ca_certs = options.get('ssl_ca_certs') cert_reqs = options.get('ssl_cert_reqs') match_hostname = options.get('ssl_match_hostname', True) ssl_kwarg_keys = [k for k in options if k.startswith('ssl_') and options[k]] if use_ssl == False and ssl_kwarg_keys: raise ConfigurationError("ssl has not been enabled but the " "following ssl parameters have been set: " "%s. Please set `ssl=True` or remove." % ', '.join(ssl_kwarg_keys)) if cert_reqs and not ca_certs: raise ConfigurationError("If `ssl_cert_reqs` is not " "`ssl.CERT_NONE` then you must " "include `ssl_ca_certs` to be able " "to validate the server.") if ssl_kwarg_keys and use_ssl is None: # ssl options imply ssl = True use_ssl = True if use_ssl is True: ctx = get_ssl_context(certfile, keyfile, ca_certs, cert_reqs) return ctx, match_hostname return None, match_hostname
def _parse_ssl_options(options): """Parse ssl options.""" use_ssl = options.get('ssl') if use_ssl is not None: validate_boolean('ssl', use_ssl) certfile = options.get('ssl_certfile') keyfile = options.get('ssl_keyfile') passphrase = options.get('ssl_pem_passphrase') ca_certs = options.get('ssl_ca_certs') cert_reqs = options.get('ssl_cert_reqs') match_hostname = options.get('ssl_match_hostname', True) crlfile = options.get('ssl_crlfile') check_ocsp_endpoint = options.get('ssl_check_ocsp_endpoint', True) ssl_kwarg_keys = [ k for k in options if k.startswith('ssl_') and options[k] ] if use_ssl is False and ssl_kwarg_keys: raise ConfigurationError("ssl has not been enabled but the " "following ssl parameters have been set: " "%s. Please set `ssl=True` or remove." % ', '.join(ssl_kwarg_keys)) if ssl_kwarg_keys and use_ssl is None: # ssl options imply ssl = True use_ssl = True if use_ssl is True: ctx = get_ssl_context(certfile, keyfile, passphrase, ca_certs, cert_reqs, crlfile, match_hostname, check_ocsp_endpoint) return ctx, match_hostname return None, match_hostname
def _parse_ssl_options(options): """Parse ssl options.""" use_tls = options.get("tls") if use_tls is not None: validate_boolean("tls", use_tls) certfile = options.get("tlscertificatekeyfile") passphrase = options.get("tlscertificatekeyfilepassword") ca_certs = options.get("tlscafile") crlfile = options.get("tlscrlfile") allow_invalid_certificates = options.get("tlsallowinvalidcertificates", False) allow_invalid_hostnames = options.get("tlsallowinvalidhostnames", False) disable_ocsp_endpoint_check = options.get("tlsdisableocspendpointcheck", False) enabled_tls_opts = [] for opt in ( "tlscertificatekeyfile", "tlscertificatekeyfilepassword", "tlscafile", "tlscrlfile", ): # Any non-null value of these options implies tls=True. if opt in options and options[opt]: enabled_tls_opts.append(opt) for opt in ( "tlsallowinvalidcertificates", "tlsallowinvalidhostnames", "tlsdisableocspendpointcheck", ): # A value of False for these options implies tls=True. if opt in options and not options[opt]: enabled_tls_opts.append(opt) if enabled_tls_opts: if use_tls is None: # Implicitly enable TLS when one of the tls* options is set. use_tls = True elif not use_tls: # Error since tls is explicitly disabled but a tls option is set. raise ConfigurationError("TLS has not been enabled but the " "following tls parameters have been set: " "%s. Please set `tls=True` or remove." % ", ".join(enabled_tls_opts)) if use_tls: ctx = get_ssl_context( certfile, passphrase, ca_certs, crlfile, allow_invalid_certificates, allow_invalid_hostnames, disable_ocsp_endpoint_check, ) return ctx, allow_invalid_hostnames return None, allow_invalid_hostnames
def test_wincertstore(self): if sys.platform != "win32": raise SkipTest("Only valid on Windows.") if hasattr(ssl, "SSLContext"): # SSLSocket doesn't provide ca_certs attribute on pythons # with SSLContext and SSLContext provides no information # about ca_certs. raise SkipTest("Can't test when SSLContext available.") if not ssl_support.HAVE_WINCERTSTORE: raise SkipTest("Need wincertstore to test wincertstore.") ctx = get_ssl_context(None, None, CA_PEM, ssl.CERT_REQUIRED) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, CA_PEM) ctx = get_ssl_context(None, None, None, None) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, ssl_support._WINCERTS.name)
def test_wincertstore(self): if sys.platform != "win32": raise SkipTest("Only valid on Windows.") if hasattr(ssl, "SSLContext"): # SSLSocket doesn't provide ca_certs attribute on pythons # with SSLContext and SSLContext provides no information # about ca_certs. raise SkipTest("Can't test when SSLContext available.") if not ssl_support.HAVE_WINCERTSTORE: raise SkipTest("Need wincertstore to test wincertstore.") ctx = get_ssl_context(None, None, None, CA_PEM, ssl.CERT_REQUIRED, None) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, CA_PEM) ctx = get_ssl_context(None, None, None, None, None, None) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, ssl_support._WINCERTS.name)
def test_certifi_support(self): if hasattr(ssl, "SSLContext"): # SSLSocket doesn't provide ca_certs attribute on pythons # with SSLContext and SSLContext provides no information # about ca_certs. raise SkipTest("Can't test when SSLContext available.") if not ssl_support.HAVE_CERTIFI: raise SkipTest("Need certifi to test certifi support.") have_wincertstore = ssl_support.HAVE_WINCERTSTORE # Force the test on Windows, regardless of environment. ssl_support.HAVE_WINCERTSTORE = False try: ctx = get_ssl_context(None, None, CA_PEM, ssl.CERT_REQUIRED) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, CA_PEM) ctx = get_ssl_context(None, None, None, None) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, ssl_support.certifi.where()) finally: ssl_support.HAVE_WINCERTSTORE = have_wincertstore
def test_certifi_support(self): if hasattr(ssl, "SSLContext"): # SSLSocket doesn't provide ca_certs attribute on pythons # with SSLContext and SSLContext provides no information # about ca_certs. raise SkipTest("Can't test when SSLContext available.") if not ssl_support.HAVE_CERTIFI: raise SkipTest("Need certifi to test certifi support.") have_wincertstore = ssl_support.HAVE_WINCERTSTORE # Force the test on Windows, regardless of environment. ssl_support.HAVE_WINCERTSTORE = False try: ctx = get_ssl_context(None, None, None, CA_PEM, ssl.CERT_REQUIRED, None) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, CA_PEM) ctx = get_ssl_context(None, None, None, None, None, None) ssl_sock = ctx.wrap_socket(socket.socket()) self.assertEqual(ssl_sock.ca_certs, ssl_support.certifi.where()) finally: ssl_support.HAVE_WINCERTSTORE = have_wincertstore
def test_system_certs_config_error(self): ctx = get_ssl_context(None, None, None, None, ssl.CERT_NONE, None) if ((sys.platform != "win32" and hasattr(ctx, "set_default_verify_paths")) or hasattr(ctx, "load_default_certs")): raise SkipTest( "Can't test when system CA certificates are loadable.") have_certifi = ssl_support.HAVE_CERTIFI have_wincertstore = ssl_support.HAVE_WINCERTSTORE # Force the test regardless of environment. ssl_support.HAVE_CERTIFI = False ssl_support.HAVE_WINCERTSTORE = False try: with self.assertRaises(ConfigurationError): MongoClient("mongodb://localhost/?ssl=true") finally: ssl_support.HAVE_CERTIFI = have_certifi ssl_support.HAVE_WINCERTSTORE = have_wincertstore
def check_ocsp(host, port, capath): ctx = get_ssl_context( None, # certfile None, # passphrase capath, # ca_certs None, # crlfile False, # allow_invalid_certificates False, # allow_invalid_hostnames False) # disable_ocsp_endpoint_check # Ensure we're using pyOpenSSL. assert isinstance(ctx, SSLContext) s = socket.socket() s.connect((host, port)) try: s = ctx.wrap_socket(s, server_hostname=host) finally: s.close()
def test_system_certs_config_error(self): ctx = get_ssl_context(None, None, None, ssl.CERT_NONE) if ((sys.platform != "win32" and hasattr(ctx, "set_default_verify_paths")) or hasattr(ctx, "load_default_certs")): raise SkipTest( "Can't test when system CA certificates are loadable.") have_certifi = ssl_support.HAVE_CERTIFI have_wincertstore = ssl_support.HAVE_WINCERTSTORE # Force the test regardless of environment. ssl_support.HAVE_CERTIFI = False ssl_support.HAVE_WINCERTSTORE = False try: with self.assertRaises(ConfigurationError): MongoClient("mongodb://localhost/?ssl=true") finally: ssl_support.HAVE_CERTIFI = have_certifi ssl_support.HAVE_WINCERTSTORE = have_wincertstore
def check_ocsp(host, port, capath): ctx = get_ssl_context( None, # certfile None, # keyfile None, # passphrase capath, CERT_REQUIRED, None, # crlfile True, # match_hostname True) # check_ocsp_endpoint # Ensure we're using pyOpenSSL. assert isinstance(ctx, SSLContext) s = socket.socket() s.connect((host, port)) try: s = ctx.wrap_socket(s, server_hostname=host) finally: s.close()
def kms_request(self, kms_context): """Complete a KMS request. :Parameters: - `kms_context`: A :class:`MongoCryptKmsContext`. :Returns: None """ endpoint = kms_context.endpoint message = kms_context.message ctx = get_ssl_context(None, None, None, None, None, None, True) opts = PoolOptions(connect_timeout=_KMS_CONNECT_TIMEOUT, socket_timeout=_KMS_CONNECT_TIMEOUT, ssl_context=ctx) with _configured_socket((endpoint, _HTTPS_PORT), opts) as conn: conn.sendall(message) while kms_context.bytes_needed > 0: data = conn.recv(kms_context.bytes_needed) kms_context.feed(data)
def kms_request(self, kms_context): """Complete a KMS request. :Parameters: - `kms_context`: A :class:`MongoCryptKmsContext`. :Returns: None """ endpoint = kms_context.endpoint message = kms_context.message provider = kms_context.kms_provider ctx = self.opts._kms_ssl_contexts.get(provider) if ctx is None: # Enable strict certificate verification, OCSP, match hostname, and # SNI using the system default CA certificates. ctx = get_ssl_context( None, # certfile None, # passphrase None, # ca_certs None, # crlfile False, # allow_invalid_certificates False, # allow_invalid_hostnames False, ) # disable_ocsp_endpoint_check opts = PoolOptions( connect_timeout=_KMS_CONNECT_TIMEOUT, socket_timeout=_KMS_CONNECT_TIMEOUT, ssl_context=ctx, ) host, port = parse_host(endpoint, _HTTPS_PORT) conn = _configured_socket((host, port), opts) try: conn.sendall(message) while kms_context.bytes_needed > 0: data = conn.recv(kms_context.bytes_needed) if not data: raise OSError("KMS connection closed") kms_context.feed(data) finally: conn.close()
def test_cert_ssl_validation_hostname_matching(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem ctx = get_ssl_context(None, None, None, None, True, True, False) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context(None, None, None, None, True, False, False) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context(None, None, None, None, False, True, False) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context(None, None, None, None, False, False, False) if _PY37PLUS or _HAVE_PYOPENSSL: self.assertTrue(ctx.check_hostname) else: self.assertFalse(ctx.check_hostname) response = self.client.admin.command(HelloCompat.LEGACY_CMD) with self.assertRaises(ConnectionFailure): connected( MongoClient('server', ssl=True, tlsCertificateKeyFile=CLIENT_PEM, tlsAllowInvalidCertificates=False, tlsCAFile=CA_PEM, serverSelectionTimeoutMS=500, **self.credentials)) connected( MongoClient('server', ssl=True, tlsCertificateKeyFile=CLIENT_PEM, tlsAllowInvalidCertificates=False, tlsCAFile=CA_PEM, tlsAllowInvalidHostnames=True, serverSelectionTimeoutMS=500, **self.credentials)) if 'setName' in response: with self.assertRaises(ConnectionFailure): connected( MongoClient('server', replicaSet=response['setName'], ssl=True, tlsCertificateKeyFile=CLIENT_PEM, tlsAllowInvalidCertificates=False, tlsCAFile=CA_PEM, serverSelectionTimeoutMS=500, **self.credentials)) connected( MongoClient('server', replicaSet=response['setName'], ssl=True, tlsCertificateKeyFile=CLIENT_PEM, tlsAllowInvalidCertificates=False, tlsCAFile=CA_PEM, tlsAllowInvalidHostnames=True, serverSelectionTimeoutMS=500, **self.credentials))
def test_cert_ssl_validation_hostname_matching(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem ctx = get_ssl_context(None, None, None, None, ssl.CERT_NONE, None, False, True) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context(None, None, None, None, ssl.CERT_NONE, None, True, True) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context(None, None, None, None, ssl.CERT_REQUIRED, None, False, True) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context(None, None, None, None, ssl.CERT_REQUIRED, None, True, True) if _PY37PLUS or _HAVE_PYOPENSSL: self.assertTrue(ctx.check_hostname) else: self.assertFalse(ctx.check_hostname) response = self.client.admin.command('ismaster') with self.assertRaises(ConnectionFailure): connected( MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=500, **self.credentials)) connected( MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=500, **self.credentials)) if 'setName' in response: with self.assertRaises(ConnectionFailure): connected( MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=500, **self.credentials)) connected( MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=500, **self.credentials))
def test_cert_ssl_validation_hostname_matching(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # Python > 2.7.9. If SSLContext doesn't have load_default_certs # it also doesn't have check_hostname. ctx = get_ssl_context( None, None, None, None, ssl.CERT_NONE, None, False) if hasattr(ctx, 'load_default_certs'): self.assertFalse(ctx.check_hostname) ctx = get_ssl_context( None, None, None, None, ssl.CERT_NONE, None, True) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context( None, None, None, None, ssl.CERT_REQUIRED, None, False) self.assertFalse(ctx.check_hostname) ctx = get_ssl_context( None, None, None, None, ssl.CERT_REQUIRED, None, True) if _PY37PLUS: self.assertTrue(ctx.check_hostname) else: self.assertFalse(ctx.check_hostname) response = self.client.admin.command('ismaster') with self.assertRaises(ConnectionFailure): connected(MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=500, **self.credentials)) connected(MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=500, **self.credentials)) if 'setName' in response: with self.assertRaises(ConnectionFailure): connected(MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=500, **self.credentials)) connected(MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=500, **self.credentials))