I set up client-server connections using mem-BIOs. I was able to send data without socket IO. This was my reference - http://roxlu.com/2014/042/using-openssl-with-memory-bios.
Question 1:
For decryption, it used, BIO_write() and then SSL_read(). If via socket IO, the record is over 2 packets, what do I need to take care? If SSL_read() returns SSL_ERROR_WANT_READ, does it mean that data is buffered in in_bio and I need to call BIO_write() and SSL_read() again for 2nd packet and this time, SSL_read() will return SSL_ERROR_NONE?
Question 2:
I am trying to understand the SSL renegotiation handshake. Does it go through a 4-way handshake again? Or should it just do a 2-way handshake and a client-hello may not be necessary again? Please share any info on the renegotiation handshake exchange.
Now, I have added this code to the above reference example:
main() {
<snip - Initial handshake>
</snip>
SSL_renegotiate(client.ssl);
SSL_do_handshake(client.ssl);
krx_ssl_handle_traffic(&client, &server);
krx_ssl_handle_traffic(&server, &client);
krx_ssl_handle_traffic(&client, &server);
krx_ssl_handle_traffic(&server, &client);
}
I see these through callbacks:
+ client: HANDSHAKE START - before connect initialization - CINIT
+ client: LOOP - SSL renegotiate ciphers - UNKWN
+ client: LOOP - SSLv3 write client hello A - 3WCH_A
+ server: HANDSHAKE START - before accept initialization - AINIT
+ server: LOOP - before accept initialization - AINIT
+ server: LOOP - SSLv3 read client hello A - 3RCH_A
+ server: LOOP - SSLv3 write server hello A - 3WSH_A
+ server: LOOP - SSLv3 write certificate A - 3WSC_A
+ server: LOOP - SSLv3 write certificate reques - 3WCR_A
+ server: LOOP - SSLv3 write server done A - 3WSD_A
+ server: LOOP - SSLv3 flush data - 3FLUSH
+ client: LOOP - SSLv3 read server hello A - 3RSH_A
+ client: LOOP - SSLv3 read server certificate - 3RSC_A
+ client: LOOP - SSLv3 read server certificate - 3RCR_A
+ client: LOOP - SSLv3 read server done A - 3RSD_A
+ client: LOOP - SSLv3 write client certificate - 3WCC_A
+ client: LOOP - SSLv3 write client key exchang - 3WCKEA
+ client: LOOP - SSLv3 write certificate verify - 3WCV_A
+ client: LOOP - SSLv3 write change cipher spec - 3WCCSA
+ client: LOOP - SSLv3 write finished A - 3WFINA
+ client: LOOP - SSLv3 flush data - 3FLUSH
+ server: LOOP - SSLv3 read client certificate - 3RCC_A
+ server: LOOP - SSLv3 read client key exchange - 3RCKEA
+ server: LOOP - SSLv3 read certificate verify - 3RCV_A
+ server: LOOP - SSLv3 read finished A - 3RFINA
+ server: LOOP - SSLv3 write session ticket A - UNKWN
+ server: LOOP - SSLv3 write change cipher spec - 3WCCSA
+ server: LOOP - SSLv3 write finished A - 3WFINA
+ server: LOOP - SSLv3 flush data - 3FLUSH
+ server: HANDSHAKE DONE - SSL negotiation finished succe - SSLOK
+ client: LOOP - SSLv3 read server session tick - UNKWN
+ client: LOOP - SSLv3 read finished A - 3RFINA
+ client: HANDSHAKE DONE - SSL negotiation finished succe - SSLOK
Thanks.
Q1. Packets and _WANT_READ
You aren't at all clear on what your packets are. When using SSL/TLS over TCP (the normal case) an SSL/TLS record can be up to a little over 16k octets, while on most network paths TCP generally uses a packet (aka segment) size of about 1400. It may take more than 10 of these packets to complete one record. And when it does, that record might not be an ApplicationData record; if it isn't, SSL_read still won't have data to return and it will instead act according to the protocol, which may involve further reads AND/OR WRITES before it returns data. You should not try to guess what nonblocking SSL_read (or SSL_write either) are going to do; you should always look at their return values, and the 'extended' values from SSL_get_error (which is the routine that actually returns SSL_WANT_{READ,WRITE} etc, NOT SSL_read and SSL_write). This is explained on the man pages, which I encourage you to read if you haven't already. If you're on non-WSL Windows where man pages aren't used, see the website.
Q2. Renegotiation
(Note: answer for TLS through 1.2 only; 1.3 definitely changes the normal handshake very substantially, and I believe also renegotiation, but I haven't gone through it in detail yet.) Except that it starts while a session (crypto context) is already in use, and may be initiated by the server with RequestHello, and (importantly) can use the Renegotiation Indication extension (RFC5746) to prevent the "Apache-splice" attack (CVE-2009-3555), re-negotiation is (almost) the same as initial negotiation. If a full handshake it takes four flights (two round-trips); if an abbreviated handshake (resuming a pre-existing session) it takes three flights but the last can be combined with client data which often reduces it to one round-trip. See my answer at https://security.stackexchange.com/questions/91248/questions-about-triple-handshakes-considered-harmful-breaking-and-fixing-authen (whose relevance is admittedly unobvious) for a riff on this. See RFC 5246 et pred for the handshake
Related
I have a C client using OpenSSL that is failing a test when using a certificate that fails validation on the server side during the SSL_do_handshake() call on the server. When the application was using TLS 1.2 The SSL_do_handshake() failure on the server would be reported back to the client when it called SSL_do_handshake() as a failure return value.
When upgrading my application to OpenSSL 1.1.1 and TLS 1.3 I noted that while the validation error is still occurring on the server, it was no longer being reported back to the client.
I'm aware that the handshake protocol got completely re-written as part of TLS 1.3 however it seems like with all of the various callbacks available I should be able somehow on the client side to determine that authentication has failed without having to attempt to write data to the server.
Has anyone else encountered this and can they recommend a path forward?
The server and client in both TLSv1.2 and TLSv1.3 consider the handshake to be complete when they have both written a "Finished" message, and received one from the peer. This is what the handshake looks like in TLSv1.2 (taken from RFC5246):
Client Server
ClientHello -------->
ServerHello
Certificate*
ServerKeyExchange*
CertificateRequest*
<-------- ServerHelloDone
Certificate*
ClientKeyExchange
CertificateVerify*
[ChangeCipherSpec]
Finished -------->
[ChangeCipherSpec]
<-------- Finished
Application Data <-------> Application Data
So here you can see that the client sends its Certificate and Finished messages in its second flight of communication with the server. It then waits to receive the ChangeCipherSpec and Finished messages back from the server before it considers the handshake "complete" and it can start sending application data.
This is the equivalent flow for TLSv1.3 taken from RFC8446:
Client Server
Key ^ ClientHello
Exch | + key_share*
| + signature_algorithms*
| + psk_key_exchange_modes*
v + pre_shared_key* -------->
ServerHello ^ Key
+ key_share* | Exch
+ pre_shared_key* v
{EncryptedExtensions} ^ Server
{CertificateRequest*} v Params
{Certificate*} ^
{CertificateVerify*} | Auth
{Finished} v
<-------- [Application Data*]
^ {Certificate*}
Auth | {CertificateVerify*}
v {Finished} -------->
[Application Data] <-------> [Application Data]
One of the advantages of TLSv1.3 is that it speeds up the time taken to complete a handshake. In TLSv1.3 the client receives the "Finished" message from the server before it sends its Certificate and Finished messages back. By the time the client sends its "Finished" message, it has already received the "Finished" and so the handshake has completed and it can immediately start sending application data.
This of course means that the client won't know whether the server has accepted the certificate or not until it next reads data from the server. If it has been rejected then the next thing the client will read will be a failure alert (otherwise it will be normal application data).
I'm aware that the handshake protocol got completely re-written as part of TLS 1.3 however it seems like with all of the various callbacks available I should be able somehow on the client side to determine that authentication has failed without having to attempt to write data to the server.
It's not writing data to the server that is important - it is reading data. Only then will you know whether the server has sent an alert or just normal application data. Until that data has been read there are no callbacks available in OpenSSL that will tell you this - because OpenSSL itself does not know due to the underlying protocol.
I am trying to connect to a web service which is written in Java language on the server side. My program is written in VB.NET 4.0 on the client side.
When i try to call any methods from the web service I receive the following error message :
WS-Metadata Exchange Error URI: [http://...] Metadata contains a reference that cannot be resolved. The request was aborted: Could not create SSL/TLS secure channel
I am using a certificate to connect to the web service, however it seems that the problem is on the communication level between my host machine (client) and the server. The certificate i am using is never been checked as the client and the server can even not communicate.
I have tried to set the security protocol to "SSLv3" or "TLS12" but it didn't help. Thank you in advance for any suggestions.
Also i should mention that i managed to connect to this web service using a Java class. It seems that when the client side is written in Java it works but when it's in VB.NET it doesn't work.
P. HAB
EDITED :
I used "Wireshark" to discover the HTTPS packets which are sent and received by my program, here what I found in the transmitted packets :
Request by the client :
Secure Sockets Layer
TLSv1 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: TLS 1.0 (0x0301)
Length: 140
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 136
Version: TLS 1.0 (0x0301)
Random
Session ID Length: 0
Cipher Suites Length: 24
Cipher Suites (12 suites)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 71
Extension: server_name
Extension: elliptic_curves
Extension: ec_point_formats
Extension: Extended Master Secret
Extension: renegotiation_info
Response from the server :
Secure Sockets Layer
TLSv1 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
Content Type: Alert (21)
Version: TLS 1.0 (0x0301)
Length: 2
Alert Message
Level: Fatal (2)
Description: Handshake Failure (40)
I have tried to change the security protocol to different versions of SSL/TLS but it changed nothing. My client tries to send a "Client hello" with standard values (no user-customized parameters were specified) but the server is not accepting it. Any suggestions ?
Solution found :
The problem is in fact related to the Cipher suites and specially the RC4 algorithme. Actually my client is written in VB.NET 4.0 and in this version of .NET the deprecated RC4 algorithme is still supported and proposed by the .NET framework to any Web server during the "Hello Client" (Handshake) process.
The only presence of the RC4 cipher suites in the supported list of the cipher suites by my client was making the server to abort the connection with the following error message : "The request was aborted: Could not create SSL/TLS secure channel"
So I had to deactivate the RC4 cipher suites on my client machine by going in the system registry using regedit.exe and add the following key to these two specified paths :
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft.NETFramework\v4.0.30319
"SchUseStrongCrypto"=dword:00000001
And
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft.NETFramework\v4.0.30319
"SchUseStrongCrypto"=dword:00000001
After restarting the client machine I was able to connect to the web service succesfully.
For more information about the deprecated RC4 algorithmes :
https://technet.microsoft.com/en-us/library/security/2960358.aspx
=> Also you should notice that this problem exists only in .NET 4.0-4.5. From the version 4.6 and above its working fine.
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.
Setup :
Erlang cluster with two Erlang nodes, different names, identical SSL setup (certificates, keys, authority)
the two nodes are listening for connections on the same port
the accept scheme is simple and doesn't have an acceptor pool in front : ListenSocket = ssl:listen() when the app starts -> then, in the children, I do AcceptSock = ssl:transport_accept(ListenSocket) + ssl:ssl_accept(AcceptSock) + mysup:start_child() which will start a new gen_server to listen on ListenSocket (in the gen_server init() I have timeout == 0, btw - to make the gen_server receive a timeout message which will be handled with handle_info(timeout...) which does the accept scheme above).
Expected behavior :
I expect all of this to work all the time :)
Observed behavior :
from time to time, one or both servers stop accepting ssl connections from the iOS apps. telnet to that port works - and it even passes transport_accept().
from the iOS app, I get a "SSLHandshake failed, error -9806" and it doesn't look like transport_accept() was successful (I have error logging before and after that line and I do not see any error messages printed in the log - theoretically, it looked like the iOS app is not trying to connect to that port, but it did try, because it says SSLHandshake failed).
I followed this thread - and got the followings :
openssl s_client -connect myserver:4321 -servername myserver -ssl3 -tls1 -prexit
CONNECTED(00000003)
write:errno=60
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 0 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg : None
Start Time: 1460057622
Timeout : 7200 (sec)
Verify return code: 0 (ok)
---
same command executed with the second server (that is still accepting connections) returned a lot more infos and doesn't time out.
Any help is appreciated, thank you.
At least I think stud is the culprit.
My server setup is stud -> haproxy -> nginx -> express server
Requests don't make it through to haproxy.
I make a request with SSLv2:
import httplib
c = httplib.HTTPSConnection("my-server.com")
c.request("GET", "/foo/bar")
response = c.getresponse()
print response.status, response.reason
data = response.read()
print data
... and get back
socket.error: [Errno 54] Connection reset by peer
Here's the SSL dump:
New TCP connection #1: clientIP(29779) <-> my-server.com(443)
1 1 0.0044 (0.0044) C>S SSLv2 compatible client hello
Version 3.1
cipher suites
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
Unknown value 0x9a
Unknown value 0x99
Unknown value 0x96
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_MD5
Unknown value 0xff
1 0.0047 (0.0002) S>C TCP RST
Does anyone have any idea how to get stud to accept SSLv2 requests?
Thanks
Obviously the haproxy doesn't support SSLv2, but even if it did it, is practically certain that the target server won't support it either.
Your requirement is 20 years out of date. Java for example has never supported SSLv2, except in the IBM JVM, and I doubt that it still does there.
Educate the client.