Hacking on Qt's SSL Support

From Qt Wiki
Jump to navigation Jump to search

Qt's SSL support is designed so that the API is reasonably independent of the actual SSL implementation in use. The idea is that it should be possible in future to implement backends for either system provided SSL libraries, or to switch to a different SSL implementation entirely. Currently the only backend that exists uses openssl.

The most common way openssl is used in Qt is by dlopening the openssl library at run-time, this allows us to handle b/c issues and avoids a hard dependency on the openssl library in the compiled Qt library. In addition, it is possible to actually link to openssl by configuring with the -openssl-linked option. If you link openssl directly then the various handle() methods can be safely used to implement custom interactions with openssl.

Qt SSL Implementation

All the implementation can be found in qtbase/src/network/ssl/

X509 Certificate Handling

  • qsslcertificate.h
  • qsslcertificate_p.h
  • qsslcertificate.cpp
  • qsslcertificateextension.cpp
  • qsslcertificateextension.h
  • qsslcertificateextension_p.h

These files provide an interface for X.509 certificates. The certificate extension files only provide reading the information. The actual logic for decoding extensions is in qsslcertificate.cpp.

Key Handling

  • qsslkey.cpp
  • qsslkey.h
  • qsslkey_p.h

These files provide access to a public or private key. Note that there's a special algorithm type Opaque which can be used for code that wants to read keys from smart-cards etc. This should be used in conjuction with the handle() methods and the openssl-linked option.

Ciphers

  • qsslcipher.cpp
  • qsslcipher.h
  • qsslcipher_p.h

These files provide accessors for reading information about a cipher suite.

API Conveniences

  • qssl.h
  • qssl.cpp

These files provide a set of enums etc. that are used throughout the SSL code. Currently the .cpp file only exists to provide documentation.

  • qsslerror.h
  • qsslerror.cpp

These files provide an interface to the various errors that can happen during SSL, including getting a user-visible string for the error.

Socket Handling

  • qsslsocket.cpp
  • qsslsocket.h
  • qsslsocket_p.h
  • qsslsocket_openssl.cpp
  • qsslsocket_openssl_p.h
  • qsslconfiguration.cpp
  • qsslconfiguration.h
  • qsslconfiguration_p.h

dlopen Glue

  • qsslsocket_openssl_symbols.cpp
  • qsslsocket_openssl_symbols_p.h

Qt resolves OpenSSL symbols at run-time, and wraps all needed functions from the OpenSSL API inside helper functions that check for the presence of the required symbol, and fail gracefully should the symbol not resolve.

The files above provide glue that provides access to the openssl functions we need. Each symbol we use has a q_XXX declaration in the header file that is the version of the method we'll call from Qt (these functions should be named like the openssl function they wrap).

The cpp file has a DEFINEFUNC macro for each of the functions, note these must use the openssl function name, not the q_XXX name. There are versions of the DEFINEFUNC macro for various numbers of function arguments. In addition, each function has a RESOLVEFUNC macro that actually handles the call to dlsym. DEFINEFUNC lets you define a suitable "default return value", e.g. –1, for functions that do not resolve at run-time. Historically, functions have been known to disappear from the OpenSSL API between patch versions.

The various macros used here will automatically deal with the openssl-linked situation (at which point they just become function calls), so that's not something you need to worry about.

Gotchas

There are a few gotchas to watch for when working with the openssl code. The biggest one is the need to support quite a range of versions of openssl, and their various source and binary compatibility issues. These are made even worse by the possibility of having a different version of openssl at run time to the one that was compiled against.

A few specific issues to beware of:

  • In openssl 1.0 the STACK type was renamed STACK_ you'll need to put an ifdef guard around any use of it.
  • openssl uses quite a lot of macros as well as functions, these can be called directly and don't need to use the dlopen glue. Unfortunately some of them call functions, and those ones need to be reimplemented to call the q_XXX function.
  • Some distros ship openssl with SSL2 disabled, we need to handle this situation. We also need to remember that we could find that it has been disabled in the openssl library we link to at run-time even if it was enabled at build-time.

If you are using -openssl option during configure step, remember to install libssl-dev package on Linux platforms.

Tested Configurations

The following configurations are currently tested as part of the CI process:

  • Ubuntu 10.04 x86: openssl 0.9.8k-7ubuntu8.6
  • Ubuntu 11.10 x86: openssl 1.0.0e-2ubuntu4
  • Ubuntu 11.10 x64: openssl 1.0.0e-2ubuntu4
  • macOS 10.7 x64 : openssl 1.0.0d_0
  • macOS 10.6 x64 : openssl 1.0.0e_1