Select (TLS 1.3) Curves in Apache - apache

I just upgraded my Apache to enable TLS 1.3. So far it works fine but TLS 1.3 ignores the "SSLOpenSSLConfCmd Groups" setting. So it uses weaker curves for TLS 1.3 than for TLS 1.2 and below. See: https://www.ssllabs.com/ssltest/analyze.html?d=neuz.de&s=2a03%3a4000%3a6%3ae04d%3a0%3a0%3a0%3a1&latest
Any hints? Sure, the curves are OK but I prefer the best ones.
Also I'm not really happy with the Group selection for lower TLS versions. I currently use this config:
"SSLOpenSSLConfCmd Groups sect571r1:sect571k1:secp521r1:sect409k1:sect409r1:secp384r1:sect283k1:sect283r1:secp256k1:prime256v1:brainpoolP512r1:brainpoolP384r1:brainpoolP256r1"
What I would like to have is "use the strongest curves as preferred but never lower than 256bit".
Also for some curves listed by "openssl ecparam -list_curves" will not work. If I add brainpoolP512t1 (while brainpoolP512r1 works) to the list, Apache fails to start. Is there an easy way to find out which will work? Trial & Error is a bit annoying.

I found the solution. In TLS 1.3 the CLIENT sends the preferred curve. If this curve is in the list of accepted ones on the server, it will be used. If not, it will be re-negotiated. Most clients send 256bit curves which will be accepted in my config. If I remove all 256bit curves, stronger ones will be used.
"SSLOpenSSLConfCmd Groups sect571r1:sect571k1:secp521r1:sect409k1:sect409r1:secp384r1:brainpoolP512r1:brainpoolP384r1"
will solve the issue, however this will impact the compatibility.

Related

"decrypt error" of TLS 1.2 change-cipher-spec, but reads MAC correctly

I'm trying to bring an old TLS 1.0 implementation (that I did not write) up to date to speak TLS 1.2.
As a first step I integrated the TLS 1.1 change of putting the plaintext initialization vector in the record. That was no problem. It seemed to work well enough that I could read https://example.com in TLS 1.1, as well as SSL Labs viewMyClient.html.
Then I adapted to the TLS 1.2 change of the pseudorandom function to (for most practical purposes) P_SHA256 instead of the (more complex and bizarre) half and half MD5/SHA1 rigamarole. I did it wrong the first time and got an invalid MAC error, but it was more or less a typo on my part and I fixed it. Then the invalid MAC error went away.
But despite that, after sending the ClientKeyExchange->ChangeCipherSpec messages, I'm getting a "Decrypt Error" back from the server(s) (same Alert regardless, https://google.com or anything I try). I gather the ChangeCipherSpec message is encrypting just one byte, putting it into a message with padding and the MAC, etc.
If I tweak the MAC randomly by one byte, it goes back to complaining about invalid MAC. What confuses me is that the MAC itself is encrypted as part of GenericBlockCipher:
struct {
opaque IV[SecurityParameters.record_iv_length];
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[SecurityParameters.mac_length]; // <-- server reads this fine!
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
};
} GenericBlockCipher;
UPDATE: FWIW, I've added a Wireshark log of the failing 1.2 read of https://example.com, as well as a log of a functioning 1.1 session running what is the same code, not counting the P_SHA256 MAC update:
http://hostilefork.com/media/shared/stackoverflow/example-com-tls-1.2.pcapng (fails)
http://hostilefork.com/media/shared/stackoverflow/example-com-tls-1.1.pcapng (succeeds)
So, what exactly is it having trouble decrypting? The padding seems correct, as if add or subtract 1 to the byte I get an invalid MAC error. (The spec says "The receiver MUST check this padding and MUST use the bad_record_mac alert to indicate padding errors.", so that is to be expected.) If I corrupt the client-iv in the message from what I used to encrypt (just put a bad byte in the transmitted version), doing so also gives me Bad Record MAC. I'd expect that to wreck the decryption also.
So I'm puzzled on what could be the problem:
The server demonstrates discernment of valid MAC vs. not, so it must have decrypted. How's it getting the right MAC -and- having a decrypt error?
Cipher suite is an old one (TLS_RSA_WITH_AES_256_CBC_SHA) but I'm just tackling one issue at a time...and if I'm not mistaken, that shouldn't matter.
Does anyone with relevant experience have a theory of how TLS 1.2 could throw a wrench into code that otherwise works in TLS 1.1? (Perhaps someone who's done a similar updating to a codebase, and had to change more than the two things I've changed to get it working?) Am I missing another crucial technical change? What recourse do I have to find out what is making the server unhappy?
There's actually not anything wrong with the ChangeCipherSpec message. It's actually the Finished message that has the problem. It is complaining about the decrypted verify_data inside that message, which is not matching an expected hash (despite the encryption/decryption itself being correct).
But what's confusing in the Wireshark log is that the Finished message shows up on the same log line, but under the name "EncryptedHandshakeMessage" This makes it look like some kind of tag or label describing ChangeCipherSpec, but it's not. That message actually isn't encrypted at all.
TLS finished packet renamed encrypted handshake message
HTTPS over TLS - encrypted type
From the second link:
In practice, you will see unencrypted Client Hello, Server Hello, Certificate, Server Key Exchange, Certificate Request, Certificate Verify and Client Key Exchange messages. The Finished handshake message is encrypted since it occurs after the Change Cipher Spec message.
"Hoping someone has experience updating TLS 1.0 or 1.1 to 1.2, and might have seen a similar problem due to not changing more than the P_SHA256 MAC and bumping the version number"
They only mention two of the three places that you need to update the MD5/SHA1 combination in the "changes from TLS 1.1" section of RFC 5246:
The MD5/SHA-1 combination in the pseudorandom function (PRF) has been replaced with cipher-suite-specified PRFs. All cipher suites in this document use P_SHA256.
The MD5/SHA-1 combination in the digitally-signed element has been replaced with a single hash. Signed elements now include a field that explicitly specifies the hash algorithm used.
(Note: The second applies to certificates, and if you haven't gotten to certificate checking you wouldn't be at that point yet.)
What they don't mention in that section is the third place the MD5/SHA-1 combination changes, which is a hash used in the seed for the verify_data of the Finished message. However, this point is also a change from TLS 1.1, described much further down the document in section 7.4.9:
"Hash denotes a Hash of the handshake messages. For the PRF defined in Section 5, the Hash MUST be the Hash used as the basis for the PRF. Any cipher suite which defines a different PRF MUST also define the Hash to use in the Finished computation."
For a formal spec they're being a bit vague on "hash used as the basis for the PRF" (is it the HMAC or just the plain hash?) But it's the plain hash. So SHA256, unless the cipher suite's spec says otherwise.
(Note also the cipher suite can dictate the length of the verify_data as more than 12 bytes, though none mentioned in the spec do so.)
"What recourse do I have to find out what is making the server unhappy?"
YMMV. But what I did was just build OpenSSL as a static debug library, and linked it to a simple server. Then I added breakpoints and instrumentation to see what it was upset about. (GDB wasn't letting me step into the shared library, for some reason.)
Circa 30-Sep-2018, on a plain linux machine:
git://git.openssl.org/openssl.git
./config no-shared no-asm -g3 -O0 -fno-omit-frame-pointer -fno-inline-functions no-ssl2 no-ssl3
make
The simple server I used came from Simple TLS Server. Compile against the static library with:
gcc -g -O0 simple.c -o simple -lssl -lcrypto -ldl -lpthread
I followed the instructions for generating certificates here, but changed the AAs to localhost
openSSL sign https_client certificate with CA
Then I changed the cert.pem => rootCA.pem and key.pem => rootCA.key in the simple server code. I was able to do:
wget https://localhost:4433 --no-check-certificate
And successfully get back test as a response. So then it was just a matter of seeing where my client caused a failure.
I can think of 2 different situations that creates this problem:
Sending incorrect IV. IV affects only 1st block in decryption of CBC mode, so if your content is more than 16 bytes (AES block size), MAC part of your data will be decrypted correctly.
If you are using incorrect padding structure, you may get error in decryption(because padding verification fails), but content will be decrypted correctly.

How to find the ssl / tls master key

I tried posting this on ask.openstack but it has been stuck in the moderator for 5 days now. I thought I'd try here.
I was trying to debug a Nova issue and wanted to decode the SSL / TLS packets being exchanged using Wireshark. Part of the changes I was making was setting Nova up to use SSL / TLS and I wanted to be sure that part of it I had set correctly. I eventually figure out my issues from the various log files but I'm somewhat assuming that being able to watch the network traffic may help in some very difficult cases.
The exchange uses TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 at one point. According to this security stackexchannge question, there is a "pre-master secret" or various other terms. I've wrestled with this before in a previous life doing IPSec. Usually you can set debug in the application and it will spew out the secret into the log file. I tried "debug = true" under Default in nova.conf and got lots of debug but no secret. There was two items that looked interesting that were reported as **** in the log: keystone_authtoken.memcache_secret_key and neutron.metadata_proxy_shared_secret. I wasn't sure if those were the secrets I was looking for or not. In this case, I'm looking at the nova-api traffic going to port 8774.
Also, since all of openstack is Python and uses the same "request" and "certifi" packages, it may be possible to generalize this to all of the openstack components.
nova --version report 9.1.1

Can WINE handle ECC certificates?

I have an application that supposedly runs well under Mono, but is having some problems on my system. In the meantime, I tried running it through WINE after using winetricks to install the proper version of .NET (winetricks dotnet452).
This worked great! The application hits Github to check for updates and manages the SSL/TLS connection flawlessly. Elsewhere while using it, it attempts to access another website, https://themoose.co.uk, but fails with an SSL/TLS error. The only reasonable difference I could find between that site and Github was that it uses an ECC cert as opposed to Github's more traditional RSA cert.
I also saw these lines in WINE's console output:
fixme:secur32:schan_get_cipher_algid Don't know CALG for encryption algorithm 2, returning 0
fixme:secur32:schan_imp_get_max_message_size Returning 1 << 14.
fixme:secur32:schan_get_cipher_algid Don't know CALG for encryption algorithm 2, returning 0
Googling these messages doesn't return anything useful.
The conclusion I am drawn to is that WINE doesn't support new ECC certificates, but I do not see that limitation documented anywhere! Am I going crazy, or is this an oversight in the documentation somewhere?

Connector/c++ with SSL?

How to connect to MySql using Connector/c++ over SSL?
I read about mysql_ssl_set(): seems to work only with Connector/c.
I have openSSL enabled and working for require SSL users on MySql. And I can connect remotely to MySql using Connector/c++, but cannot see how to modify parameters of sql::Connection to reference certs for SSL.
Excellent tutorial from Giri Mandalika at MySql DevZone and docs on Connector/c++ don't mention SSL, which surprised me because SSL is well documented for Connector/c...or did I miss something obvious?
I realize sql::Driver::Connect() is overloaded, with the less-commonly discussed method taking one parameter sql::ConnectOptionsMap &options. Following that trail, I found just one discussion on point: Ulf Wendel/Thomas Pollak question-and-solution here (http://forums.mysql.com/read.php?167,367519,369534#msg-369534).
Did not work for me: when I incorporated it and tried to build (VC2008, WIN7) the build had warnings and failed.
I traced the exact causes as:
sql::ConnectPropertyVal generates locally defined symbol warning; and
std::map causes fatal error LNK1120: 1 unresolved externals.
With so many users out there of Connector/c++, I hoped others in the community might also be interested in how to use SSL with Connector/c++. Appreciate any ideas or help.
Spoke to Giri Mandalika (on the original development team), who mentioned that SSL support was originally planned but not completed for Connector/c++.
In case others who want SSL find this question, I worked around the problem only by using Connector/c, the underlying C api which Connector/C++ was designed to wrap.
As more than six months have elapsed without any community member coming up with a specific solution to use SSL with Connector/c++ (other than the overload solution referenced in my question), I guess I have to conclude that it just isn't possible, and mark my own question as "Answered" by me.

How does one set SSL ciphers when using CFSocket/CFStream in Cocoa?

I recently needed to configure CocoaHttpServer, which we're using in our application with success, to handle HTTPS connections coming from a client application (running on Android devices). This is fine - there is copious sample code which allows for this, and we were able to enable the secure server without issue.
In practice we were seeing incredibly long SSL negotiation phases while the client was doing its handshaking with our server - upwards of 70 seconds.
Through a long series of searches, I found that the delay was because of the calculation of Diffie-Hellman parameters used by default when SSL is enabled in CFSocket. This thread is where I first started to find the answer to my issue.
To match what our Windows server was doing (using a less-secure SSL cipher) I needed to set the cipher explicitly on the Mac, which isn't easy when using AsyncSocket as a wrapper for the socket communications.
Our Windows server was using:
TLS_RSA_WITH_RC4_128_MD5 )(0x04)
RC4 128 bits MD5 RSA
Our Macintosh server was using:
TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x039)
AES 256 bits SHA-1 Ephemeral Diffie-Hellman key exchange using RSA certificate
The difference in "security" is large, but likely not worth the effort/computation/delay that we were seeing. Security Theater?
Please note that there are different ciphers that can be chosen - I chose to use the same one as our Windows implementation for consistency.
With information from another question mentioned above, I figured out how to set the cipher for CFSocket to use the same as Windows, and the code appears to be now quite a bit better - like it really works! CFSocket isn't directly exposing the SecureTransport support, which makes this kind of hard, but defining a particular key makes it work nicely.
For posterity, here's the code I've added to -onSocketWillConnect: in our HTTPConnection class:
// define this value; it isn't exposed by CFSocketStream.h
const extern CFStringRef kCFStreamPropertySocketSSLContext;
...
CFReadStreamRef stream = [sock getCFReadStream];
CFDataRef data = (CFDataRef) CFReadStreamCopyProperty(stream, kCFStreamPropertySocketSSLContext);
// Extract the SSLContextRef from the CFData
SSLContextRef sslContext;
CFDataGetBytes(data, CFRangeMake(0, sizeof(SSLContextRef)), (UInt8*)&sslContext);
SSLCipherSuite *ciphers = (SSLCipherSuite *)malloc(1 * sizeof(SSLCipherSuite));
ciphers[0] = SSL_RSA_WITH_RC4_128_MD5; // Basic cipher - not Diffie-Hellman
SSLSetEnabledCiphers(sslContext, ciphers, 1);
I hope this helps anyone working through the same issue as I - I'd be happy to share some more code and advice if needed.
For what it's worth, I contributed a patch to CocoaAsyncSocket about a week before you had this issue. Sorry that I didn't notice your question back then. :-)