How do I disable SSLv3 in Thin? - thin

Is there a way to prevent Thin from accepting requests using SSLv3?
I cannot find any resources on how to deal with Poodle for a Thin server running with SSL. I don't want to move thin behind nginx if I don't have to so any resources would be helpful. I took a look at the source code but couldn't find a way to monkey patch it, can't even find a reference to it.

Thin uses eventmachine, so the solution involves making eventmachine not use SSLv2 or v3.
This discussion has some insights on a generic patch
https://github.com/eventmachine/eventmachine/issues/359
Another option is to build eventmachine with a patch to disable
(https://github.com/eventmachine/eventmachine/wiki/Building-EventMachine)
and then a patch of
--- a/ext/ssl.cpp
+++ b/ext/ssl.cpp
## -145,7 +145,7 ## SslContext_t::SslContext_t (bool is_server, const string &privkeyfile, const str
}
bIsServer = is_server;
- pCtx = SSL_CTX_new (is_server ? SSLv23_server_method() : SSLv23_client_method());
+ pCtx = SSL_CTX_new (is_server ? TLSv1_server_method() : TLSv1_client_method());
if (!pCtx)
throw std::runtime_error ("no SSL context");
I haven't been able to get it fully tested, but this command should fail:
openssl s_client -connect 127.0.0.1:3000 -ssl3

Related

WebSocketpp handshake issue with TLS

I have been learning with WebSocket++ and built some of the server examples (Windows 10 Visual Studio 2019). The non-TLS examples work without issues, however, the TLS-enabled examples (echo_server_both.cpp and echo_server_tls.cpp) can't do the handshake. I am very new to web development in general so I know I must be doing something wrong with regards to the certificate and keys.
I am testing the servers with WebSocket King client, an extension of Google Chrome that connects correctly to other websocket servers like wss://echo.websocket.org and to my own localhost when I don't use TLS.
The echo_server_both example comes with a server.pem file, and the echo_server_tls example comes with server.pem and dh.pem. I have used the same files that come with the samples, and I have also tried generating and registering my own .pem files using openSSL. In both cases I get this when the client tries to connect:
[2021-06-29 20:51:21] [error] handle_transport_init received error: sslv3 alert certificate unknown
[2021-06-29 20:51:21] [fail] WebSocket Connection [::1]:63346 - "" - 0 asio.ssl:336151574 sslv3 alert certificate unknown
[2021-06-29 20:51:21] [info] asio async_shutdown error: asio.ssl:336462231 (shutdown while in init)
I discovered these errors after I edited handle_init() in tls.hpp, following a suggestion in another site, to look like this:
void handle_init(init_handler callback,lib::asio::error_code const & ec) {
if (ec) {
//m_ec = socket::make_error_code(socket::error::tls_handshake_failed);
m_ec = ec;
} else {
m_ec = lib::error_code();
}
callback(m_ec);
}
This change let the actual openSSL error to show in the console, otherwise it would show a generic "handshake failed" error.
I know I'm not doing what I should with the certificates, but I have no idea where else to look or what to do next. Can anyone here help please? Should I use the .pem files that come with the examples, or should I generate my own? in case I should generate my own, what would be the openSSL command to do that correctly and how do I tell my PC to recognize these as valid so that the server works?
Found the problem: WebSocket++ will not accept a self-signed certificate (the ones you can create directly in your own PC using OpenSSL or the Windows utilities). There is no way around it. You must have a valid, authority-validated and endorsed certificate. You can get such a certificate for free (valid only for 90 days) from https://zerossl.com/. The site has detailed instructions on how to request, obtain and install a certificate. After getting a valid certificate and installing it on my server, everything worked as it should.

Find SSL Version after Handshake in OpenSSL

I want to find out the protocols supported by a target but the problem is that their are quite a number websites which are not supporting a particular version but when i performed handshake it was successful becz target surpassed the version that i gave and perform handshake on the supported version
[ it happened on only 1 website]
example : i passed a version :TLSVersion.TLS_1_2 but the handshake is performed using TLSv1_0 becz it is not supporting TLSVersion.TLS_1_2
Because of the above issue i want to check the version on handshake and i dont want to use scapy.ssl_tls
version = [SSL.SSLv23_METHOD,
SSL.TLSv1_METHOD,
SSL.TLSv1_1_METHOD,
SSL.TLSv1_2_METHOD]
context = OpenSSL.SSL.Context(version)
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
soc.settimeout(CONNECTION_TIMEOUT)
connection = OpenSSL.SSL.Connection(context,soc)
connection.connect((host,port))
connection.do_handshake()
#wants to check version here
i want to check the version on handshake
The relevant functions to check the version both client and server use for the remaining session in pyOpenSSL are get_protocol_version_name or get_protocol_version:
connection.do_handshake()
#wants to check version here
print(connection.get_protocol_version_name())
Note that these functions are only available since pyOpenSSL 0.16.0
Please not also that you cannot specify a list of TLS methods when creating the context but only a single method which essentially specifies the minimal TLS version supported by the client. Thus
context = OpenSSL.SSL.Context(SSL.TLSv1_METHOD)
allows the client to use TLS 1.0 and better. If you instead use SSL.TLSv1_2_METHOD the client would be restricted to TLS 1.2 and better and thus could not establish a SSL connection with a server supporting only TLS 1.0.
Find SSL Version after Handshake in OpenSSL...
If I am parsing what you want correctly... you want the protocol version like printed by openssl s_client:
$ openssl version
OpenSSL 1.1.0b 26 Sep 2016
$ openssl s_client -connect www.google.com:443 -servername www.google.com
CONNECTED(00000005)
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
Server did acknowledge servername extension.
---
...
---
New, TLSv1.2, Cipher is ECDHE-RSA-CHACHA20-POLY1305
Server public key is 2048 bit
Secure Renegotiation IS supported
No ALPN negotiated
SSL-Session:
Protocol : TLSv1.2
...
The first message of "New, TLSv1.2" tells you about the cipher. That is, when is ECDHE-RSA-CHACHA20-POLY1305 first arrived in TLS. In the case of ECDHE-RSA-CHACHA20-POLY1305, the cipher suite was first seen in TLS 1.2.
The source code for s_client is located at <openssl src>/apps/s_client.c. The code responsible in OpenSSL 1.0.2 is around line 2210:
/* line 2210 */
c = SSL_get_current_cipher(s);
BIO_printf(bio, "%s, Cipher is %s\n",
SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c));
...
The second message of "Protocol: TLSv1.2" tells you the protocol version used during key exchange and subsequent cipher selection and bulk transfer.
The code responsible in OpenSSL 1.0.2 is <openssl src>/ssl/ssl_txt.c around line 105:
/* line 105 */
int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x)
{
unsigned int i;
const char *s;
if (x == NULL)
goto err;
if (BIO_puts(bp, "SSL-Session:\n") <= 0)
goto err;
if (x->ssl_version == SSL2_VERSION)
s = "SSLv2";
else if (x->ssl_version == SSL3_VERSION)
s = "SSLv3";
else if (x->ssl_version == TLS1_2_VERSION)
s = "TLSv1.2";
else if (x->ssl_version == TLS1_1_VERSION)
s = "TLSv1.1";
else if (x->ssl_version == TLS1_VERSION)
s = "TLSv1";
else if (x->ssl_version == DTLS1_VERSION)
s = "DTLSv1";
else if (x->ssl_version == DTLS1_2_VERSION)
s = "DTLSv1.2";
else if (x->ssl_version == DTLS1_BAD_VER)
s = "DTLSv1-bad";
else
s = "unknown";
if (BIO_printf(bp, " Protocol : %s\n", s) <= 0)
goto err;
...
}
I want to find out the protocols supported by a target but the problem is that their are quite a number websites which are not supporting a particular version but when i performed handshake ...
This is a different problem. You should look at the source code for sslscan at SSLScan - Fast SSL Scanner to see how it works. The Sourceforge one seems abandoned. It lacks SNI and other new features, like secure negotiation and ALPN.
You might try this sslscan from GitHub: rbsec/sslscan. The GitHub one is actively maintained and seems to be more up to date.
example : i passed a version :TLSVersion.TLS_1_2 but the handshake is performed using TLSv1_0 becz it is not supporting TLSVersion.TLS_1_2
This will not happen. TLS specifies one protocol version only. The idea is your try TLS 1.2. If it fails, then you fall back to TLS 1.1. If it fails, then you fall back to TLS 1.0. Ad infinitum.
The try-and-fallback approach is the reason for RFC 7504, TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks. This was an awful band-aide from the Browser crowd. See, for example, Last Call: <draft-ietf-tls-downgrade-scsv-03.txt> (TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacks) to Proposed Standard.
TLS does not accept a range of protocol versions like many folks think. We have tried to get it changed a few times. See, for example, A new TLS version negotiation mechanism.

Twisted listenSSL virtualhosts

Currently using a really simple Twisted NameVirtualHost coupled with some JSON config files to serve really basic content in one Site object. The resources being served by Twisted are all WSGI objects built in flask.
I was wondering on how to go about wrapping the connections to these domains with an SSLContext, since reactor.listenSSL takes one and only one context, it isn't readily apparent how to give each domain/subdomain it's own crt/key pair. Is there any way to set up named virtual hosting with ssl for each domain that doesn't require proxying? I can't find any Twisted examples that use NameVirtualHost with SSL, and they only thing I could get to work is hook on the reactor listening on port 443 with only one domain's context?
I was wondering if anyone has attempted this?
My simple server without any SSL processing:
https://github.com/DeaconDesperado/twsrv/blob/master/service.py
TLS (the name for the modern protocol which replaces SSL) only very recently supports the feature you're looking for. The feature is called Server Name Indication (or SNI). It is supported by modern browsers on modern platforms, but not some older but still widely used platforms (see the wikipedia page for a list of browsers with support).
Twisted has no specific, built-in support for this. However, it doesn't need any. pyOpenSSL, upon which Twisted's SSL support is based, does support SNI.
The set_tlsext_servername_callback pyOpenSSL API gives you the basic mechanism to build the behavior you want. This lets you define a callback which is given access to the server name requested by the client. At this point, you can specify the key/certificate pair you want to use for the connection. You can find an example demonstrating the use of this API in pyOpenSSL's examples directory.
Here's an excerpt from that example to give you the gist:
def pick_certificate(connection):
try:
key, cert = certificates[connection.get_servername()]
except KeyError:
pass
else:
new_context = Context(TLSv1_METHOD)
new_context.use_privatekey(key)
new_context.use_certificate(cert)
connection.set_context(new_context)
server_context = Context(TLSv1_METHOD)
server_context.set_tlsext_servername_callback(pick_certificate)
You can incorporate this approach into a customized context factory and then supply that context factory to the listenSSL call.
Just to add some closure to this one, and for future searches, here is the example code for the echo server from the examples that prints the SNI:
from twisted.internet import ssl, reactor
from twisted.internet.protocol import Factory, Protocol
class Echo(Protocol):
def dataReceived(self, data):
self.transport.write(data)
def pick_cert(connection):
print('Received SNI: ', connection.get_servername())
if __name__ == '__main__':
factory = Factory()
factory.protocol = Echo
with open("keys/ca.pem") as certAuthCertFile:
certAuthCert = ssl.Certificate.loadPEM(certAuthCertFile.read())
with open("keys/server.key") as keyFile:
with open("keys/server.crt") as certFile:
serverCert = ssl.PrivateCertificate.loadPEM(
keyFile.read() + certFile.read())
contextFactory = serverCert.options(certAuthCert)
ctx = contextFactory.getContext()
ctx.set_tlsext_servername_callback(pick_cert)
reactor.listenSSL(8000, factory, contextFactory)
reactor.run()
And because getting OpenSSL to work can always be tricky, here is the OpenSSL statement you can use to connect to it:
openssl s_client -connect localhost:8000 -servername hello_world -cert keys/client.crt -key keys/client.key
Running the above python code against pyOpenSSL==0.13, and then running the s_client command above, will print this to the screen:
('Received SNI: ', 'hello_world')
There is now a txsni project that takes care of finding the right certificates per request. https://github.com/glyph/txsni

SSL api for winsock?

I have windows c++ project.
Need to implement both ssl client and server on top of existing winsock code.
I tried with openssl but it seems too messy. I assume there is nicer/shorter/cleaner/faster way implementeing this than openssl..
Im thankful for any suggestions..
You can use Windows built-in SSL stuff -- SChannel . Searching Google fo "SChannel SSL" would give you plenty of information (though SChannel itself is poorly documented and not easy to comprehend).
On the other hand, OpenSSL is not messy once you study the source code of some project, that uses OpenSSL.
Acctually .. After some time spent with openssl hacking I wouldnt say its that messy :)
In case anyone anytime needs to add ssl to existing winsock code:
existing winsock code was like this:
0: sockett.Listen etc....
1: sockett.Accept(client, .....
2: recv(client , ...)
3: send(client , .....)
well in short if you want to implement SSL here..
delete lines 2 and 3 :) and add:
SSL_library_init();
SSL_load_error_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *tlsctx;
SSL *ssl;
tlsctx = SSL_CTX_new( SSLv23_method());
// search google : generate self signed certificate openssl
SSL_CTX_use_certificate_file(tlsctx, "ssl\\server1.crt" , SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(tlsctx, "ssl\\server1.key", SSL_FILETYPE_PEM);
ssl = SSL_new(tlsctx);
SSL_set_fd(ssl, client);
SSL_accept(ssl);
/* instaed recv SSL_read(ssl, ....*/
/* instaed send SSL_write(ssl, ....*/
/* not 100% sure Sleep and shutdown/free/close are entirely correct here but in my code works fine */
Sleep(3000);
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(tlsctx);
shutdown(client, SD_BOTH);
Sleep(10);
closesocket(client);
For testing:
in command line run:
openssl s_client -host localhost -port <PORT>

2-way SSL with CherryPy

From CherryPy 3.0 and onwards, one-way SSL can be turned on simply by pointing to the server certificate and private key, like this:
import cherrypy
class HelloWorld(object):
def index(self):
return "Hello SSL World!"
index.exposed = True
cherrypy.server.ssl_certificate = "keys/server.crt"
cherrypy.server.ssl_private_key = "keys/server.crtkey"
cherrypy.quickstart(HelloWorld())
This enables clients to validate the server's authenticity. Does anyone know whether CherryPy supports 2-way ssl, e.g. where the server can also check client authenticity by validating a client certificate?
If yes, could anyone give an example how is that done? Or post a reference to an example?
It doesn't out of the box. You'd have to patch the wsgiserver to provide that feature. There is a ticket (and patches) in progress at http://www.cherrypy.org/ticket/1001.
I have been looking for the same thing. I know there are some patches on the CherryPy site.
I also found the following at CherryPy SSL Client Authentication. I haven't compared this vs the CherryPy patches but maybe the info will be helpful.
We recently needed to develop a quick
but resilient REST application and
found that CherryPy suited our needs
better than other Python networking
frameworks, like Twisted.
Unfortunately, its simplicity lacked a
key feature we needed, Server/Client
SSL certificate validation. Therefore
we spent a few hours writing a few
quick modifications to the current
release, 3.1.2. The following code
snippets are the modifications we
made:
cherrypy/_cpserver.py
## -55,7 +55,6 ## instance = None ssl_certificate = None ssl_private_key
= None
+ ssl_ca_certificate = None nodelay = True
def __init__(self):
cherrypy/wsgiserver/__init__.py
## -1480,6 +1480,7 ##
# Paths to certificate and private key files ssl_certificate = None ssl_private_key = None
+ ssl_ca_certificate = None
def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None, max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
## -1619,7 +1620,9 ##
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if self.nodelay: self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- if self.ssl_certificate and self.ssl_private_key:
+ if self.ssl_certificate and self.ssl_private_key and \
+ self.ssl_ca_certificate:
+ if SSL is None: raise ImportError("You must install pyOpenSSL to use HTTPS.")
## -1627,6 +1630,11 ## ctx = SSL.Context(SSL.SSLv23_METHOD) ctx.use_privatekey_file(self.ssl_private_key) ctx.use_certificate_file(self.ssl_certificate)
+ x509 = crypto.load_certificate(crypto.FILETYPE_PEM,
+ open(self.ssl_ca_certificate).read())
+ store = ctx.get_cert_store()
+ store.add_cert(x509)
+ ctx.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, lambda *x:True) self.socket = SSLConnection(ctx, self.socket) self.populate_ssl_environ()
The above patches require the
inclusion of a new configuration
option inside of the CherryPy server
configuration,
server.ssl_ca_certificate. This
option identifies the certificate
authority file that connecting clients
will be validated against, if the
client does not present a valid client
certificate it will close the
connection immediately.
Our solution has advantages and
disadvantages, the primary advantage
being if the connecting client doesn’t
present a valid certificate it’s
connection is immediately closed.
This is good for security concerns as
it does not permit the client any
access into the CherryPy application
stack. However, since the restriction
is done at the socket level the
CherryPy application can never see the
client connecting and hence the
solution is somewhat inflexible.
An optimal solution would allow the
client to connect to the CherryPy
socket and send the client certificate
up into the application stack. Then a
custom CherryPy Tool would validate
the certificate inside of the
application stack and close the
connection if necessary; unfortunately
because of the structure of CherryPy’s
pyOpenSSL implementation it is
difficult to retrieve the client
certificate inside of the application
stack.
Of course the patches above should
only be used at your own risk. If you
come up with a better solution please
let us know.
If the current version of CherryPy does not support client certificate verification, it is possible to configure CherryPy to listen to 127.0.0.1:80, install HAProxy to listen to 443 and verify client side certificates and to forward traffic to 127.0.0.1:80
HAProxy is simple, light, fast and reliable.
An example of HAProxy configuration