Force use of specific SSL version and/or ciphers

I need to overwrite the default behavior of choosing which ssl_version or ciphers are allowed to be negotiated.

There is a 'broken' internal site which accepts TLS v1.0 only. It works with curl and Chrome (who end up selecting TLSv1.0 / DES-CBC3-SHA), but from Python it ends up 'choosing' SSLv3 and you get the error requests.exceptions.SSLError: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:590)

I implemented the overwrite for requests.packages.urllib3.poolmanager as described in http://docs.python-requests.org/en/latest/user/advanced/#example-specific-ssl-version or https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/, but that still does not 'prohibit' the use of SSLv3 and you end up again using it.

I implemented the changes of SSLContext as suggested at http://stackoverflow.com/questions/29153271/sending-tls-1-2-request-in-python-2-6  and this fixes the issue, but I had to directly patch the code in requests.packages.urllib3.connection, since there is no way to overwrite which 'kind' of HTTPSConnection it will instantiate. Or is there a way to do that?

You can create an SSLContext and configure it as needed by using [these instructions](https://lukasa.co.uk/2017/02/Configuring_TLS_With_Requests/). You can set a bunch of `OP_NO` flags to disable everything you don't need. 

Thanks a bunch. The explanation of the '3DES stream cipher' being removed makes sense.

This allowed me to overwrite the context, but it did not work literally (see below what worked). So I guess there is a way to overwrite the context being used. Did I miss some documentation or it is simply my inexperience with Python?

The code that worked for me was the following, effectively I did not overwrite the list of allowed ciphers, but rather disabled SSL v3, which is I guess not part of ssl.create_default_context(). Basically I do not require the ctx.set_ciphers() call


```
FORCED_CIPHERS = (
    'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
    'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES'
)

class DESAdapter(HTTPAdapter):
    """
    A TransportAdapter that re-enables 3DES support in Requests.
    """
    def create_ssl_context(self):
        #ctx = create_urllib3_context(ciphers=FORCED_CIPHERS)
        ctx = ssl.create_default_context()
        # allow TLS 1.0 and TLS 1.2 and later (disable SSLv3 and SSLv2)
        ctx.options |= ssl.OP_NO_SSLv2
        ctx.options |= ssl.OP_NO_SSLv3        
        ctx.set_ciphers( FORCED_CIPHERS )
        return ctx
    
    def init_poolmanager(self, *args, **kwargs):
        logging.debug(' ----------- DESAdapter.init_poolmanager -------------- ')
        kwargs['ssl_context'] = self.create_ssl_context()
        return super(DESAdapter, self).init_poolmanager(*args, **kwargs)

    def proxy_manager_for(self, *args, **kwargs):
        logging.debug(' ----------- DESAdapter.proxy_manager_for -------------- ')
        kwargs['ssl_context'] = self.create_ssl_context()
        return super(DESAdapter, self).proxy_manager_for(*args, **kwargs)

```

Yeah, that code was intended as an example for you to extend rather than as an expected complete solution for you.