如何为使用 Python 打包的 libcrypto 和 libssl 启用 FIPS 模式?
How to enable FIPS mode for libcrypto and libssl packaged with Python?
我有一个 python 应用程序,它与 Python 以及 Libcrypto 和 LibSSL 共享对象打包在一起。该应用程序是使用 Openssl Fips Module 2.0 构建的。 Python 的请求模块和幕后的 urllib3 使用这些共享对象来发出 TLS 请求。
我在构建应用程序的环境中启用了 OPENSSL_FIPS 标志。现在如果要检查共享对象是否启用了fips模式,当我将它们从开发环境中取出并放在另一台机器上时,我该怎么办?
如何查看是否启用了fips模式?如果不是,我如何为这些共享对象启用 fips 模式?
可能有帮助的其他详细信息:
OpenSSL 版本:1.0.2h(从源代码构建)
Fips 模块:2.0.12(从源代码构建)
Python: 3.6
OS:Ubuntu 16.04 LTS
如果需要任何其他详细信息,请告诉我。
谢谢!
我使用常规标志构建了 OpenSSL-fips 模块(例如:no-asm、shared, 一些古老的密码被禁用):
[cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q049320993]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in Whosebug (or other) pages ***
[064bit-prompt]> ls ssl/build/bin ssl/build/lib
ssl/build/bin:
c_rehash openssl
ssl/build/lib:
engines libcrypto.a libcrypto.so libcrypto.so.1.0.0 libssl.a libssl.so libssl.so.1.0.0 pkgconfig
并开始玩它:
[064bit-prompt]> ssl/build/bin/openssl version
OpenSSL 1.0.2h-fips 3 May 2016 (Library: OpenSSL 1.0.2g 1 Mar 2016)
注意“(库:OpenSSL 1.0.2g 2016 年 3 月 1 日)”部分。那(存在)表明 openssl 可执行文件是好的(预期版本),但它使用的是 错误的 libcrypto(这是默认安装在系统上的那个 - 在 /lib 下 - 通常那个不是用 FIPS 构建的支持)。
它必须加载我们的库,这是通过设置LD_LIBRARY_PATH来完成的(同样的行为也可以是通过在构建 OpenSSL 时设置一个 env var 来实现,这将在 openssl 可执行文件中设置 rpath,但是我忘记了,我不想再次构建它):
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl version
OpenSSL 1.0.2h-fips 3 May 2016
现在,设置成功,让我们深入研究 OPENSSL_FIPS env var:
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code.py
MD5(./code.py)= d41d8cd98f00b204e9800998ecf8427e
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code.py
SHA1(./code.py)= da39a3ee5e6b4b0d3255bfef95601890afd80709
[064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code.py
SHA1(./code.py)= da39a3ee5e6b4b0d3255bfef95601890afd80709
[064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code.py
Error setting digest md5
139778679649944:error:060A80A3:digital envelope routines:FIPS_DIGESTINIT:disabled for fips:fips_md.c:180:
从上面可以看出,md5 哈希行为受 OPENSSL_FIPS env 变量的影响(当FIPS模式开启时,不允许使用它)。
备注:
- 很可能,较新的 openssl-fips 版本也将禁用 sha1,因为它被认为是弱的,所以不变量应该是切换到 sha2 哈希函数系列之一(例如 sha256)或更好的 sha3(较旧的OpenSSL 版本可能没有)
- 根据我的 PoV 这有点太严格了,因为在某些情况下,可能需要哈希算法用于不关心安全性的目的,并且更复杂(并且还很耗时)仍然必须使用允许的算法
由于 OPENSSL_FIPS env var 在 openssl 可执行级别处理,这将被绕过(因为libcrypto将被直接使用),它对目前的情况没有用,所以我们必须更深入。这些是在 loaded libcrypto 实例中控制 FIPS 模式的函数:
它们将用于read/write FIPS 模式。为了测试是否真的设置了 FIPS 模式,将使用 md5 哈希(来自上面的示例)。
code.py:
#!/usr/bin/env python3
import sys
import ssl
import ctypes
libcrypto = ctypes.CDLL("libcrypto.so.1.0.0")
fips_mode = libcrypto.FIPS_mode
fips_mode.argtypes = []
fips_mode.restype = ctypes.c_int
fips_mode_set = libcrypto.FIPS_mode_set
fips_mode_set.argtypes = [ctypes.c_int]
fips_mode_set.restype = ctypes.c_int
text = b""
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
print("OPENSSL_VERSION: {:s}".format(ssl.OPENSSL_VERSION))
enable_fips = len(sys.argv) > 1
print("FIPS_mode(): {:d}".format(fips_mode()))
if enable_fips:
print("FIPS_mode_set(1): {:d}".format(fips_mode_set(1)))
print("FIPS_mode(): {:d}".format(fips_mode()))
import hashlib
print("SHA1: {:s}".format(hashlib.sha1(text).hexdigest()))
print("MD5: {:s}".format(hashlib.md5(text).hexdigest()))
备注:
- 为 [Python 3.Docs]: ctypes - A foreign function library for Python
中指定的 2 个函数设置 argtypes 和 restype
- md5 哈希算法由 [Python 3.Docs]: hashlib - Secure hashes and message digests
在 Python 级别提供
- 重要:
import hashlib
语句位于 设置 FIPS 之后模式(而不是在文件开头,因为它应该是),因为 hashlib 在导入时 做了一些缓存 ,所以它捕获 FIPS 导入时的值,不关心之后是否更改
输出:
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code.py
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
OPENSSL_VERSION: OpenSSL 1.0.2h-fips 3 May 2016
FIPS_mode(): 0
FIPS_mode(): 0
SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
MD5: d41d8cd98f00b204e9800998ecf8427e
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code.py 1
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
OPENSSL_VERSION: OpenSSL 1.0.2h-fips 3 May 2016
FIPS_mode(): 0
FIPS_mode_set(1): 1
FIPS_mode(): 1
SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
fips_md.c(149): OpenSSL internal error, assertion failed: Digest Final previous FIPS forbidden algorithm error ignored
Aborted (core dumped)
如上所示,通过 ctypes 设置 FIPS 模式,really 设置它。
我不知道为什么会出现段错误,但是 md5 相关代码仅用于测试目的,因此在生产中不需要它。
我记得在某些 Lnx 版本上(可能基于 RH),FIPS也可以通过编辑一些条目(在 /proc 下?)来设置模式(系统全局),但我不记得了。
一种更优雅的方法 是为这两个函数公开Python 包装器。
检查[Python.Bugs]: FIPS_mode() and FIPS_mode_set() functions in Python (ssl),我也提交了Python 3.4[=182=的补丁](它们被 ssl 模块公开),但基于以下参数被拒绝(其中1st 2 是相关的):
- FIPS 是一个糟糕的标准
- OpenSSL 将放弃对它的支持
- 它打破了共性
您可以将它应用于 Python 3.6(我认为它不会起作用 OOTB,因为行号最有可能改变),并且(显然)你必须从源代码构建 Python。
底线:
- FIPS 工作 和 [= 之间存在 大 差异73=]FIPS 已验证,我相信您已经阅读了 [OpenSSL]: User Guide for the OpenSSL FIPS Object Module v2.0
- [AskUbuntu]: Enable FIPS 140-2 in ubuntu 可能还包含一些有用的信息
更新#0
这只是抚摸我,你在 [SO]: Not able to call FIPS_mode_set() of libcrypto.so with Python ctypes [duplicate] 上遇到的行为也可能是 r错误的 libcrypto 被加载 (检查 openssl version
测试 w/wo LD_LIBRARY_PATH 从头开始)。
不支持 FIPS 的 OpenSSL 仍将导出 2 个函数,但它们都只是 return 0.
[064bit-prompt]> ./code.py 1
Python 3.5.2 (default, Nov 23 2017, 16:37:01)
[GCC 5.4.0 20160609] on linux
OPENSSL_VERSION: OpenSSL 1.0.2g 1 Mar 2016
FIPS_mode(): 0
FIPS_mode_set(1): 0
FIPS_mode(): 0
SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
MD5: d41d8cd98f00b204e9800998ecf8427e
因此,请确保通过指定 LD_LIBRARY_PATH 加载正确的库! (还有其他方法,但这是最直接的一种)。
我有一个 python 应用程序,它与 Python 以及 Libcrypto 和 LibSSL 共享对象打包在一起。该应用程序是使用 Openssl Fips Module 2.0 构建的。 Python 的请求模块和幕后的 urllib3 使用这些共享对象来发出 TLS 请求。
我在构建应用程序的环境中启用了 OPENSSL_FIPS 标志。现在如果要检查共享对象是否启用了fips模式,当我将它们从开发环境中取出并放在另一台机器上时,我该怎么办?
如何查看是否启用了fips模式?如果不是,我如何为这些共享对象启用 fips 模式?
可能有帮助的其他详细信息:
OpenSSL 版本:1.0.2h(从源代码构建)
Fips 模块:2.0.12(从源代码构建)
Python: 3.6
OS:Ubuntu 16.04 LTS
如果需要任何其他详细信息,请告诉我。
谢谢!
我使用常规标志构建了 OpenSSL-fips 模块(例如:no-asm、shared, 一些古老的密码被禁用):
[cfati@cfati-ubtu16x64-0:~/Work/Dev/Whosebug/q049320993]> ~/sopr.sh *** Set shorter prompt to better fit when pasted in Whosebug (or other) pages *** [064bit-prompt]> ls ssl/build/bin ssl/build/lib ssl/build/bin: c_rehash openssl ssl/build/lib: engines libcrypto.a libcrypto.so libcrypto.so.1.0.0 libssl.a libssl.so libssl.so.1.0.0 pkgconfig
并开始玩它:
[064bit-prompt]> ssl/build/bin/openssl version OpenSSL 1.0.2h-fips 3 May 2016 (Library: OpenSSL 1.0.2g 1 Mar 2016)
注意“(库:OpenSSL 1.0.2g 2016 年 3 月 1 日)”部分。那(存在)表明 openssl 可执行文件是好的(预期版本),但它使用的是 错误的 libcrypto(这是默认安装在系统上的那个 - 在 /lib 下 - 通常那个不是用 FIPS 构建的支持)。
它必须加载我们的库,这是通过设置LD_LIBRARY_PATH来完成的(同样的行为也可以是通过在构建 OpenSSL 时设置一个 env var 来实现,这将在 openssl 可执行文件中设置 rpath,但是我忘记了,我不想再次构建它):
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl version OpenSSL 1.0.2h-fips 3 May 2016
现在,设置成功,让我们深入研究 OPENSSL_FIPS env var:
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code.py MD5(./code.py)= d41d8cd98f00b204e9800998ecf8427e [064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code.py SHA1(./code.py)= da39a3ee5e6b4b0d3255bfef95601890afd80709 [064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code.py SHA1(./code.py)= da39a3ee5e6b4b0d3255bfef95601890afd80709 [064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code.py Error setting digest md5 139778679649944:error:060A80A3:digital envelope routines:FIPS_DIGESTINIT:disabled for fips:fips_md.c:180:
从上面可以看出,md5 哈希行为受 OPENSSL_FIPS env 变量的影响(当FIPS模式开启时,不允许使用它)。
备注:
- 很可能,较新的 openssl-fips 版本也将禁用 sha1,因为它被认为是弱的,所以不变量应该是切换到 sha2 哈希函数系列之一(例如 sha256)或更好的 sha3(较旧的OpenSSL 版本可能没有)
- 根据我的 PoV 这有点太严格了,因为在某些情况下,可能需要哈希算法用于不关心安全性的目的,并且更复杂(并且还很耗时)仍然必须使用允许的算法
由于 OPENSSL_FIPS env var 在 openssl 可执行级别处理,这将被绕过(因为libcrypto将被直接使用),它对目前的情况没有用,所以我们必须更深入。这些是在 loaded libcrypto 实例中控制 FIPS 模式的函数:
它们将用于read/write FIPS 模式。为了测试是否真的设置了 FIPS 模式,将使用 md5 哈希(来自上面的示例)。
code.py:
#!/usr/bin/env python3
import sys
import ssl
import ctypes
libcrypto = ctypes.CDLL("libcrypto.so.1.0.0")
fips_mode = libcrypto.FIPS_mode
fips_mode.argtypes = []
fips_mode.restype = ctypes.c_int
fips_mode_set = libcrypto.FIPS_mode_set
fips_mode_set.argtypes = [ctypes.c_int]
fips_mode_set.restype = ctypes.c_int
text = b""
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
print("OPENSSL_VERSION: {:s}".format(ssl.OPENSSL_VERSION))
enable_fips = len(sys.argv) > 1
print("FIPS_mode(): {:d}".format(fips_mode()))
if enable_fips:
print("FIPS_mode_set(1): {:d}".format(fips_mode_set(1)))
print("FIPS_mode(): {:d}".format(fips_mode()))
import hashlib
print("SHA1: {:s}".format(hashlib.sha1(text).hexdigest()))
print("MD5: {:s}".format(hashlib.md5(text).hexdigest()))
备注:
- 为 [Python 3.Docs]: ctypes - A foreign function library for Python 中指定的 2 个函数设置 argtypes 和 restype
- md5 哈希算法由 [Python 3.Docs]: hashlib - Secure hashes and message digests 在 Python 级别提供
- 重要:
import hashlib
语句位于 设置 FIPS 之后模式(而不是在文件开头,因为它应该是),因为 hashlib 在导入时 做了一些缓存 ,所以它捕获 FIPS 导入时的值,不关心之后是否更改
输出:
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code.py Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux OPENSSL_VERSION: OpenSSL 1.0.2h-fips 3 May 2016 FIPS_mode(): 0 FIPS_mode(): 0 SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709 MD5: d41d8cd98f00b204e9800998ecf8427e [064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code.py 1 Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux OPENSSL_VERSION: OpenSSL 1.0.2h-fips 3 May 2016 FIPS_mode(): 0 FIPS_mode_set(1): 1 FIPS_mode(): 1 SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709 fips_md.c(149): OpenSSL internal error, assertion failed: Digest Final previous FIPS forbidden algorithm error ignored Aborted (core dumped)
如上所示,通过 ctypes 设置 FIPS 模式,really 设置它。
我不知道为什么会出现段错误,但是 md5 相关代码仅用于测试目的,因此在生产中不需要它。
我记得在某些 Lnx 版本上(可能基于 RH),FIPS也可以通过编辑一些条目(在 /proc 下?)来设置模式(系统全局),但我不记得了。
一种更优雅的方法 是为这两个函数公开Python 包装器。
检查[Python.Bugs]: FIPS_mode() and FIPS_mode_set() functions in Python (ssl),我也提交了Python 3.4[=182=的补丁](它们被 ssl 模块公开),但基于以下参数被拒绝(其中1st 2 是相关的):
- FIPS 是一个糟糕的标准
- OpenSSL 将放弃对它的支持
- 它打破了共性
您可以将它应用于 Python 3.6(我认为它不会起作用 OOTB,因为行号最有可能改变),并且(显然)你必须从源代码构建 Python。
底线:
- FIPS 工作 和 [= 之间存在 大 差异73=]FIPS 已验证,我相信您已经阅读了 [OpenSSL]: User Guide for the OpenSSL FIPS Object Module v2.0
- [AskUbuntu]: Enable FIPS 140-2 in ubuntu 可能还包含一些有用的信息
更新#0
这只是抚摸我,你在 [SO]: Not able to call FIPS_mode_set() of libcrypto.so with Python ctypes [duplicate] 上遇到的行为也可能是 r错误的 libcrypto 被加载 (检查 openssl version
测试 w/wo LD_LIBRARY_PATH 从头开始)。
不支持 FIPS 的 OpenSSL 仍将导出 2 个函数,但它们都只是 return 0.
[064bit-prompt]> ./code.py 1 Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] on linux OPENSSL_VERSION: OpenSSL 1.0.2g 1 Mar 2016 FIPS_mode(): 0 FIPS_mode_set(1): 0 FIPS_mode(): 0 SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709 MD5: d41d8cd98f00b204e9800998ecf8427e
因此,请确保通过指定 LD_LIBRARY_PATH 加载正确的库! (还有其他方法,但这是最直接的一种)。