]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-9216: Expose OpenSSL FIPS_mode() as _hashlib.get_fips_mode() (GH-19703)
authorVictor Stinner <vstinner@python.org>
Wed, 29 Apr 2020 16:04:22 +0000 (18:04 +0200)
committerGitHub <noreply@github.com>
Wed, 29 Apr 2020 16:04:22 +0000 (09:04 -0700)
test.pythoninfo logs OpenSSL FIPS_mode() and Linux
/proc/sys/crypto/fips_enabled in a new "fips" section.

Co-Authored-By: Petr Viktorin <encukou@gmail.com>
Lib/test/pythoninfo.py
Lib/test/test_hashlib.py
Modules/_hashopenssl.c
Modules/clinic/_hashopenssl.c.h

index cc0bbc5fe3e77f9e893ff7ebfe96eec1ae3dbf20..cc228fb3b54c9449fcb0a86b8ae12b882d68d09e 100644 (file)
@@ -720,6 +720,25 @@ def collect_windows(info_add):
         pass
 
 
+def collect_fips(info_add):
+    try:
+        import _hashlib
+    except ImportError:
+        _hashlib = None
+
+    if _hashlib is not None:
+        call_func(info_add, 'fips.openssl_fips_mode', _hashlib, 'get_fips_mode')
+
+    try:
+        with open("/proc/sys/crypto/fips_enabled", encoding="utf-8") as fp:
+            line = fp.readline().rstrip()
+
+        if line:
+            info_add('fips.linux_crypto_fips_enabled', line)
+    except OSError:
+        pass
+
+
 def collect_info(info):
     error = False
     info_add = info.add
@@ -735,6 +754,7 @@ def collect_info(info):
         collect_datetime,
         collect_decimal,
         collect_expat,
+        collect_fips,
         collect_gdb,
         collect_gdbm,
         collect_get_config,
index 33b687e0b408644e6649c279dd6e7249857eea27..31d8e5567639c84b60d12bf3d92cbf1f31b4c5f4 100644 (file)
@@ -856,6 +856,11 @@ class HashLibTestCase(unittest.TestCase):
 
         self.assertEqual(expected_hash, hasher.hexdigest())
 
+    @unittest.skipUnless(hasattr(c_hashlib, 'get_fips_mode'),
+                         'need _hashlib.get_fips_mode')
+    def test_get_fips_mode(self):
+        self.assertIsInstance(c_hashlib.get_fips_mode(), int)
+
 
 class KDFTests(unittest.TestCase):
 
index 0919cd3f47caa3e870ba74f069928fcae576bae2..91834e5330f4bdef48cbcabf819fd8fed97b2438 100644 (file)
@@ -25,6 +25,8 @@
 #include <openssl/objects.h>
 #include "openssl/err.h"
 
+#include <openssl/crypto.h>       // FIPS_mode()
+
 #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
 /* OpenSSL < 1.1.0 */
 #define EVP_MD_CTX_new EVP_MD_CTX_create
@@ -1096,12 +1098,53 @@ generate_hash_name_list(void)
     return state.set;
 }
 
+/* LibreSSL doesn't support FIPS:
+   https://marc.info/?l=openbsd-misc&m=139819485423701&w=2
+
+   Ted Unangst wrote: "I figured I should mention our current libressl policy
+   wrt FIPS mode.  It's gone and it's not coming back." */
+#ifndef LIBRESSL_VERSION_NUMBER
+/*[clinic input]
+_hashlib.get_fips_mode -> int
+
+Determine the OpenSSL FIPS mode of operation.
+
+Effectively any non-zero return value indicates FIPS mode;
+values other than 1 may have additional significance.
+
+See OpenSSL documentation for the FIPS_mode() function for details.
+[clinic start generated code]*/
+
+static int
+_hashlib_get_fips_mode_impl(PyObject *module)
+/*[clinic end generated code: output=87eece1bab4d3fa9 input=c2799c3132a36d6c]*/
+
+{
+    ERR_clear_error();
+    int result = FIPS_mode();
+    if (result == 0) {
+        // "If the library was built without support of the FIPS Object Module,
+        // then the function will return 0 with an error code of
+        // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)."
+        // But 0 is also a valid result value.
+        unsigned long errcode = ERR_peek_last_error();
+        if (errcode) {
+            _setException(PyExc_ValueError);
+            return -1;
+        }
+    }
+    return result;
+}
+#endif  // !LIBRESSL_VERSION_NUMBER
+
+
 /* List of functions exported by this module */
 
 static struct PyMethodDef EVP_functions[] = {
     EVP_NEW_METHODDEF
     PBKDF2_HMAC_METHODDEF
     _HASHLIB_SCRYPT_METHODDEF
+    _HASHLIB_GET_FIPS_MODE_METHODDEF
     _HASHLIB_HMAC_DIGEST_METHODDEF
     _HASHLIB_OPENSSL_MD5_METHODDEF
     _HASHLIB_OPENSSL_SHA1_METHODDEF
index de53e7e196c20674703af6262e610d55e05eaf35..275784dcdcd0e9dffc790ced68e788ee2d62121f 100644 (file)
@@ -725,7 +725,48 @@ exit:
     return return_value;
 }
 
+#if !defined(LIBRESSL_VERSION_NUMBER)
+
+PyDoc_STRVAR(_hashlib_get_fips_mode__doc__,
+"get_fips_mode($module, /)\n"
+"--\n"
+"\n"
+"Determine the OpenSSL FIPS mode of operation.\n"
+"\n"
+"Effectively any non-zero return value indicates FIPS mode;\n"
+"values other than 1 may have additional significance.\n"
+"\n"
+"See OpenSSL documentation for the FIPS_mode() function for details.");
+
+#define _HASHLIB_GET_FIPS_MODE_METHODDEF    \
+    {"get_fips_mode", (PyCFunction)_hashlib_get_fips_mode, METH_NOARGS, _hashlib_get_fips_mode__doc__},
+
+static int
+_hashlib_get_fips_mode_impl(PyObject *module);
+
+static PyObject *
+_hashlib_get_fips_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    PyObject *return_value = NULL;
+    int _return_value;
+
+    _return_value = _hashlib_get_fips_mode_impl(module);
+    if ((_return_value == -1) && PyErr_Occurred()) {
+        goto exit;
+    }
+    return_value = PyLong_FromLong((long)_return_value);
+
+exit:
+    return return_value;
+}
+
+#endif /* !defined(LIBRESSL_VERSION_NUMBER) */
+
 #ifndef _HASHLIB_SCRYPT_METHODDEF
     #define _HASHLIB_SCRYPT_METHODDEF
 #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */
-/*[clinic end generated code: output=acb22ccddb7043c7 input=a9049054013a1b77]*/
+
+#ifndef _HASHLIB_GET_FIPS_MODE_METHODDEF
+    #define _HASHLIB_GET_FIPS_MODE_METHODDEF
+#endif /* !defined(_HASHLIB_GET_FIPS_MODE_METHODDEF) */
+/*[clinic end generated code: output=b0703dd5a043394d input=a9049054013a1b77]*/