3

I run an HTTP2 server example (libevent-server.c) from nghttp2 on Ubuntu 15.04. I would like to sniff the HTTP2 packet between the client-server using Wireshark.

I don't use any web browser as the client, so the tips on how to read HTTP2 message in Wireshark explained here is not applicable to my project. I use libcurl.

Since the HTTP2 packet is the application layer inside TLS, Wireshark must know how to decrypt it; hence, I followed the guide from here to supply Wireshark with the key. However the guide warns that, "If the server sends a ServerKeyExchange message, you will not be able to decrypt the data." Unfortunately, my Wireshark shows that the Server Key Exchange was sent by the server.

The following is a snippet of libevent-server.c code:

 SSL_load_error_strings();
 SSL_library_init();
 OpenSSL_add_all_algorithms();
 OPENSSL_config(NULL);

I have recompiled the code after changing OPENSSL_config(NULL) to OPENSSL_no_config() but the Server Key Exchange was still sent.

How can I disable the Server Key Exchange?

jww
  • 97,681
  • 90
  • 411
  • 885
Curioso
  • 343
  • 1
  • 3
  • 7

3 Answers3

2

As the page you link to explains almost correctly, for Wireshark (or any other passive eavesdropper) to decrypt the SSL/TLS handshake must use plain RSA keyexchange, NOT any of the Diffie-Hellman options (DHE or ECDHE in practice) or "ephemeral" RSA. (The "almost" is that it says "RSA keys have been used to encrypt the data". In fact RSA keyexchange uses the server RSA key to encrypt the premaster secret, which goes through extensive transformation to produce the multiple keys used to encrypt and authenticate the data.)

In practice DHE or ECDHE are the problem. These ciphersuites provide what is called Perfect Forward Secrecy which means that even if an eavesdropper captures and logs your communications and later compromises the server key they can't use it retroactively decrypt the logged encrypted data. Although these suites have existed and mostly been supported a long time, post-Snowden lots more people (browser and other application and middleware makers, sysadmins, network admins, CISOs and auditors, etc) placed lots more emphasis on using them.

"Ephemeral RSA" keyexchange is used only for some of the long-obsolete "EXPORT" ciphersuites in SSL/TLS. These were already known to be insecure since about 1995 and most people who care have prohibited using them a long time, or at least prioritizing nonbroken suites over them, although the FREAK researchers a few months ago found something like 5% of (I think a sample of) public servers still supporting them (which enabled their attack to work). Last I checked OpenSSL still enables them by default, but at lowest priority.

Answer: So you should configure your client (here curl with --ciphers) or your server (call SSL_[CTX_]set_cipher_list) -- or both if you like -- to remove ephemeral suites DEFAULT:!EDH:!EECDH:!EXPORT or directly require "plain" RSA RSA:!EXPORT:!eNULL:!SSLv2.

Which brings up another option: if you only need to examine traffic between an OpenSSL-based client and server you control, as here, you can use a null-encryption suite. These are designed to be insecure, basically for testing purposes or possibly very severe legal/external restrictions that were seen as imaginable back in the 1990s, and not supported by many implementations; they are supported by OpenSSL but disabled by default, and not enabled even in ALL which you might logically expect to include them. To get them you must explicitly specify eNULL (better eNULL+RSA) or the very counterintuitive COMPLEMENTOFALL. Then you can read the data in Wireshark without decrypting.

dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70
  • Added a line `SSL_CTX_set_cipher_list(ctx, "DEFAULT:!EDH:!EECDH:!EXPORT")` on the server code, then the ServerKeyExchange was not sent by the server. I can now see the HTTP2 traffic. [The guide](http://packetpushers.net/using-wireshark-to-decode-ssltls-packets/) hinted that the wildcard port 0 may be used to configure Wireshark, but that didn't work for me. I had to specifically put the port number (443). – Curioso Jul 23 '15 at 04:16
1

If your goal is to read decrypted application data from your OpenSSL application in Wireshark, do note that RSA private keys are not your only option, you can also pass a mapping to the (pre-)master secret. This functionality is not limited to SSL clients even though the use of SSLKEYLOGFILE is commonly found for those applications using NSS.

For a method to retrieve the pre-master key from OpenSSL client and server applications, see this Sec.SE post (does not require application changes). If you would like to embed such debugging functionality in your application, then you can do it more cleanly by setting a callback when the handshake completes. Example:

// converts bytes to hex
void to_hex(unsigned char *dst, unsigned char *src, size_t len) {
  unsigned char hex[] = "0123456789abcdef";
  unsigned i;
  for (i = 0; i < len; i++) {
    unsigned char c = src[i];
    *dst++ = hex[c >> 4];
    *dst++ = hex[c & 0xf];
  }
  *dst = '\0';
}

static FILE *ssl_keylog;

void info_callback(const SSL *ssl, int where, int ret) {
  unsigned char rnd[SSL3_RANDOM_SIZE*2+1];
  unsigned char pmk[SSL_MAX_MASTER_KEY_LENGTH*2+1];

  // skip in case the session is invalid, or if it is not
  // a Handshake Done notification.
  if (!ssl || !ssl->session || !ssl->s3 || !(where & SSL_CB_HANDSHAKE_DONE)) {
     return;
  }

  // convert bytes to hex
  to_hex(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
  to_hex(pmk, ssl->session->master_key, ssl->session->master_key_length);

  // write to SSL keylog file
  fprintf(keylog_file, "CLIENT_RANDOM %s %s\n", rnd, pmk);
}

static void run(const char *service, const char *key_file,
                const char *cert_file) {
  SSL_CTX *ssl_ctx;
  ...

  ssl_ctx = create_ssl_ctx(key_file, cert_file);
  if (!keylog_file) {
    // open key log file if any.
    keylog_file = fopen("premaster.txt", "a");
  }
  // register callback (for SSL objects, use SSL_set_info_callback instead)
  SSL_CTX_set_info_callback(ssl_ctx, info_callback);
  ...
}
Lekensteyn
  • 64,486
  • 22
  • 159
  • 192
0

I would like to sniff the HTTP2 packet between the client-server using Wireshark.

For that, you usually refer to Wireshark and TLS on the Wireshark Wiki.


my Wireshark shows that the Server Key Exchange was sent by the server.

I believe the Serer Key Exchange message is always sent. I think about the best you will be able to do is suppress the Server Certificate message in the Server Hello. Do that by enabling only anonymous protocols. The anonymous protocols forgo server authentication, and will allow you to intercept the traffic.

I believe the cipher string you are looking for is "ADH:AECDH" or "aNULL" (usually, you explicitly state "!aNULL"). It needs to be available at both the client and the server. Finally, you can get of list of tokens at ciphers(3) OpenSSL man page.

Most clients categorically reject anonymous protocols, so it might be hard to actually get into that configuration (and have everything work).

jww
  • 97,681
  • 90
  • 411
  • 885
  • ServerKeyExchange is not always sent. However, it *is* sent for *all* anonymous (aNULL) suites, which as you say are a very bad idea anyway. – dave_thompson_085 Jul 22 '15 at 11:21