openSSL 1.1.1 API Doubts - ssl

I want to set up and run SSL client and server with TLS 1.2 using openSSL 1.1.1 for my project.
I have a few doubts and/or requirements with openSSL:
what is the right way to select TLS 1.2 as version? Currently I am using TLS_client_method(). the other methods seem to be deprecated. Is there a specific API for choosing particular version?
I need to run an SSL clinet with following handshake extensions.
ec_point_formats with "uncompressed" as value
supported_groups with list of "secp521r","secp384r1","secp256r1","secp224r1","secp192r1","secp160r1","ffdhe2048"
encrypt_then_mac with value 0
server_name
extended_master_secret without any value and length set to 0
I need to run an SSL server with following handshake extensions
encrypt_then_mac with value 0
extended_master_secret without any value and length set to 0
Apart from above header extension fields I want to disable everything else. How to accomplish that?
From client I want to provide only "TLS_PSK_WITH_AES_128_CBC_SHA256" cipher suite as option.
Is client certificate and key files (pem) necessary for successful connection establishment and communication when PSK cipher is used?
Is there any example or open source client-server implementation with PSK authentication?

what is the right way to select TLS 1.2 as version? Currently I am using TLS_client_method(). the other methods seem to be deprecated. Is there a specific API for choosing particular version?
TLS_client_method() is the correct method to use. To specify that no version below TLSv1.2 is used you should do this:
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
Where ctx is your SSL_CTX object.
If you also want to prevent anything higher than TLSv1.2 from being used then do this:
SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
See this page for information on these calls:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_min_proto_version.html
I need to run an SSL clinet with following handshake extensions.
ec_point_formats with "uncompressed" as value
supported_groups with list of "secp521r","secp384r1","secp256r1","secp224r1","secp192r1","secp160r1","ffdhe2048"
These extensions aren't used if you specify the PSK ciphersuite that you've selected so OpenSSL won't send them (assuming you've restricted the max TLS protocol version as described above, and have configured only that ciphersuite). Doing so would be pointless. Even if it did, OpenSSL 1.1.1 does not support "ffdhe2048". It does support all the others.
encrypt_then_mac with value 0
Not sure what you mean by "with value 0" since this extension is always empty and has no value. I assume you mean with length 0. This extension is sent by default so you don't need to do anything.
server_name
You should call:
SSL_set_tlsext_host_name(ssl, "hostname of the server");
Where ssl is your SSL object, and replacing "hostname of the server" with the server's real hostname.
See this page for information on this call:
https://www.openssl.org/docs/man1.1.1/man3/SSL_set_tlsext_host_name.html
extended_master_secret without any value and length set to 0
This extension is sent by default so you don't need to do anything.
I need to run an SSL server with following handshake extensions
encrypt_then_mac with value 0
extended_master_secret without any value and length set to 0
If the client sent them, then the server will echo them back by default. You don't need to do anything.
Apart from above header extension fields I want to disable everything else. How to accomplish that?
An OpenSSL client will additionally send the session_ticket extension. Its harmless, but if you really want to disable it you can do this:
SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
See this page for further information:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_options.html
An OpenSSL server will additionally send the "renegotiate" extension. You must not disable this (in fact you cannot). Ignore it. Its harmless.
From client I want to provide only "TLS_PSK_WITH_AES_128_CBC_SHA256" cipher suite as option.
That is the official IANA name for the ciphersuite. OpenSSL knows it as "PSK-AES128-CBC-SHA256".
Configure it on both the client and the server like this:
SSL_CTX_set_cipher_list(ctx, "PSK-AES128-CBC-SHA256");
See this page for further information:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_cipher_list.html
In addition you will need to provide PSK callbacks to tell OpenSSL what the PSK is that you want to use.
On the client you need to call SSL_CTX_set_psk_client_callback(). On the server you must call SSL_CTX_set_psk_server_callback().
See these pages for further information:
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_psk_client_callback.html
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_psk_server_callback.html
TLSv1.3 ciphersuites will still automatically be sent unless you have additionally restricted the max TLS protocol version to TLSv1.2 as described above. Finally you will also see a ciphersuite called "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" being sent. This isn't actually a real ciphersuite at all. It is always sent and cannot be suppressed. It will never be negotiated and is harmless. Ignore it.
Is client certificate and key files (pem) necessary for successful connection establishment and communication when PSK cipher is used?
No.
Is there any example or open source client-server implementation with PSK authentication?
You can look at how s_client and s_server do it:
https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/apps/s_client.c
https://github.com/openssl/openssl/blob/OpenSSL_1_1_1-stable/apps/s_server.c

Related

How to do TLS 1.3 PSK using openssl?

I'm working on a client/server software and trying to figure out how to setup a TLS 1.3 PSK connection using openssl. Apparently, there are different callbacks as compared to TLS 1.2 (and lower) but openssl documentation is dreadful and I can't really understand the full flow.
Can someone provide sample code on how to return info in these callbacks?
int SSL_psk_use_session_cb_func(SSL *ssl, const EVP_MD *md,const unsigned char **id,size_t *idlen,SSL_SESSION **sess);
int (*SSL_psk_find_session_cb_func)(SSL *ssl,const unsigned char *identity,size_t identity_len,SSL_SESSION **sess);
My understanding was that in TLS1.3 the Identity Hint is NULL, then why do these TLS1.3 specific callbacks have identity fields in them?
Read somewhere that TLS 1.3 has a different set of ciphersuites, what are the names of ones for PSK AES256 and PSK CHACHA20
In my case, the server will only accept one connection i.e. P2P datalink. Do I still have to make one side act as a server i.e. use find_session_cb instead of use_session_cb?
Can someone provide sample code on how to return info in these callbacks?
You can take a look at how s_client does it here:
https://github.com/openssl/openssl/blob/6af1b11848f000c900877f1289a42948d415f21c/apps/s_client.c#L183-L243
And here is how s_server does it:
https://github.com/openssl/openssl/blob/6af1b11848f000c900877f1289a42948d415f21c/apps/s_server.c#L185-L232
My understanding was that in TLS1.3 the Identity Hint is NULL, then why do these TLS1.3 specific callbacks have identity fields in them?
Identity Hint and Identity are two different things. In TLSv1.2 a server could provide a hint to the client to allow the client to select the correct identity for that server. In TLSv1.3 PSKs work completely differently. The client sends the identity to the server in the very first message so there is no opportunity for a hint to be received. In practice hints aren't usually that useful anyway.
In the context of PSK you can think of an identity as a bit like a username (that's actually a bit of an over-simplification - but enough for our purposes here)
Read somewhere that TLS 1.3 has a different set of ciphersuites, what are the names of ones for PSK AES256 and PSK CHACHA20
In TLSv1.2 you needed to use special PSK ciphersuites. In TLSv1.3 that is no longer the case. Ciphersuites work quite differently and there is no concept of having special PSK ciphersuites. You just use the normal ciphersuites. The main thing to be wary of is that in TLSv1.3 a PSK is always associated with a hash (e.g. SHA256). Whatever ciphersuite you use must be compatible with that hash, e.g. for SHA256 you might use TLS_CHACHA20_POLY1305_SHA256 or TLS_AES_128_GCM_SHA256.
In my case, the server will only accept one connection i.e. P2P datalink. Do I still have to make one side act as a server i.e. use find_session_cb instead of use_session_cb?
In TLS the client is defined as the peer that initiates the communication and the server is the peer that receives incoming connections. Therefore there is always a client and a server role. So, yes, one side must use find_session_cb and the other side must use use_session_cb.
I hope you meant externally established PSK (out-of-band PSK key and ID) with TLSv1.3. For that you can directly use old callbacks psk_client_callback and psk_server_callback. With these callback, by default AES_128_GCM_WITH_SHA256 ciphersuite gets used.
TLSv1.3 PSK client, server example in this repo
Here the ClientHello msg sends pre_shared_key extension with the PSK_ID. And the ServerHello responds with pre_shared_key extension with chosen PSK_ID index as 0.
If you need to use different ciphersuites then you need to use psk_use_session_cb and psk_find_session_cb.

OpenSSL connection: alert internal error

I have 100 HTTPS services running on a single server using SNI. (Actually, I don't have access to them. It's an assignment. All I know are their domain names N.xxx.yy where N is in range from 00 to 99.) The goal of the assignment is to evaluate security of every single connection to each of these servers. So some of the servers contain expired certificates, certificates with wrong CN, etc.
My problem is that I cannot get past the handshake on some of the servers. I have written my own application in C++ using OpenSSL, but I've also tried it with openssl s_client. This is how I connect to the server:
openssl s_client -host N.xxx.yy -port 443 -verify 1 -servername N.xxx.yy -CAfile assignment-ca.pem
And this is what I get:
139625941858168:error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:s3_pkt.c:1493:SSL alert number 80
139625941858168:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:
In Wireshark, I see that client sent ClientHello, server responded with ServerHello (choosing TLSv1.2 and ECDHE-RSA-AES256-GCM-SHA384) followed by Certificate and then it sent me Alert message containing Internal Error (80).
After trying different thing I have found out that if I run s_client with -tls1 or -tls1_1 I can successfully get past the handshake. -tls1_2 does not work. What is even stranger is that connection through Chrome/Firefox/any other browser succeeds even if TLSv1.2 is negotiated. From what I see, Chrome is sending a different cipher list than me or s_client but even after modifying the cipher list to match the one in Chrome (and making sure that server chooses ECDHE-RSA-AES128-GCM-SHA256), it does not work either. Chrome is sending these TLS extensions, which I don't but most of them seem empty:
Unknown 47802
renegotiation_info
Extended Master Secret
signed_certificate_timestamp
status_request
Application Layer Protocol Negotiation
channel_id
Unknown 6682
Can anybody explain me what is happening here? Unfortunately, I have no way to debug it on the server side so this is all I know.
UPDATE:
After playing around with forged ClientHello messages I managed to track it down to signature_algorithms extension. My app and s_client provide SHA384 + {RSA,DSA,ECDSA} but if I remove these and keep just SHA256 + {RSA,DSA,ECDSA}, as Chrome does, it works and I receive Server Key Exchange message successfully. Could it be that server somehow does not support it, but instead of providing meaningful error message, it just ends unexpectedly and gives me this internal error?
UPDATE 2:
I found answer to why it works with TLS versions prior to 1.2 in RFC5246. Question from the previous UPDATE still holds.
Note: this extension is not meaningful for TLS versions prior to 1.2.
Clients MUST NOT offer it if they are offering prior versions.
However, even if clients do offer it, the rules specified in [TLSEXT]
require servers to ignore extensions they do not understand.
Since you wrote that -tls1_2 does not work I assume either you and/or the server uses an older openssl library. The current version while writing this is 1.1.0e
There were quite some fixes since 0.9.8, which could often be seen on older systems.
For Version 1.0.1 there was this fix, which sounds like your problem:
`Some servers which support TLS 1.0 can choke if we initially indicate
support for TLS 1.2 and later renegotiate using TLS 1.0 in the RSA
encrypted premaster secret. As a workaround use the maximum permitted
client version in client hello, this should keep such servers happy
and still work with previous versions of OpenSSL.`
Maybe also notable:
Don't allow TLS 1.2 SHA-256 ciphersuites in TLS 1.0, 1.1 connections.
So I would suggest to update your openssl-Version and in case of the servers out of your control I would stick to the settings you already found.

TLS Extended Master Secret- calculate session hash

I'm have tool which manually dissect ssl/http traffic using openssl library. It's work fine in most cases, but failed wheen client/server usese Extended Master Secret extension.
Fail occured on last stage of handshake, where veryfying of test encripted data performed .
As I understand for proper work of this extension I need properly fill handshake buffer with specific TLS fields (client hello, server hello, key exchange) and then master key should be generated baasing on hashing of handshake buffer.
Unfortunatelly it's not work for me.
So my question-which exactly tls packeds should be hashed for generating proper master key ?
Will be gratefull for any comments.
Thanks.
PS: I downloaded experemental version of openssl from github, where this functionality implemented.
openssl s_server/s_client uses corespond extension, Ican see it in Wireshark, and able to decode traffic with server pem file.
You need to do the following to generate the session hash
1) Append all the Handshake messages, other than encrypted handshakes in order of arrival, please don't include the record header to the handshakes. only messages and message headers
2) Hash them based , simple to say,
Hash algorithm varies based on Cipher Suite and Protocal Version
TLS1 and TLS1.1 its mixture of SHA1 and MD5 (16 bit each)
TLS1.2 its mostly SHA256 or SHA384 based on cipher suite.

OpenSSL let the server and client negotiate the method

Following a really outdated tutorial I managed to create an HTTPS server using OpenSSL with TLS1.2, and I'm very proud of it ;)
However TLS 1.2 is only supported in latest browsers and I would like to have some kind of negotiation of the protocol between the client and server, which I'm sure it can be done, but I'm not able to find how! So that if the client only supports TLS1.0, well use that. And if it only supports SSLv3, use that. Not sure about SSLv2, maybe better leave that...
The code I use right now is:
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ssl_method = TLSv1_2_server_method();
ssl_ctx = SSL_CTX_new(ssl_method);
Then the server certificates are loaded and the ssl_ctx is shared among all connections. When a client is accepted by the server socket it is encapsulated in an SSL object (whatever it represents):
ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, client_socket);
SSL_accept(ssl);
So I guess that something has to be changed in the ssl_ctx creation to allow more methods... Any idea?
<rant> No decent, extensive documentation can be found for OpenSSL, the best available is a 10 years old tutorial! </rant>
Thanks in advance.
You do this by using SSLv23_method() (and friends) instead of a specific method (e.g. TLSv1_2_server_method() in your example). This sends the SSLv2 ClientHello but also specifies the highest protocol supported. The somewhat outdated man page says:
SSLv23_method(void), SSLv23_server_method(void), SSLv23_client_method(void)
A TLS/SSL connection established with these methods will understand
the SSLv2, SSLv3, and TLSv1 protocol. A client will send out SSLv2
client hello messages and will indicate that it also understands SSLv3
and TLSv1. A server will understand SSLv2, SSLv3, and TLSv1 client
hello messages. This is the best choice when compatibility is a
concern.
This online man page doesn't discuss the newer TLSv1_1 and TLSv1_2 protocols, but I verified in the 1.0.1g source of s23_clnt.c that SSLv23_method() includes them.
You then limit the protocols you actually accept with SSL_CTX_set_options():
The list of protocols available can later be limited using the
SSL_OP_NO_SSLv2, SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1 options of the
SSL_CTX_set_options() or SSL_set_options() functions. Using these
options it is possible to choose e.g. SSLv23_server_method() and be
able to negotiate with all possible clients, but to only allow newer
protocols like SSLv3 or TLSv1.
Note, however, that you can't enable arbitrary sets of protocols, only contiguous protocols in SSLv2, SSLv3, TLSv1, TLSv1_1, TLSv1_2. For example, you can't choose only SSLv3 and TLSv1_1, omitting TLSv1. This comment in the source explains why:
SSL_OP_NO_X disables all protocols above X if there are some protocols below X enabled. This is required in order to maintain "version capability" vector contiguous. So that if application wants to disable TLS1.0 in favour of TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2.

In which cases can an SSL server omit sending the certificate?

I'm trying to figure out the SSL handshake process. After reading up on TLS in Wikipedia I've seen that
The server sends its Certificate message (depending on the selected cipher suite, this may be omitted by the server)
I've also seen such behavior in real-life sniffs, but only in cases where the user eventually received an "Invalid certificate" warning.
I was wondering in which cases can a server omit the certificate? How can the client verify the server's identity in this case then? Or is it only reserved to cases where the server have no certificate and gives up on sending a fake one, knowing that the user will see a browser warning anyway?
Thanks!
Some cipher suites don't rely on certificates:
The anonymous cipher suites, defined in the main TLS RFC (the names containing DH_anon). Some of them can provide encryption, but without authentication, which is insecure. Section A.5 says the following about them:
The following cipher suites are used for completely anonymous
Diffie-Hellman communications in which neither party is
authenticated. Note that this mode is vulnerable to man-in-the-
middle attacks. Using this mode therefore is of limited use: These
cipher suites MUST NOT be used by TLS 1.2 implementations unless the
application layer has specifically requested to allow anonymous key
exchange. (Anonymous key exchange may sometimes be acceptable, for
example, to support opportunistic encryption when no set-up for
authentication is in place, or when TLS is used as part of more
complex security protocols that have other means to ensure
authentication.)
Kerberos cipher suites, in which case the identification is done via the Kerberos ticket, and the name is verified against the Kerberos principal name (host/MachineName#Realm).
Pre-Shared Keys cipher suites (see section on PSK Identity Encoding).
There is one valid case for anonymous ciphers: the opportunistic encryption of e-mail over SMTP with STARTTLS. As an MITM could easily prevent the use of TLS, there is no use in protecting agains MITM at the TLS level.
If the client knows that he will proceed anyway, even if the certificate was invalid, the can request an anonymous ciphersuite saving the server the generation of a signature and himself the verification the certificate and the signature.