为了账号安全,请及时绑定邮箱和手机立即绑定

OpenSSL FIPS_mode_set 在 Python 密码库中不起作用

OpenSSL FIPS_mode_set 在 Python 密码库中不起作用

弑天下 2022-06-14 15:28:26
根据 Python Cryptography library 的文档 [1],可以使用静态链接的 OpenSSL 构建自定义密码轮。我尝试使用使用 FIPS 对象模块构建的 OpenSSL 安装来执行此操作,并且能够成功构建轮子,但发现它没有 FIPS 功能(无法设置 FIPS_mode_set=1)。我创建了一个可以重现相同结果的 Dockerfile。最后的 Python 代码应该显示“1”和“OpenSSL 1.0.2t-fips 10 Sep 2019”,而是显示“0”和“OpenSSL 1.0.2t 2019 年 9 月 10 日”(未-fips指定)。令我难以置信的是,当我调用openssl version我构建的 CLI 时,它正确显示了带有-fips后缀的版本。因为,我猜我在构建密码学的某个地方出错了。在这里感谢任何帮助!FROM centos# Install build dependenciesRUN yum groupinstall -y  "Development Tools" && \    yum install -y python-devel libffi-devel# Install Python dependenciesRUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \    python get-pip.py && \    pip install virtualenv setuptools wheel pip# Build Fips object moduleRUN curl -O https://www.openssl.org/source/openssl-fips-2.0.16.tar.gz && \    tar xvf openssl-fips-2.0.16.tar.gz && \    cd openssl-fips-2.0.16 && \    ./config && \    make && \    make install# Build OpenSSLRUN curl -O https://www.openssl.org/source/openssl-1.0.2t.tar.gz && \    tar xvf openssl-1.0.2t.tar.gz && \    cd /openssl-1.0.2t && \    ./config fips no-shared -fPIC --prefix=/openssl-1.0.2t/openssl && \    make depend && \    make && \    make install_sw# Build cryptographyRUN CFLAGS="-I/openssl-1.0.2t/openssl/include" LDFLAGS="-L/openssl-1.0.2t/openssl/lib" pip wheel --no-cache --no-binary :all: cryptography && \    pip install cryptography*.whl# Test if fips is enabledRUN python -c "\from cryptography.hazmat.backends.openssl.backend import backend;\print backend._lib.FIPS_mode_set(1);\print ''.join([backend._lib.OPENSSL_VERSION_TEXT[i] for i in range(30)])"[1] https://cryptography.io/en/latest/installation/#static-wheels
查看完整描述

1 回答

?
牛魔王的故事

TA贡献1830条经验 获得超3个赞

1. 一般

首先,我想提一下,虽然我明白其中的原因,但我并不完全认同Cryptography的设想([Cryptography]: Installation - Static Wheels)。共享库已经存在了几十年,并且已经证明了它们的优越性。更不用说Python提供了2 个(标准)模块(_ssl_hashlib),它们动态链接到OpenSSL(无论它在系统上是什么)。附带说明一下,在Win上,2 个Python模块也用于静态链接到OpenSSL,但从3.7开始,它们不再这样做。回到Nix:2 个OpenSSL版本被加载到同一个 ( Python ) 进程中。它似乎没有伤害,但它看起来很有趣。和今天一样(191009),有一堆.whl用于v2.7v3.4,但没有一个相当不错的(Python)环境:


//img1.sycdn.imooc.com//62a838c90001dec819141076.jpg

我记得前段时间有一个类似的情况:除了2个标准模块外,还使用了M2Crypto 。在那种情况下(我们完全交付了Python),也交付了 2 个特定的(支持 FIPS的)OpenSSL动态,并且所有的Python模块都链接到它们。它适用于各种(桌面)环境(其中许多“异国情调”的环境):

  • CPU架构 ( LE / BE ): x86 , AMD64 , IA64 , SPARC , PPC , zSeries

  • 操作系统(有多个版本):WinLnxRHCentOSOELSuSEXenUbuntu)、SolarisAIXHP-UX(作为个人练习,我添加了OSX

[OpenSSL]:UserGuide-2.0.pdf - OpenSSL FIPS 对象模块 v2.0 的用户指南(引用自[OpenSSL]:FIPS-140以防URL更改)包含所有需要的详细信息。

在继续之前,这里有一些我将在整个帖子中使用的术语:

  • FOM - FIPS对象模块 ( fipscanister.o )

  • FOME - FOM链接的可执行文件(ELFWin上的PE))。请记住,它本身可以是可执行文件,也可以是.so ( .dll )。此外,如果它包含在静态库 ( .a ) 中,它不会被链接(只是存档)。附带说明一下,当OpenSSL构建为共享时,FOMElibcrypto.so.*,而当静态构建时(如本例中),它是与libcrypto.a链接的可执行文件(例如openssl可执行文件)

FOM位于OpenSSL(可能还有其他类似的密码学提供程序,如LibreSSLWolfSSL等)之上,它旨在通过限制一些原本可用的功能来增强安全性(根据NIST标准)。一个这样的功能示例是md5哈希的使用,它被认为是弱的(我很确定sha1也会遵循,在即将发布的下一个版本中)。
这是(在运行时)发生的事情的(非常简化的)版本:

  1. FIPS模式开启:

    1. 是:继续(使用默认功能)

    2. 否:返回错误

    3. 检查是否满足附加约束:

  2. FIPS模式关闭:

    1. 回退到默认功能

#1.1的一部分。是自测。这包括:

  • 计算FOME签名

  • 将其与一个值(也存储在FOME中)进行比较

这恰好确保(或大大减少机会)没有人篡改(手动修改、拆卸......)FOME。为了更好地理解签名机制,让我们深入了解FOME构建过程:

  1. 所有FOME源 + FOM都被编译(到目标文件中)

  2. 它们链接在一起(进入FOME)。这是正常构建结束的时间

  3. 正在计算 FOME签名

    1. #1 中的项目。+ fips_premain.o被链接到一个(真正的,不是.dll)可执行文件(FPD

    2. 针对FOME ( #1. )调用FPD 。它读取FOME.rodata部分并计算其sha1哈希。请注意,它忽略了位于特定地址的41字节区域(打孔)

  4. #3.1。重复,但这次fips_premain.o被重新编译以包含上一步的哈希。现在很清楚上一步的打孔,它是签名的地方:(sha hash 的长度(40)+ nul)。这是最终的FOME

注意:在Win上,情况会有所不同。

我设法重现了这个问题。我将从测试脚本开始。

code00.py:

#!/usr/bin/env python3


import sys

from cryptography.hazmat.backends.openssl.backend import backend

import cffi



def main():

    ffi = cffi.FFI()

    lib = backend._lib

    fmt = "OpenSSL version: {0:s}\nFIPS_mode(): {1:d}\nFIPS_mode_set(1): {2:d}\nFIPS_mode(): {3:d}"

    print(fmt.format(ffi.string(lib.OPENSSL_VERSION_TEXT).decode(),

                    lib.FIPS_mode(), lib.FIPS_mode_set(1), lib.FIPS_mode()))

    err = lib.ERR_get_error()

    if err:

        err_fmt = "error:[{0:d}]:[{1:s}]:[{2:s}]:[{3:s}]"

        print(err_fmt.format(

                err,

                ffi.string(lib.ERR_lib_error_string(err)).decode(),

                ffi.string(lib.ERR_func_error_string(err)).decode(),

                ffi.string(lib.ERR_reason_error_string(err)).decode()

        ))

    else:

        print("Success !!!")



if __name__ == "__main__":

    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))

    main()

    print("\nDone.")

2. 设置

我已经构建了FOM和支持FIPS的OpenSSL(与您的类似,但我自定义了它们的路径)。在构建FOM和OpenSSL时使用了 ${FIPSDIR}变量。


[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q058228435]> ~/sopr.sh

*** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***


[064bit-prompt]> uname -a

Linux cfati-ubtu16x64-0 4.15.0-65-generic #74~16.04.1-Ubuntu SMP Wed Sep 18 09:51:44 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

[064bit-prompt]> cat /etc/lsb-release | grep DESCR

DISTRIB_DESCRIPTION="Ubuntu 16.04.6 LTS"

[064bit-prompt]> gcc --version | grep gcc

gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609

[064bit-prompt]>

[064bit-prompt]> echo ${FIPSDIR}

/home/cfati/Work/Dev/Tools/zzz_Build/OpenSSL/int/openssl-fips-2.0.16

[064bit-prompt]> tree ${FIPSDIR}

/home/cfati/Work/Dev/Tools/zzz_Build/OpenSSL/int/openssl-fips-2.0.16

├── bin

│   ├── fipsld

│   └── fips_standalone_sha1

├── include

│   └── openssl

│       ├── aes.h

│       ├── bn.h

│       ├── buffer.h

│       ├── cmac.h

│       ├── crypto.h

│       ├── des.h

│       ├── des_old.h

│       ├── dh.h

│       ├── dsa.h

│       ├── ebcdic.h

│       ├── ecdh.h

│       ├── ecdsa.h

│       ├── ec.h

│       ├── e_os2.h

│       ├── evp.h

│       ├── fips.h

│       ├── fips_rand.h

│       ├── fipssyms.h

│       ├── hmac.h

│       ├── modes.h

│       ├── opensslconf.h

│       ├── opensslv.h

│       ├── ossl_typ.h

│       ├── rsa.h

│       ├── sha.h

│       └── symhacks.h

└── lib

    ├── fipscanister.o

    ├── fipscanister.o.sha1

    ├── fips_premain.c

    └── fips_premain.c.sha1


4 directories, 32 files

[064bit-prompt]>

[064bit-prompt]> echo ${OPENSSL_DIR}

/home/cfati/Work/Dev/Tools/openssl-1.0.2t-fips-2.0.16-static

[064bit-prompt]> tree ${OPENSSL_DIR}/bin ${OPENSSL_DIR}/lib

/home/cfati/Work/Dev/Tools/openssl-1.0.2t-fips-2.0.16-static/bin

├── c_rehash

└── openssl

/home/cfati/Work/Dev/Tools/openssl-1.0.2t-fips-2.0.16-static/lib

├── engines

├── libcrypto.a

├── libssl.a

└── pkgconfig

    ├── libcrypto.pc

    ├── libssl.pc

    └── openssl.pc


2 directories, 7 files

[064bit-prompt]>

[064bit-prompt]> ldd ${OPENSSL_DIR}/bin/openssl

    linux-vdso.so.1 =>  (0x00007ffeec045000)

    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f12c19c2000)

    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f12c15f8000)

    /lib64/ld-linux-x86-64.so.2 (0x00007f12c1bc6000)

[064bit-prompt]>

[064bit-prompt]> ${OPENSSL_DIR}/bin/openssl version

OpenSSL 1.0.2t-fips  10 Sep 2019

[064bit-prompt]> ${OPENSSL_DIR}/bin/openssl sha1 ./code00.py

SHA1(./code00.py)= ff122260b025103dbc03316e3d3e26cd683e7a12

[064bit-prompt]> ${OPENSSL_DIR}/bin/openssl md5 ./code00.py

MD5(./code00.py)= eac85e46734260c1bfcceb89d6a3bd32

[064bit-prompt]> OPENSSL_FIPS=1 ${OPENSSL_DIR}/bin/openssl sha1 ./code00.py

SHA1(./code00.py)= ff122260b025103dbc03316e3d3e26cd683e7a12

[064bit-prompt]> OPENSSL_FIPS=1 ${OPENSSL_DIR}/bin/openssl md5 ./code00.py

Error setting digest md5

140584610875032:error:060A80A3:digital envelope routines:FIPS_DIGESTINIT:disabled for fips:fips_md.c:180:

3.密码学模块

[064bit-prompt]> ls

code00.py  cryptography-2.7.tar.gz

[064bit-prompt]> mkdir build

[064bit-prompt]> cd build

[064bit-prompt]>

[064bit-prompt]> CFLAGS="-I${OPENSSL_DIR}/include -DOPENSSL_FIPS=1" LDFLAGS="-L${OPENSSL_DIR}/lib" python3 -m pip wheel --no-cache --no-binary :all: ../cryptography-2.7.tar.gz

Processing /home/cfati/Work/Dev/StackOverflow/q058228435/cryptography-2.7.tar.gz

  Installing build dependencies ... done

  Getting requirements to build wheel ... done

    Preparing wheel metadata ... done

Collecting asn1crypto>=0.21.0 (from cryptography==2.7)

  Downloading https://files.pythonhosted.org/packages/d1/e2/c518f2bc5805668803ebf0659628b0e9d77ca981308c7e9e5564b30b8337/asn1crypto-1.0.1.tar.gz (115kB)

     |████████████████████████████████| 122kB 801kB/s

Collecting cffi!=1.11.3,>=1.8 (from cryptography==2.7)

  Downloading https://files.pythonhosted.org/packages/93/1a/ab8c62b5838722f29f3daffcc8d4bd61844aa9b5f437341cc890ceee483b/cffi-1.12.3.tar.gz (456kB)

     |████████████████████████████████| 460kB 1.8MB/s

Collecting six>=1.4.1 (from cryptography==2.7)

  Downloading https://files.pythonhosted.org/packages/dd/bf/4138e7bfb757de47d1f4b6994648ec67a51efe58fa907c1e11e350cddfca/six-1.12.0.tar.gz

Collecting pycparser (from cffi!=1.11.3,>=1.8->cryptography==2.7)

  Downloading https://files.pythonhosted.org/packages/68/9e/49196946aee219aead1290e00d1e7fdeab8567783e83e1b9ab5585e6206a/pycparser-2.19.tar.gz (158kB)

     |████████████████████████████████| 163kB 4.5MB/s

Building wheels for collected packages: cryptography, asn1crypto, cffi, six, pycparser

  Building wheel for cryptography (PEP 517) ... done

  Stored in directory: /home/cfati/Work/Dev/StackOverflow/q058228435/build

  Building wheel for asn1crypto (setup.py) ... done

  Stored in directory: /home/cfati/Work/Dev/StackOverflow/q058228435/build

  Building wheel for cffi (setup.py) ... done

  Stored in directory: /home/cfati/Work/Dev/StackOverflow/q058228435/build

  Building wheel for six (setup.py) ... done

  Stored in directory: /home/cfati/Work/Dev/StackOverflow/q058228435/build

  Building wheel for pycparser (setup.py) ... done

  Stored in directory: /home/cfati/Work/Dev/StackOverflow/q058228435/build

Successfully built cryptography asn1crypto cffi six pycparser

WARNING: You are using pip version 19.1.1, however version 19.2.3 is available.

You should consider upgrading via the 'pip install --upgrade pip' command.

[064bit-prompt]>

[064bit-prompt]> ls

asn1crypto-1.0.1-py3-none-any.whl        cryptography-2.7-cp35-cp35m-linux_x86_64.whl  six-1.12.0-py2.py3-none-any.whl

cffi-1.12.3-cp35-cp35m-linux_x86_64.whl  pycparser-2.19-py2.py3-none-any.whl

[064bit-prompt]>

[064bit-prompt]> for f in $(ls *.whl); do unzip ${f} > /dev/null; done

[064bit-prompt]> ls

asn1crypto                         cffi-1.12.3-cp35-cp35m-linux_x86_64.whl        cryptography-2.7-cp35-cp35m-linux_x86_64.whl  pycparser-2.19-py2.py3-none-any.whl

asn1crypto-1.0.1.dist-info         cffi-1.12.3.dist-info                          cryptography-2.7.dist-info                    six-1.12.0.dist-info

asn1crypto-1.0.1-py3-none-any.whl  _cffi_backend.cpython-35m-x86_64-linux-gnu.so  pycparser                                     six-1.12.0-py2.py3-none-any.whl

cffi                               cryptography                                   pycparser-2.19.dist-info                      six.py

[064bit-prompt]> PYTHONPATH=.:${PYTHONPATH} python3 ../code00.py

Python 3.5.2 (default, Jul 10 2019, 11:58:48) [GCC 5.4.0 20160609] 64bit on linux


OpenSSL version: OpenSSL 1.0.2t-fips  10 Sep 2019

FIPS_mode(): 0

FIPS_mode_set(1): 0

FIPS_mode(): 0

error:[755413103]:[FIPS routines]:[FIPS_check_incore_fingerprint]:[fingerprint does not match]


Done.

正如所见,我几乎在你所在的地方。

4. 更深的潜水

经过长时间(有些人可能认为是痛苦的)调试、试验……,我得出了一个结论。考虑到:

  • 篡改FOM中的任何内容(${FIPSDIR}的内容)将无法获得FIPS验证的资格。坦率地说,这也不是,因为有特定说明,在构建FOM时,只有系统管理员应该将工件复制到安全位置......,bla,bla,bla。这对我来说似乎是偏执狂,但这些都是事实。作为评论,早在 2013 年,当我们第一次接触FIPS时(可能是为了防止任何可能的攻击(例如MITM)),FOMCD是从美国运到ROU :)))

  • 默认Python版本是静态(再次:))构建的,这意味着${PYTHONCORE}Python解释器)驻留在python可执行文件中,而不是可以链接到的.solibpython*.so* )中(并且python可执行文件在共享构建的情况下执行)

  • Cryptography_openssl扩展模块(_openssl.abi*.so)需要来自${PYTHONCORE}的符号(例如PyLong_FromLong),但这没关系,因为此时它将被加载到(Python)进程中(从上述可执行文件启动) ,它会找到它们(这是Nix的常见做法)

  • 构建步骤#3.2。:可执行文件(FPD - 必须运行)找不到符号,因此失败

这是一个死锁(无论一个约束离开什么房间,都被其他人关闭),所以它根本无法完成!!!(至少,在这个时候)。时期!!!X(

5.替代

我将建议这是一个优雅的替代方案(包括 .whl 中的OpenSSL .so s(任何 ( .so ) 客户端的rpath设置为“那里”),在_openssl.abi3.so旁边链接到它们) ,但显然这是唯一的方法(至少我找到了)。

第一步是构建一个共享的OpenSSL版本(FOMElibcrypto.so.*)。

[064bit-prompt]> ls

code00.py  cryptography-2.7.tar.gz

[064bit-prompt]> export OPENSSL_DIR=/home/cfati/Work/Dev/Tools/openssl-1.0.2t-fips-2.0.16

[064bit-prompt]> ldd ${OPENSSL_DIR}/bin/openssl

        linux-vdso.so.1 =>  (0x00007ffe62faf000)

        libssl.so.1.0.0 => /home/cfati/Work/Dev/Tools/openssl-1.0.2t-fips-2.0.16/lib/libssl.so.1.0.0 (0x00007fe33c06f000)

        libcrypto.so.1.0.0 => /home/cfati/Work/Dev/Tools/openssl-1.0.2t-fips-2.0.16/lib/libcrypto.so.1.0.0 (0x00007fe33bb92000)

        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe33b7c8000)

        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe33b5c4000)

        /lib64/ld-linux-x86-64.so.2 (0x00007fe33c2e3000)

[064bit-prompt]>

[064bit-prompt]> ${OPENSSL_DIR}/bin/openssl version

OpenSSL 1.0.2t-fips  10 Sep 2019

[064bit-prompt]> ${OPENSSL_DIR}/bin/openssl md5 ./code00.py

MD5(./code00.py)= eac85e46734260c1bfcceb89d6a3bd32

[064bit-prompt]> OPENSSL_FIPS=1 ${OPENSSL_DIR}/bin/openssl md5 ./code00.py

Error setting digest md5

139796140275352:error:060A80A3:digital envelope routines:FIPS_DIGESTINIT:disabled for fips:fips_md.c:180

经过另一次深潜(许多失败的尝试),我能够让它工作。但是,采取了很多措施:

人工干预

黑客

(蹩脚)解决方法(gainarii)

恐怕如果我把所有东西都放在这里,它会超过30K 字符的限制([SE.Meta]:了解你的限制:使用的问题标题、帖子、图片和链接的最大长度是多少?) .


但是,我在[GitHub] 上发布了.whl :CristiFati/Prebuilt-Binaries - (master) Prebuilt-Binaries/Cryptography/v2.7。到目前为止,它仅适用于Python 3.5 ( 64bit ),因为它是Ubuntu 16上的默认版本。如果您使用另一个(较新)版本,请告诉我,我会得到它(也许自己构建它),并为该版本构建.whl(无论如何我都会这样做)。


将原始.whl替换为我构建的之后:


[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q058228435/build]> ll

total 2936

drwxrwxr-x 2 cfati cfati    4096 Oct  9 21:40 .

drwxrwxr-x 4 cfati cfati    4096 Oct  9 21:28 ..

-rw-rw-r-- 1 cfati cfati  108067 Oct  9 08:43 asn1crypto-1.0.1-py3-none-any.whl

-rw-rw-r-- 1 cfati cfati  318045 Oct  9 08:43 cffi-1.12.3-cp35-cp35m-linux_x86_64.whl

-rw-rw-r-- 1 cfati cfati 2438739 Oct  9 21:40 cryptography-2.7-cp35-cp35m-linux_x86_64.whl

-rw-rw-r-- 1 cfati cfati  112066 Oct  9 08:43 pycparser-2.19-py2.py3-none-any.whl

-rw-rw-r-- 1 cfati cfati   12099 Oct  9 08:43 six-1.12.0-py2.py3-none-any.whl

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q058228435/build]> for f in $(ls *.whl); do unzip ${f} > /dev/null; done

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q058228435/build]> ls

asn1crypto                         cffi-1.12.3-cp35-cp35m-linux_x86_64.whl        cryptography-2.7-cp35-cp35m-linux_x86_64.whl  pycparser-2.19-py2.py3-none-any.whl

asn1crypto-1.0.1.dist-info         cffi-1.12.3.dist-info                          cryptography-2.7.dist-info                    six-1.12.0.dist-info

asn1crypto-1.0.1-py3-none-any.whl  _cffi_backend.cpython-35m-x86_64-linux-gnu.so  pycparser                                     six-1.12.0-py2.py3-none-any.whl

cffi                               cryptography                                   pycparser-2.19.dist-info                      six.py

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q058228435/build]> PYTHONPATH=.:${PYTHONPATH} python3 ../code00.py

Python 3.5.2 (default, Jul 10 2019, 11:58:48) [GCC 5.4.0 20160609] 64bit on linux


OpenSSL version: OpenSSL 1.0.2t-fips  10 Sep 2019

FIPS_mode(): 0

FIPS_mode_set(1): 1

FIPS_mode(): 1

Success !!!


Done.


查看完整回答
反对 回复 2022-06-14
  • 1 回答
  • 0 关注
  • 179 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号