【问题标题】:How to enable FIPS mode for libcrypto and libssl packaged with Python?如何为 Python 打包的 libcrypto 和 libssl 启用 FIPS 模式?
【发布时间】:2018-08-25 12:51:12
【问题描述】:

我有一个 Python 应用程序,它与 Python 和 Libcrypto 以及 LibSSL 共享对象一起打包。该应用程序是使用 Openssl Fips Module 2.0 构建的。 Python 的 request 模块和 urllib3 在后台使用这些共享对象来发出 TLS 请求。

我在构建应用程序的环境中启用了 OPENSSL_FIPS 标志。现在如果想检查共享对象是否在我将它们从开发环境中取出并放入另一台机器时是否启用了fips模式,我该怎么做?

如何查看是否启用了 fips 模式?如果不是,如何为这些共享对象启用 fips 模式?

可能有帮助的其他详细信息:

OpenSSL 版本:1.0.2h(从源代码构建)

Fips 模块:2.0.12(从源代码构建)

Python:3.6

操作系统:Ubuntu 16.04 LTS

如果需要任何其他详细信息,请告诉我。

谢谢!

【问题讨论】:

  • 您是否有更多详细信息,例如OpenSSLPython 版本,无论您是从源代码构建它们还是只是下载了二进制文件,您应该在该 OS 上运行。
  • 是的,我期待这样的评论。实际上,我不确定要回答这个问题需要哪些细节。问题已更新。如果需要任何其他详细信息,请告诉我。

标签: python python-3.x ssl openssl ctypes


【解决方案1】:

我已经使用常规标志构建了 OpenSSL-fips 模块(例如:no-asmshared、一些古老的密码被禁用) :

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049320993]> ~/sopr.sh
*** Set shorter prompt to better fit when pasted in StackOverflow (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时设置一个环境变量来实现 会在 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 var 的影响(当 FIPS模式已开启,不允许使用)。

注意事项

  • 很可能,较新的 openssl-fips 版本也将禁用 sha1,因为它被认为是弱的,因此应将不变量切换到 sha2 哈希函数系列(例如 sha256)甚至更好的 sha3(旧的 OpenSSL 版本可能没有它)
  • 从我的 PoV 来看,这有点过于严格,因为在某些情况下,可能需要哈希算法来实现不关心安全性的目的,并且更复杂(而且也很耗时)仍然必须使用允许的算法

由于 OPENSSL_FIPS env varopenssl 可执行级别处理,这将被绕过(因为 libcrypto 将直接使用),对于目前的情况没有用,所以我们必须深入。这些是在 已加载 libcrypto 实例中控制 FIPS 模式的函数:

它们将用于读/写 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()))

注意事项

输出

[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 模式,真的 设置它。
我不知道为什么会出现段错误,但是 md5 相关代码仅用于测试目的,因此在生产中不需要。

我记得在某些 Lnx 版本上(可能基于 RH),还可以设置 FIPS 模式(系统全局) ,通过编辑一些条目(在 /proc 下?),但我不记得了。

更优雅的方法是为这 2 个函数公开 Python 包装器。
检查 [Python.Bugs]: FIPS_mode() and FIPS_mode_set() functions in Python (ssl),我还提交了 Python 3.4 的补丁(ssl 模块),但基于以下参数被拒绝(其中 1st 2 是相关的):

  1. FIPS 是一个糟糕的标准
  2. OpenSSL 将不再支持它
  3. 它打破了一般性

你可以将它应用到 Python 3.6(我认为它不会工作 OOTB,因为行号很可能会改变),并且(显然)你会必须从源代码构建Python

底线



更新#0

这让我很震惊,您在 [SO]: Not able to call FIPS_mode_set() of libcrypto.so with Python ctypes [duplicate] 上遇到的行为也可能与 错误的 libcrypto 正在加载有关(检查 openssl version 测试w/wo LD_LIBRARY_PATH 从头开始​​)。
不支持 FIPSOpenSSL 仍将导出这 2 个函数,但它们都只返回 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 加载正确的库! (还有其他方法,但这是最直接的一种)。

【讨论】:

  • 再次感谢您提供如此详细的答复。这就像一个魅力!对于您的 Edit0,我在其他 SO 问题上遇到的行为也可能与 LD_LIBRARY_Flag 有关,您是对的!我可以通过指定标志来切换 fips。
  • 很高兴为您提供帮助!
  • 嗨!如果您能查看我发布的后续问题,我将不胜感激:stackoverflow.com/questions/49493537/…。谢谢!
  • 嗨!如果你能看看,我真的很感激。我在 3.7 python 上遵循 Stack Overflow stackoverflow.com/questions/49493537/… 并且编译工作正常。但是当我运行下面的 code.py 脚本时,md5 仍然可以正常工作。理想情况下,md5 应该会失败。这里有什么问题?脚本和输出在这里pastebin.com/0Sn7qYcs
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 2018-10-17
  • 2013-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多