Hacking on Qt's SSL Support: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
 
(5 intermediate revisions by 3 users not shown)
Line 1: Line 1:
=Hacking on Qt’s <span class="caps">SSL</span> Support=
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.
 
==Introduction==
 
Qt’s <span class="caps">SSL</span> support is designed so that the <span class="caps">API</span> is reasonably independent of the actual <span class="caps">SSL</span> implementation in use. The idea is that it should be possible in future to implement backends for either system provided <span class="caps">SSL</span> libraries, or to switch to a different <span class="caps">SSL</span> 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.
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 <span class="caps">SSL</span> Implementation==
== Qt SSL Implementation ==


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


==X509 Certificate Handling==
== X509 Certificate Handling ==


* qsslcertificate.h
* qsslcertificate.h  
* qsslcertificate_p.h
* qsslcertificate_p.h  
* qsslcertificate.cpp
* qsslcertificate.cpp  
* qsslcertificateextension.cpp
* qsslcertificateextension.cpp
* qsslcertificateextension.h
* qsslcertificateextension.h  
* qsslcertificateextension_p.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.
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==
== Key Handling ==


* qsslkey.cpp
* qsslkey.cpp  
* qsslkey.h
* qsslkey.h  
* qsslkey_p.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.
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==
== Ciphers ==


* qsslcipher.cpp
* qsslcipher.cpp  
* qsslcipher.h
* qsslcipher.h  
* qsslcipher_p.h
* qsslcipher_p.h  


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


==<span class="caps">API</span> Conveniences==
== API Conveniences ==


* qssl.h
* qssl.h  
* qssl.cpp
* qssl.cpp  


These files provide a set of enums etc. that are used throughout the <span class="caps">SSL</span> code. Currently the .cpp file only exists to provide documentation.
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.h  
* qsslerror.cpp
* qsslerror.cpp


These files provide an interface to the various errors that can happen during <span class="caps">SSL</span>, including getting a user-visible string for the error.
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==
== Socket Handling ==


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


==dlopen Glue==
== dlopen Glue ==


* qsslsocket_openssl_symbols.cpp
* qsslsocket_openssl_symbols.cpp  
* qsslsocket_openssl_symbols_p.h
* qsslsocket_openssl_symbols_p.h  


Qt resolves OpenSSL symbols at run-time, and wraps all needed functions from the OpenSSL <span class="caps">API</span> inside helper functions that check for the presence of the required symbol, and fail gracefully should the symbol not resolve.
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 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 <span class="caps">DEFINEFUNC</span> macro for each of the functions, note these must use the openssl function name, not the q_XXX name. There are versions of the <span class="caps">DEFINEFUNC</span> macro for various numbers of function arguments. In addition, each function has a <span class="caps">RESOLVEFUNC</span> macro that actually handles the call to dlsym. <span class="caps">DEFINEFUNC</span> 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 <span class="caps">API</span> between patch versions.
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.
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==
== 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.
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.
Line 80: Line 76:
A few specific issues to beware of:
A few specific issues to beware of:


* In openssl 1.0 the <span class="caps">STACK</span> type was renamed <span class="caps">STACK</span>_ you’ll need to put an ifdef guard around any use of it.
* 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.
* 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.
* 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.
Line 88: Line 84:
If you are using -openssl option during configure step, remember to install libssl-dev package on Linux platforms.
If you are using -openssl option during configure step, remember to install libssl-dev package on Linux platforms.


==Tested Configurations==
== Tested Configurations ==


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


* Ubuntu 10.04 ×86: openssl 0.9.8k-7ubuntu8.6
* Ubuntu 10.04 x86: openssl 0.9.8k-7ubuntu8.6
* Ubuntu 11.10 ×86: openssl 1.0.0e-2ubuntu4
* Ubuntu 11.10 x86: openssl 1.0.0e-2ubuntu4
* Ubuntu 11.10 ×64: openssl 1.0.0e-2ubuntu4
* Ubuntu 11.10 x64: openssl 1.0.0e-2ubuntu4
* <span class="caps">OSX</span> 10.7 ×64 : openssl 1.0.0d_0
* macOS 10.7 x64 : openssl 1.0.0d_0
* <span class="caps">OSX</span> 10.6 ×64 : openssl 1.0.0e_1
* macOS 10.6 x64 : openssl 1.0.0e_1
* Windows 7 ×86 : Win32OpenSSL 0_9_8o (not enabled)
 
===Categories:===
 
* [[:Category:Developing Qt|Developing_Qt]]

Latest revision as of 22:04, 14 June 2016

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