如何为 Python 打包的 libcrypto 和 libssl 启用 FIPS 模式? [英] How to enable FIPS mode for libcrypto and libssl packaged with Python?

查看:29
本文介绍了如何为 Python 打包的 libcrypto 和 libssl 启用 FIPS 模式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 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

操作系统:Ubuntu 16.04 LTS

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

谢谢!

解决方案

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

<块引用>

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q049320993]>〜/sopr.sh*** 当粘贴到 StackOverflow(或其他)页面时,设置更短的提示以更好地适应 ***[064位提示]>ls ssl/build/bin ssl/build/libssl/构建/bin:c_rehash opensslssl/构建/库:引擎 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 版本OpenSSL 1.0.2h-fips 2016 年 5 月 3 日(库:OpenSSL 1.0.2g 2016 年 3 月 1 日)

注意(库: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 版本OpenSSL 1.0.2h-fips 2016 年 5 月 3 日

现在,设置成功,让我们深入OPENSSL_FIPS环境变量:

<块引用>

[064bit-prompt]>LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code.pyMD5(./code.py)= d41d8cd98f00b204e9800998ecf8427e[064位提示]>LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code.pySHA1(./code.py)= da39a3ee5e6b4b0d3255bfef95601890afd80709[064位提示]>OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code.pySHA1(./code.py)= da39a3ee5e6b4b0d3255bfef95601890afd80709[064位提示]>OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code.py设置摘要 md5 时出错139778679649944:错误:060A80A3:数字信封例程:FIPS_DIGESTINIT:禁用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导入系统导入 ssl导入 ctypeslibcrypto = ctypes.CDLL("libcrypto.so.1.0.0")fips_mode = libcrypto.FIPS_modefips_mode.argtypes = []fips_mode.restype = ctypes.c_intfips_mode_set = libcrypto.FIPS_mode_setfips_mode_set.argtypes = [ctypes.c_int]fips_mode_set.restype = ctypes.c_int文字 = b""如果 __name__ == "__main__":print("Python {:s} on {:s}
".format(sys.version, sys.platform))打印(OPENSSL_VERSION:{:s}".格式(ssl.OPENSSL_VERSION))enable_fips = len(sys.argv) >1打印(FIPS_mode():{:d}".格式(fips_mode()))如果 enable_fips:打印(FIPS_mode_set(1):{:d}".格式(fips_mode_set(1)))打印(FIPS_mode():{:d}".格式(fips_mode()))导入哈希库打印(SHA1:{:s}".格式(hashlib.sha1(文本).hexdigest()))print("MD5: {:s}".format(hashlib.md5(text).hexdigest()))

注意事项:

输出:

<块引用>

[064bit-prompt]>LD_LIBRARY_PATH=ssl/build/lib ./code.pyPython 3.5.2(默认,2017 年 11 月 23 日,16:37:01)[GCC 5.4.0 20160609] 在 linux 上OPENSSL_VERSION:OpenSSL 1.0.2h-fips 2016 年 5 月 3 日FIPS_mode(): 0FIPS_mode(): 0SHA1:da39a3ee5e6b4b0d3255bfef95601890afd80709MD5:d41d8cd98f00b204e9800998ecf8427e[064位提示]>LD_LIBRARY_PATH=ssl/build/lib ./code.py 1Python 3.5.2(默认,2017 年 11 月 23 日,16:37:01)[GCC 5.4.0 20160609] 在 linux 上OPENSSL_VERSION:OpenSSL 1.0.2h-fips 2016 年 5 月 3 日FIPS_mode(): 0FIPS_mode_set(1): 1FIPS_mode(): 1SHA1:da39a3ee5e6b4b0d3255bfef95601890afd80709fips_md.c(149):OpenSSL 内部错误,断言失败:摘要最终前 FIPS 禁止算法错误被忽略中止(核心转储)

正如所见,通过 ctypes 设置 FIPS 模式,真的设置了它.
我不知道它为什么会出现段错误,但是 md5 相关代码仅用于测试目的,因此在生产中不需要.

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

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

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

您可以将其应用于 Python 3.6(我认为它不会OOTB,因为行号很可能已更改),并且(显然)您将必须从源代码构建 Python.

底线:


<小时>

更新#0

它只是抚摸我,你在 [SO]:无法使用 Python ctypes [重复] 调用 libcrypto.so 的 FIPS_mode_set() 也可能与错误的libcrypto 正在加载(从一开始检查 openssl 版本 测试 w/wo LD_LIBRARY_PATH).
不具备FIPS能力的OpenSSL仍将导出这两个函数,但它们都只返回0.

<块引用>

[064bit-prompt]>./code.py 1Python 3.5.2(默认,2017 年 11 月 23 日,16:37:01)[GCC 5.4.0 20160609] 在 linux 上OPENSSL_VERSION:OpenSSL 1.0.2g 2016 年 3 月 1 日FIPS_mode(): 0FIPS_mode_set(1): 0FIPS_mode(): 0SHA1:da39a3ee5e6b4b0d3255bfef95601890afd80709MD5:d41d8cd98f00b204e9800998ecf8427e

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

I have a python application which comes packaged with Python and Libcrypto and LibSSL shared objects. The application was built with Openssl Fips Module 2.0. These shared objects are used by Python's request module and urllib3 under the hood to make TLS requests.

I enabled the OPENSSL_FIPS flag in the environment where i was building the application. Now if want to check whether the shared objects have the fips mode enabled when i take them out of the development environment and put them in another machine, how can i do that?

How can i check whether the fips mode is enabled or not? And if it isn't, how can i enable the fips mode for these shared objects?

Additional Details that might help:

OpenSSL Version: 1.0.2h (built from source)

Fips Module: 2.0.12 (built from source)

Python: 3.6

OS: Ubuntu 16.04 LTS

Please let me know if any additional details are required.

Thanks!

解决方案

I've built the OpenSSL-fips module using regular flags (e.g.: no-asm, shared, some ancient ciphers disabled):

[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

And started playing a little bit with it:

[064bit-prompt]> ssl/build/bin/openssl version
OpenSSL 1.0.2h-fips  3 May 2016 (Library: OpenSSL 1.0.2g  1 Mar 2016)

Note the "(Library: OpenSSL 1.0.2g 1 Mar 2016)" part. That (being present) states that the openssl executable is OK (expected version), but it's using a wrong libcrypto (it's the one that comes installed by default on the system - under /lib - and typically that one isn't built with FIPS support).
It must load our libraries, and that is done by setting LD_LIBRARY_PATH (the same behavior could have also been achieved by setting an env var when building OpenSSL that would have set the rpath in the openssl executable, but I forgot, and I didn't want to build it again):

[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl version
OpenSSL 1.0.2h-fips  3 May 2016

Now, that the setup is successful, let's dive into 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:

As seen from above, the md5 hash behavior is influenced by the OPENSSL_FIPS env var (when FIPS mode is on, its usage is not allowed).

Notes:

  • Most likely, newer openssl-fips versions will also have sha1 disabled since it's considered weak, so the invariant should be switched to one of the sha2 hash functions family (e.g. sha256) or even better, sha3 (older OpenSSL versions might not have it)
  • From my PoV this is a little too restrictive, as there might be cases when a hashing algorithm is needed for purposes that don't care about security, and more complex (and also time consuming) allowed algorithms still have to be used

Since OPENSSL_FIPS env var is handled at openssl executable level, which will be bypassed (as libcrypto will be used directly), it's no use for the current situation, so we have to go deeper. These are the functions that control FIPS mode in a loaded libcrypto instance:

They will be used to read/write FIPS mode. In order to test whether FIPS mode is really set, md5 hash (from the example above) will be used.

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}
".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()))

Notes:

Output:

[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)

As seen, setting FIPS mode via ctypes, really sets it.
I don't know why it segfaults, but the md5 related code is there only for testing purposes, so it's not needed in production.

I remember that on some Lnx version (might be RH based), FIPS mode could also be set (globally for the system), by editing some entry (under /proc ?), but I can't remember it.

A more elegant approach would be to expose Python wrappers for the 2 functions.
Check [Python.Bugs]: FIPS_mode() and FIPS_mode_set() functions in Python (ssl), I've also submitted a patch for Python 3.4 (where they were exposed by the ssl module), but it was rejected based on the following arguments (out of which the 1st 2 are relevant):

  1. FIPS is a bad standard
  2. OpenSSL will drop support for it
  3. It breaks up generality

You can apply it to Python 3.6 (I don't think it will work OOTB, since line numbers most likely changed), and (obviously) you'll have to build Python from sources.

Bottom line:



Update #0

It just stroke me, the behavior that you're encountering on [SO]: Not able to call FIPS_mode_set() of libcrypto.so with Python ctypes [duplicate] might also be related to the wrong libcrypto being loaded (check the openssl version tests w/wo LD_LIBRARY_PATH from the beginning).
A non FIPS capable OpenSSL will still export the 2 functions, but they both simply 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

So, make sure to load the correct libraries by specifying LD_LIBRARY_PATH ! (there are other ways, but this is the most straightforward one).

这篇关于如何为 Python 打包的 libcrypto 和 libssl 启用 FIPS 模式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆