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

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

问题描述

我有一个Python应用程序,该应用程序与Python和Libcrypto和LibSSL共享对象打包在一起.该应用程序是使用Openssl Fips Module 2.0构建的.这些共享库由Python的request模块和urllib3用来进行TLS请求.

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.

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

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?

如何检查是否启用了fips模式?如果不是,我如何为这些共享库启用fips模式?

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版本:1.0.2h(从源构建)

修复模块:2.0.12(从源构建)

Python:3.6

操作系统:Ubuntu 16.04 LTS

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

Please let me know if any additional details are required.

谢谢!

推荐答案

我使用常规标志(例如 no-asm shared (已禁用某些古代密码):

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

并开始使用它:

[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 ,但我忘了,而且我不想再次构建它):

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

现在,设置成功了,让我们进入 OPENSSL_FIPS env var:

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:

从上方可以看出, md5 哈希行为受 OPENSSL_FIPS env var 的影响(当 FIPS 模式已启用,不允许其使用.)

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

注释:

  • 很可能,较新的 openssl-fips 版本也将禁用 sha1 ,因为它被认为是弱的,因此应将不变式切换为 sha2 哈希函数家族(例如 sha256 )或更佳的是 sha3 (旧的 OpenSSL 版本可能没有)
  • 从我的 PoV 来看,这有点太严格了,因为在某些情况下,出于不关心安全性的目的而需要散列算法,并且更加复杂(也很耗时)仍然必须使用允许的算法
  • 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

由于 OPENSSL_FIPS env var 是在 openssl 可执行文件级别处理的,因此将被绕过(如 libcrypto 直接使用),对于当前情况没有用,所以我们必须更深入.以下是在已加载 libcrypto 实例中控制 FIPS 模式的功能:

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:

  • [OpenSSL.Wiki]: FIPS mode()
  • [OpenSSL.Wiki]: FIPS mode set()

它们将用于读取/写入 FIPS 模式.为了测试是否真的设置了 FIPS 模式,将使用 md5 哈希(来自上面的示例).

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}\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()))

注释:

  • Setting the argtypes and restype for the 2 functions like specified in [Python 3.Docs]: ctypes - A foreign function library for Python
  • The md5 hashing algorithm is provided at Python level by [Python 3.Docs]: hashlib - Secure hashes and message digests
  • Important: the import hashlib statement is located after setting the FIPS mode (and not at the file beginning, as it should be), because hashlib does some caching at import time, so it captures the FIPS value at import time, and doesn't care if it changes afterwards

输出:

[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 相关的代码仅用于测试目的,因此在生产中不需要.

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.

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

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.

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

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 是一个不好的标准
  2. OpenSSL 将放弃对此的支持
  3. 它破坏了普遍性
  1. FIPS is a bad standard
  2. OpenSSL will drop support for it
  3. It breaks up generality

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

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.

底线:

  • There's a big difference between FIPS working and FIPS validated, as I'm sure you've read on [OpenSSL]: User Guide for the OpenSSL FIPS Object Module v2.0
  • [AskUbuntu]: Enable FIPS 140-2 in ubuntu might also contain some useful info


这让我很感动,您在

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

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

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天全站免登陆