Skip to main content

SSL issues in the ingame browser

EVE Online has an ingame browser, and under Wine that browser has issues with opening some websites using https. Those sites work in the game under Windows, so I knew it wasn't a browser issue per se. It wasn't an issue with all sites using https, either, so it wasn't a matter of SSL not working at all, either.

With the help of CCP's security expert, we noticed that the sites that were failing had certificate chains up to a root certificate with a very strong signature algorithm, ecdsa-with-SHA384, and chances were that Wine did not support that particular algorithm.

Now what?

Personally I'm no expert in security algorithms, SSL or TSL or anything like that, so I wasn't sure where to even begin looking at Wine source code to see if this algorithm was supported.

After some digging around I decided to look at the output of the secur32 channel:
export WINEDEBUG=+secur32

Then I started up the EVE client and opened up the browser, entering https://zkillboard.com in the address bar. There was quite a lot of output - no errors or warnings, though, and no smoking gun to be found. The functions in secur32 are very low level, though, and I found they were being called from functions in crypt32. Adding the crypt channel to the debug output would in theory give a clearer view of what was going on, but now I had the problem that the log was up to 800k lines.

I disabled the code that gets the root certificates from the system and pointed it to a bundle read from disk - I could then trim that bundle to only include the root certificate used by this particular site - Comodo ECC. This resulted in a log of around 10k lines - somewhat more manageable. Now I was able to confirm that this root certificate did not import properly due to a bad signature. Adding a bit more detailed logging confirmed that the bad signature stemmed from signature algorithm not being recognized.

But it works on Linux

I spent a bit of time trying to figure out what would be needed to add support for this signature algorithm - ecdsa-with-SHA384, but after a day or so realized that this was a rabbit hole I probably shouldn't be going down. I also found out that this troublesome site seemed to work fine on Linux. Feeling stupid for not checking that sooner, I compiled Wine on my Ubuntu box from the same repo and tested this. Sure enough, https://zkillboard.com loaded up just fine in the ingame browser.

Well, great, I thought, I can use the implementation for Linux as a reference to get this to work on OS X. When looking through the code I quickly found that there was no support for this algorithm, or any ECC certificates on Linux either. Pouring over the logs from Linux also revealed that this same root certificate failed to import, so there had to be some other way for that site to get certified.

Consider the alternatives

We took another look at zkillboard.com and found that there was an alternate chain, with a root certificate with a more typical RSA type signature. The question still remained, though - why did Wine on OS X not validate the alternate certificate chain when Wine on Linux did?

I added the Comodo RSA root certificate to the bundle I was using on the Mac, and it imported fine. Still the site wouldn't work. I figured there had to be some issue with finding that alternate chain, but as I knew very little about SSL in general this was a bit of a needle in a haystack situation. Being stubborn I figured I had no other option than digging into the Wine source, trying to understand what was going on.

I started tracing through CertGetCertificateChain in dlls/crypt32/chain.c, trying to understand how that worked and why it wouldn't accept the alternate chain we knew was available for this site. After adding more detailed logging I was convinced that this code was simply not getting an alternate chain. Why did this work on Linux, then?

The smoking gun

I went back to the Linux machine, ran the EVE client with the secur32 and crypt channels enabled and started analyzing the logs. Finally I noticed that the handshake was logged in some detail.

trace:secur32:schan_gnutls_log <4> HSK[0x7d416a18]: SERVER KEY EXCHANGE (12) was received. Length 327[327], frag offset 0, frag length: 327, sequence: 0
trace:secur32:schan_gnutls_log <4> HSK[0x7d416a18]: Selected ECC curve SECP256R1 (2)
...
trace:secur32:schan_gnutls_log <4> HSK[0x7d416a18]: CLIENT KEY EXCHANGE was queued [70 bytes]
trace:secur32:schan_gnutls_log <4> REC[0x7d416a18]: Sent ChangeCipherSpec

trace:secur32:schan_gnutls_log <4> HSK[0x7d416a18]: Cipher Suite: ECDHE_RSA_AES_128_CBC_SHA1

Maybe this would have been obvious to somebody that knows SSL well, but I hadn't realized that the server decides what certificate chain to send to the client. I guess it sends the strongest chain it has, unless the client specifically asks for a weaker cipher. I finally felt I was getting somewhere - now I just had to figure out how do the same on the Mac.

A secure session starts in InitializeSecurityContext, which is implemented in dlls/secur32/schannel.c. It calls schan_imp_create_session, which is in dlls/secur32/schannel_macosx.c - that function uses functions provided from OS X - SSLNewContext, for example, then later on SSLHandshake is called. I got a bit worried that since OS X handled the handshake I wouldn't be able to affect it, but a bit of searching led me to SSLSetEnabledCiphers.

A happy ending

To cut a long story short, calling that function with an array of cipher suites that Wine really supports, i.e. excluding the Elliptic Curve cipher suites solved the issue. That site that caused me such grief now finally loaded in the ingame browser.

Now I just need to clean this up a bit and submit a patch!

Comments

Popular posts from this blog

Working with Xmpp in Python

Xmpp is an open standard for messaging and presence, used for instant messaging systems. It is also used for chat systems in several games, most notably League of Legends made by Riot Games. Xmpp is an xml based protocol. Normally you work with xml documents - with Xmpp you work with a stream of xml elements, or stanzas - see https://tools.ietf.org/html/rfc3920 for the full definitions of these concepts. This has some implications on how best to work with the xml. To experiment with Xmpp, let's start by installing a chat server based on Xmpp and start interacting with it. For my purposes I've chosen Prosody - it's nice and simple to install, especially on macOS with Homebrew : brew tap prosody/prosody brew install prosody Start the server with prosodyctl - you may need to edit the configuration file (/usr/local/etc/prosody/prosody.cfg.lua on the Mac), adding entries for prosody_user and pidfile. Once the server is up and running we can start poking at it

JumperBot

In a  previous blog  I described a simple echo bot, that echoes back anything you say to it. This time I will talk about a bot that generates traffic for the chat server, that can be used for load-testing both the chat server as well as any chat clients connected to it. I've dubbed it  JumperBot  - it jumps between chat rooms, saying a few random phrases in each room, then jumping to the next one. This bot builds on the same framework as the  EchoBot  - refer to the previous blog if you are interested in the details. The source lives on GitHub:  https://github.com/snorristurluson/xmpp-chatbot Configure the server In an  earlier blog  I described the setup of Prosody as the chat server to run against. Before we can connect bots to the server we have to make sure they can log in, either by creating accounts for them: prosodyctl register jumperbot_0 localhost jumperbot prosodyctl register jumperbot_1 localhost jumperbot ... or by  setting the authentication up  so that anyon

Simple JSON parsing in Erlang

I've been playing around with Erlang . It's an interesting programming language - it forces you to think somewhat differently about how to solve problems. It's all about pattern matching and recursion, so it takes bit getting used to before you can follow the flow in an Erlang program. Back in college I did some projects with Prolog  so some of the concepts in Erlang were vaguely familiar. Supposedly, Erlang's main strength is support for concurrency. I haven't gotten that far in my experiments but wanted to start somewhere with writing actual code. OTP - the Erlang standard library doesn't have support for JSON so I wanted to see if I could parse a simple JSON representation into a dictionary object. The code is available on Github:  https://github.com/snorristurluson/erl-simple-json This is still very much a work in progress, but the  parse_simple_json/1 now handles a string like {"ExpiresOn":"2017-09-28T15:19:13", "Scopes":