如何为Python打包的libcrypto和libssl启用FIPS模式?

brjng4g3  于 2023-03-03  发布在  Python
关注(0)|答案(1)|浏览(116)

我有一个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(从源代码构建)**
    • 巨蟒:3.6**
    • 操作系统:Ubuntu 16.04 LTS**

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

igetnqfo

igetnqfo1#

我使用常规标志构建了 * OpenSSL-FIPS * 模块(例如:* no-asm shared *、禁用某些旧密码):

[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 * 时设置一个env var来实现,该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_FIPSenvvar *:

[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code00.py
MD5(./code00.py)= 47fb26ec5d1ca16d3537fe7fd12ea529
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code00.py
SHA1(./code00.py)= 5188a221ba61309e78e70004285bc6fd148701b6
[064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code00.py
SHA1(./code00.py)= 5188a221ba61309e78e70004285bc6fd148701b6
[064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code00.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_FIPSenv var * 是在 * openssl * 可执行级别处理的,将被绕过(因为 * libcrypto * 将被直接使用),因此对于当前情况没有任何用处,因此我们必须深入研究。以下是在loaded***libcrypto * 示例中控制 * FIPS * 模式的函数:

它们将用于读取/写入 * FIPS * 模式。为了测试是否真正设置了 * FIPS * 模式,将使用 * md5 * 散列(来自上例)。

  • 代码00.py *:
#!/usr/bin/env python

import ctypes as cts
import ssl
import sys

libcrypto = cts.CDLL("libcrypto.so.1.0.0")

#ssleay = libcrypto.SSLeay
#ssleay.argtypes = ()
#ssleay.restype = cts.c_ulong

fips_mode = libcrypto.FIPS_mode
fips_mode.argtypes = ()
fips_mode.restype = cts.c_int

fips_mode_set = libcrypto.FIPS_mode_set
fips_mode_set.argtypes = (cts.c_int,)
fips_mode_set.restype = cts.c_int

def main(*argv):
    text = b""

    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()))
    #print("SSLeay: {:X}".format(ssleay()))

    import hashlib
    print("SHA1: {:s}".format(hashlib.sha1(text).hexdigest()))
    print("MD5: {:s}".format(hashlib.md5(text).hexdigest()))

if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                   64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)
    • 备注**:
  • 为2个函数设置 * argtypes * 和 * restype *。有关详细信息,请查看[SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer)
    • md5 * 散列算法由[Python. Docs]在 * Python * 级别提供:hashlib-安全散列和消息摘要
      • 重要信息**:import hashlib语句位于设置 * FIPS * 模式之后(而不是在文件开头,这是应该的),因为 * hashlib在导入时执行一些缓存,所以它在导入时捕获 * FIPS * 值,而不关心它之后是否更改
    • 输出**:
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code00.py
Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit on linux

OPENSSL_VERSION: OpenSSL 1.0.2h-fips  3 May 2016
FIPS_mode(): 0
FIPS_mode(): 0
SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
MD5: d41d8cd98f00b204e9800998ecf8427e

Done.
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code00.py 1
Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit 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 * 模式,实际上设置了它。
我不知道为什么会出现 * SegFault ,但与 * md5 * 相关的代码仅用于测试目的,因此在生产中不需要。
我记得在一些 * Nix * 版本(可能是基于 * RH * 的)上,也可以通过编辑一些条目(在
/proc * 下?)来设置 * FIPS * 模式(对系统全局),但我不记得了。
一个更优雅的方法是为这两个函数公开 * Python * Package 器。
检查**[Python.Bugs]: FIPS_mode() and FIPS_mode_set() functions in Python (ssl),我还提交了 * Python3.4***的补丁(它们由**ssl**模块公开),但基于以下参数(其中前两个是相关的),它被拒绝了:
1.
FIPS * 是一个糟糕的标准
1.
OpenSSL * 将不再支持它
1.它打破了一般性
您可以将其应用于 * 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 *)。
不支持 * FIPS * 的 * OpenSSL * 仍将导出这2个函数,但它们都只返回0。

[064bit-prompt]> ./code00.py 1
Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit 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

Done.

因此,确保通过指定 * LD_LIBRARY_PATH*加载正确的库(还有其他方法,但这是最直接的一种)。

相关问题