This patch significantly changes the callback that is called upon receiving an incoming SSL connection. Since this callback is called not only with the certificate that the client sends, but also (in some implementations) with the entire certificate chain of the client certificate.
In our case, the certficate chain contains the client certificate and the server certificate as the one that signed the client certificate. This means that we have to accept the server certificate, but only if we receive it with the 'depth' greater than 0, meaning that this is part of the chain and not the actual certificate. If the depth value is 0, we can be sure to have received the actual certficate and match it against the list of master candidate certificates as before. Signed-off-by: Helga Velroyen <[email protected]> --- lib/server/noded.py | 51 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/lib/server/noded.py b/lib/server/noded.py index a7fdf49..581ef27 100644 --- a/lib/server/noded.py +++ b/lib/server/noded.py @@ -1262,22 +1262,49 @@ def SSLVerifyPeer(conn, cert, errnum, errdepth, ok): @param conn: the OpenSSL connection object @type cert: C{OpenSSL.X509} @param cert: the peer's SSL certificate + @type errdepth: integer + @param errdepth: number of the step in the certificate chain starting at 0 + for the actual client certificate. """ # some parameters are unused, but this is the API # pylint: disable=W0613 - sstore = ssconf.SimpleStore() - try: - candidate_certs = sstore.GetMasterCandidatesCertMap() - except errors.ConfigurationError: - logging.info("No candidate certificates found. Switching to " - "bootstrap/update mode.") - candidate_certs = None - if not candidate_certs: - candidate_certs = { - constants.CRYPTO_BOOTSTRAP: utils.GetCertificateDigest( - cert_filename=pathutils.NODED_CERT_FILE)} - return cert.digest("sha1") in candidate_certs.values() + + # If we receive a certificate from the certificate chain that is higher + # than the lowest element of the chain, we have to check it against the + # server certificate. + if errdepth > 0: + server_digest = utils.GetCertificateDigest( + cert_filename=pathutils.NODED_CERT_FILE) + match = cert.digest("sha1") == server_digest + if not match: + logging.debug("Received certificate from the certificate chain, which" + " does not match the server certficate. Digest of the" + " received certificate: %s. Digest of the server" + " certificate: %s.", cert.digest("sha1"), server_digest) + return match + elif errdepth == 0: + sstore = ssconf.SimpleStore() + try: + candidate_certs = sstore.GetMasterCandidatesCertMap() + except errors.ConfigurationError: + logging.info("No candidate certificates found. Switching to " + "bootstrap/update mode.") + candidate_certs = None + if not candidate_certs: + candidate_certs = { + constants.CRYPTO_BOOTSTRAP: utils.GetCertificateDigest( + cert_filename=pathutils.NODED_CERT_FILE)} + match = cert.digest("sha1") in candidate_certs.values() + if not match: + logging.debug("Received certificate which is not a certificate of a" + " master candidate. Certificate digest: %s. List of master" + " candidate certificate digests: %s.", cert.digest("sha1"), + str(candidate_certs)) + return match + else: + logging.error("Invalid errdepth value: %s.", errdepth) + return False # pylint: enable=W0613 -- 2.4.3.573.g4eafbef
