From 9a30f28c7280ac315f7f9bc80b2335c2ddf22311 Mon Sep 17 00:00:00 2001 From: Andreas Maier Date: Wed, 19 May 2021 23:24:50 +0200 Subject: [PATCH] Certificate verification, part 2 Details: * Changed default to verify the HMC certificate. * Documented how the REQUESTS_CA_BUNDLE and CURL_CA_BUNDLE env vars are used. * Other documentation improvements in the HMC certificate section. Signed-off-by: Andreas Maier --- docs/appendix.rst | 7 +-- docs/changes.rst | 11 +++- docs/security.rst | 89 ++++++++++++++++++++------- tests/unit/zhmcclient/test_session.py | 2 +- zhmcclient/_session.py | 30 ++++++--- 5 files changed, 100 insertions(+), 39 deletions(-) diff --git a/docs/appendix.rst b/docs/appendix.rst index aa2eff6e..1448857a 100644 --- a/docs/appendix.rst +++ b/docs/appendix.rst @@ -72,17 +72,16 @@ The root cause is that the HMC is set up to use a self-signed certificate and the client has used ``verify_cert=True`` in the :class:`zhmcclient.Session` initialization, which is the default. That causes the client to use the Python 'certifi' package for verification of the server certificate and the -'certifi' package rejects self-signed certificates. The 'certifi' package -uses the certificates from the +'certifi' package provides the CA certificates from the `Mozilla Included CA Certificate List `_ -for verifying the server certificate. +which does not include the self-signed certificate. The issue can be temporarily circumvented by specifying ``verify_cert=False``, which disables the verification of the server certificate. Since that makes the connection vulnerable to man-in-the-middle attacks, it should be done only as a temporary circumvention. -The solution is to have your HMC administrator obtain a proper CA-verifyable +The solution is to have your HMC administrator obtain a CA-verifiable certificate and to install that in the HMC. See also the :ref:`Security` section. diff --git a/docs/changes.rst b/docs/changes.rst index b53dfa26..075653d9 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -33,6 +33,10 @@ Released: not yet are now raised as a new exception 'NotificationParseError'. Both new exceptions are based on a new base exception 'NotificationError'. (issue #770) +* By default, the zhmcclient now verifies the HMC certificate using the + CA certificates in the Python 'certifi' package. This can be controlled with + a new 'verify_cert' init parameter to the 'zhmcclient.Session' class. (issue #779) + **Deprecations:** **Bug fixes:** @@ -51,14 +55,17 @@ Released: not yet **Enhancements:** * Added a 'verify_cert' init parameter to the 'zhmcclient.Session' class to - enable verificatin of the server certificate presented by the HMC during - SSL/TLS handshake. + enable verification of the server certificate presented by the HMC during + SSL/TLS handshake. By default, the certificate is validated against + the CA certificates provided in the Python 'certifi' package. (issue #779) * Docs: Added a section "Security" to the documentation that describes security related aspects in the communication between the zhmcclient and the HMC. + (related to issue #779) * Docs: Added a section "Troubleshooting" to appendix of the documentation that currently lists two cases of communication related issues. + (related to issue #779) **Cleanup:** diff --git a/docs/security.rst b/docs/security.rst index 79d66e23..697f0158 100644 --- a/docs/security.rst +++ b/docs/security.rst @@ -22,6 +22,8 @@ This section contains information about the security of the communication between the 'zhmcclient' client and the HMC. +.. _`HMC Web Services API`: + HMC Web Services API -------------------- @@ -53,33 +55,74 @@ You can display the OpenSSL version used by Python using this command: $ python -c "import ssl; print(ssl.OPENSSL_VERSION)" OpenSSL 1.1.1i 8 Dec 2020 -Server certificate -^^^^^^^^^^^^^^^^^^ -By default, the HMC is configured with a self-signed certificate at its -Web Services API. Self-signed certificates are rejected by the 'certifi' package. -The HMC should be configured to use a proper CA-verifyable certificate. This -can be done in the HMC task "Certificate Management". -See also the :term:`HMC Security` book and Chapter 3 "Invoking API operations" -in the :term:`HMC API` book. +.. _`HMC certificate`: + +HMC certificate +^^^^^^^^^^^^^^^ + +By default, the HMC is configured with a self-signed certificate. That is the +X.509 certificate presented by the HMC as the server certificate during SSL/TLS +handshake at its Web Services API. + +Starting with version 0.31, the zhmcclient will reject self-signed certificates +by default. + +The HMC should be configured to use a CA-verifiable certificate. This can be +done in the HMC task "Certificate Management". See also the :term:`HMC Security` +book and Chapter 3 "Invoking API operations" in the :term:`HMC API` book. + +Starting with version 0.31, the zhmcclient provides a control knob for the +verification of the HMC certificate via the ``verify_cert`` init parameter of +the :class:`zhmcclient.Session` class. That init parameter can be set to: + +* `False`: Do not verify the HMC certificate. Not verifying the HMC certificate + means the zhmcclient will not detect hostname mismatches, expired + certificates, revoked certificates, or otherwise invalid certificates. Since + this mode makes the connection vulnerable to man-in-the-middle attacks, it + is insecure and should not be used in production environments. -The 'zhmcclient' package provides a control knob for the verification of the -server certificate presented by the HMC during SSL/TLS handshake via the -``verify_cert`` init parameter of the :class:`zhmcclient.Session` class, which -can be set to: +* `True` (default): Verify the HMC certificate using the CA certificates from + the first of these locations: -* `False`: Do not verify the server certificate. Since that makes - the connection vulnerable to man-in-the-middle attacks, it should not be - used in production environments. + - The file or directory in the ``REQUESTS_CA_BUNDLE`` env.var, if set + - The file or directory in the ``CURL_CA_BUNDLE`` env.var, if set + - The `Python 'certifi' package `_ + (which contains the + `Mozilla Included CA Certificate List `_). -* `True`: Verify the server certificate using the certificates provided by the - `Python 'certifi' package `_, - which are the certificates in the - `Mozilla Included CA Certificate List `_. +* :term:`string`: Path name of a certificate file or directory. Verify the HMC + certificate using the CA certificates in that file or directory. -* :term:`string`: Path name of a CA_BUNDLE certificate file or directory to be - used for verifying the server certificate. For details, see - `SSL Cert Verification `_. +If a certificate file is specified (using any of the ways listed above), that +file must be in PEM format and must contain all CA certificates that are +supposed to be used. Usually they are in the order from leaf to root, but +that is not a hard requirement. The single certificates are concatenated +in the file. + +If a certificate directory is specified (using any of the ways listed above), +it must contain PEM files with all CA certificates that are supposed to be used, +and copies of the PEM files or symbolic links to them in the hashed format +created by the OpenSSL command ``c_rehash``. + +An X.509 certificate in PEM format is base64-encoded, begins with the line +``-----BEGIN CERTIFICATE-----``, and ends with the line +``-----END CERTIFICATE-----``. +More information about the PEM format is for example on this +`www.ssl.com page `_ +or in this `serverfault.com answer `_. + +Since the zhmcclient package uses the 'requests' package for the communication +with the Web Services API of the HMC, the behavior described above actually +comes from the 'requests' package. Unfortunately, its documentation about +certificate verification is somewhat brief, see +`SSL Cert Verification `_. + +Note that setting the ``REQUESTS_CA_BUNDLE`` or ``CURL_CA_BUNDLE`` environment +variables influences other programs that use these variables, too. + + +.. _`Cipher suites`: Cipher suites ^^^^^^^^^^^^^ @@ -130,6 +173,8 @@ Brief expansion of the output field names used by this command: * Mac = Message Authentication Code +.. _`HMC Web Services API notifications`: + HMC Web Services API notifications ---------------------------------- diff --git a/tests/unit/zhmcclient/test_session.py b/tests/unit/zhmcclient/test_session.py index c8849b45..bf5b8f60 100644 --- a/tests/unit/zhmcclient/test_session.py +++ b/tests/unit/zhmcclient/test_session.py @@ -30,7 +30,7 @@ ClientAuthError, DEFAULT_HMC_PORT # Default value for the 'verify_cert' parameter of the Session class: -DEFAULT_VERIFY_CERT = False +DEFAULT_VERIFY_CERT = True # TODO: Test Session.get() in all variations (including errors) diff --git a/zhmcclient/_session.py b/zhmcclient/_session.py index 09c3269f..71c39b8c 100644 --- a/zhmcclient/_session.py +++ b/zhmcclient/_session.py @@ -274,7 +274,7 @@ class Session(object): def __init__(self, host, userid=None, password=None, session_id=None, get_password=None, retry_timeout_config=None, - port=DEFAULT_HMC_PORT, verify_cert=False): + port=DEFAULT_HMC_PORT, verify_cert=True): # pylint: disable=line-too-long """ Creating a session object will not immediately cause a logon to be @@ -358,18 +358,28 @@ def __init__(self, host, userid=None, password=None, session_id=None, Controls whether and how the client verifies the server certificate presented by the HMC during SSL/TLS handshake: - * `False`: Do not verify the server certificate. Since that makes - the connection vulnerable to man-in-the-middle attacks, it should - not be used in production environments. + * `False`: Do not verify the HMC certificate. Not verifying the HMC + certificate means the zhmcclient will not detect hostname + mismatches, expired certificates, revoked certificates, or + otherwise invalid certificates. Since this mode makes the + connection vulnerable to man-in-the-middle attacks, it is insecure + and should not be used in production environments. - * `True`: Verify the server certificate using the certificates - in the - `Mozilla Included CA Certificate List `_. + * `True`: Verify the HMC certificate using the CA certificates from + the first of these locations: - * :term:`string`: Path name of a CA_BUNDLE certificate file or - directory to be used for verifying the server certificate. + - The file or directory in the REQUESTS_CA_BUNDLE env.var, if set + - The file or directory in the CURL_CA_BUNDLE env.var, if set + - The Python 'certifi' package (which contains the + `Mozilla Included CA Certificate List `_). - For details, see the :ref:`Security` section. + * :term:`string`: Path name of a certificate file or directory. + Verify the HMC certificate using the CA certificates in that file + or directory. + + For details, see the :ref:`HMC certificate` section. + + *Added in version 0.31* """ # noqa: E501 # pylint: enable=line-too-long