How to automate create Function App with Blob Trigger and Sendgrid Notification through Azure Arm Template and deploy
In previous post (Trigger Email on Blob Trigger), we saw how we can create such…
March 02, 2021
In this post, we will see
In previous post, we saw how we built FIPS-enabled Openssl.
It is important to note that even you have FIPS enabled Openssl, still you need something to invoke this. Only setting to environment variable will not work if you are working from other language like Python. So, you need those methods in Python to get/set fips mode in Openssl.
Note: This patch is tested for Python 3.9.0 and 3.9.2
This patch is built over https://bugs.python.org/issue27592
The older patch was exposing two methods FIPS_mode()
and FIPS_mode_set()
in Python.
Python 3.9 solves the issue when even your Openssl is fips enabled. Still, you are able to get md5. We solved this issue in Python 3.7.9 patch for FIPS
diff -aur Python-3.9.0__orig/Lib/ssl.py Python-3.9.0/Lib/ssl.py
--- Python-3.9.0__orig/Lib/ssl.py 2020-10-05 15:07:58.000000000 +0000
+++ Python-3.9.0/Lib/ssl.py 2021-03-02 04:23:32.026226000 +0000
@@ -111,6 +111,11 @@
# LibreSSL does not provide RAND_egd
pass
+try:
+ from _ssl import FIPS_mode, FIPS_mode_set
+except ImportError as e:
+ sys.stderr.write('error in importing\n')
+ sys.stderr.write(str(e))
from _ssl import (
HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_SSLv2, HAS_SSLv3, HAS_TLSv1,
diff -aur Python-3.9.0__orig/Modules/Setup Python-3.9.0/Modules/Setup
--- Python-3.9.0__orig/Modules/Setup 2020-10-05 15:07:58.000000000 +0000
+++ Python-3.9.0/Modules/Setup 2021-03-02 04:24:28.071717000 +0000
@@ -207,14 +207,14 @@
#_csv _csv.c
# Socket module helper for socket(2)
-#_socket socketmodule.c
+_socket socketmodule.c
# Socket module helper for SSL support; you must comment out the other
# socket line above, and possibly edit the SSL variable:
-#SSL=/usr/local/ssl
-#_ssl _ssl.c \
-# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
-# -L$(SSL)/lib -lssl -lcrypto
+SSL=/usr/local/ssl
+_ssl _ssl.c \
+ -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \
+ -L$(SSL)/lib -lssl -lcrypto
# The crypt module is now disabled by default because it breaks builds
# on many systems (where -lcrypt is needed), e.g. Linux (I believe).
diff -aur Python-3.9.0__orig/Modules/_ssl.c Python-3.9.0/Modules/_ssl.c
--- Python-3.9.0__orig/Modules/_ssl.c 2020-10-05 15:07:58.000000000 +0000
+++ Python-3.9.0/Modules/_ssl.c 2021-03-02 04:25:30.930669000 +0000
@@ -5394,6 +5394,20 @@
return PyLong_FromLong(RAND_status());
}
+static PyObject *
+_ssl_FIPS_mode_impl(PyObject *module) {
+ return PyLong_FromLong(FIPS_mode());
+}
+
+static PyObject *
+_ssl_FIPS_mode_set_impl(PyObject *module, int n) {
+ if (FIPS_mode_set(n) == 0) {
+ _setSSLError(ERR_error_string(ERR_get_error(), NULL) , 0, __FILE__, __LINE__);
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
#ifndef OPENSSL_NO_EGD
/* LCOV_EXCL_START */
/*[clinic input]
@@ -5875,6 +5889,8 @@
_SSL_ENUM_CRLS_METHODDEF
_SSL_TXT2OBJ_METHODDEF
_SSL_NID2OBJ_METHODDEF
+ _SSL_FIPS_MODE_METHODDEF
+ _SSL_FIPS_MODE_SET_METHODDEF
{NULL, NULL} /* Sentinel */
};
diff -aur Python-3.9.0__orig/Modules/clinic/_ssl.c.h Python-3.9.0/Modules/clinic/_ssl.c.h
--- Python-3.9.0__orig/Modules/clinic/_ssl.c.h 2020-10-05 15:07:58.000000000 +0000
+++ Python-3.9.0/Modules/clinic/_ssl.c.h 2021-03-02 04:27:06.120295000 +0000
@@ -1204,6 +1204,45 @@
return _ssl_RAND_status_impl(module);
}
+PyDoc_STRVAR(_ssl_FIPS_mode__doc__,
+"FIPS Mode");
+
+#define _SSL_FIPS_MODE_METHODDEF \
+ {"FIPS_mode", (PyCFunction)_ssl_FIPS_mode, METH_NOARGS, _ssl_FIPS_mode__doc__},
+
+static PyObject *
+_ssl_FIPS_mode_impl(PyObject *module);
+
+static PyObject *
+_ssl_FIPS_mode(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return _ssl_FIPS_mode_impl(module);
+}
+
+PyDoc_STRVAR(_ssl_FIPS_mode_set_doc__,
+"FIPS Mode Set");
+
+#define _SSL_FIPS_MODE_SET_METHODDEF \
+ {"FIPS_mode_set", (PyCFunction)_ssl_FIPS_mode_set, METH_O, _ssl_FIPS_mode_set_doc__},
+
+static PyObject *
+_ssl_FIPS_mode_set_impl(PyObject *module, int n);
+
+static PyObject *
+_ssl_FIPS_mode_set(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ int n;
+
+ if (!PyArg_Parse(arg, "i:FIPS_mode_set", &n)) {
+ goto exit;
+ }
+ return_value = _ssl_FIPS_mode_set_impl(module, n);
+
+exit:
+ return return_value;
+}
+
#if !defined(OPENSSL_NO_EGD)
PyDoc_STRVAR(_ssl_RAND_egd__doc__,
Download Python 3.9.2 source code from https://www.python.org/ftp/python/3.9.2/Python-3.9.2.tgz
wget https://www.python.org/ftp/python/3.9.2/Python-3.9.2.tgz
tar -xzf Python-3.9.2.tgz
cd Python-3.9.2
Assuming patch file patch.diff
is placed outside Python folder.
patch -p1 < ../patch.diff
Now comes the tricker part. We need to carefully set the compiler flags and linker flags.
CFLAGS=-Wl,--enable-new-dtags,-rpath,/usr/local/ssl/lib LDFLAGS=-L/usr/local/ssl/lib CPPFLAGS=-I/usr/local/ssl/include LIBS=-lcrypto ./configure --enable-shared
make
make install
If above steps goes well. Python is installed on your machine.
export LD_LIBRARY_PATH=/usr/local/ssl/lib:/usr/local/lib
Run version command,
python3.9 --version
Python 3.9.2
Although, our work is complete with basic Python/hashlib. But, if somebody installed another python module cryptography
, he/she can still able to calculate unsupported FIPS-encyption algorithm like md5.
Its a little complex trick, where we need to install cryptography
module in a different way.
# upgrade pip
python3.9 -m pip install --upgrade pip
# install wheel
python3.9 -m pip install wheel
# Build cryptography wheel
CRYPTOGRAPHY_DONT_BUILD_RUST=1 CFLAGS="-I/usr/local/ssl/include" LDFLAGS="-L/usr/local/ssl/lib" python3.9 -m pip wheel --no-binary :all: cryptography==3.0
# This will create a wheel file in current directory with name: cryptography-3.0-cp39-cp39-linux_x86_64.whl
# install cryptography module now
CRYPTOGRAPHY_DONT_BUILD_RUST=1 CFLAGS="-I/usr/local/ssl/include" LDFLAGS="-L/usr/local/ssl/lib" python3.9 -m pip install cryptography-3.0-cp39-cp39-linux_x86_64.whl
Note: We are installing cryptography-3.0
, not the latest one. As, it does not have support for our FIPS enabled Openssl (1.0.2t)
We have solved our most of the problem, now it the time to test things.
import ssl
print(ssl.OPENSSL_VERSION)
print(ssl.FIPS_mode())
ssl.FIPS_mode_set(1)
print(ssl.FIPS_mode())
import hashlib
print(hashlib.sha1("test_str".encode('utf-8')).hexdigest())
print(hashlib.md5("test_str".encode('utf-8')).hexdigest())
OpenSSL 1.0.2t-fips 10 Sep 2019
0
1
f9a90e7c1ff51236191623b84267d110c617118a
Traceback (most recent call last):
File "/python_downloads/Python-3.9.2/t1.py", line 12, in <module>
print(hashlib.md5("test_str".encode('utf-8')).hexdigest())
ValueError: [digital envelope routines: FIPS_DIGESTINIT] disabled for fips
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("OPENSSL_VERSION: {:s}".format(ssl.OPENSSL_VERSION))
print("FIPS_mode(): {:d}".format(fips_mode()))
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()))
OPENSSL_VERSION: OpenSSL 1.0.2t-fips 10 Sep 2019
FIPS_mode(): 0
FIPS_mode_set(1): 1
FIPS_mode(): 1
SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
Traceback (most recent call last):
File "/python_downloads/Python-3.9.2/t1.py", line 26, in <module>
print("MD5: {:s}".format(hashlib.md5(text).hexdigest()))
ValueError: [digital envelope routines: FIPS_DIGESTINIT] disabled for fips
As I mentioned before, cryptography module is a dangerous one, as its package hazmat
called Hazardous Materials
provides access to lower level library where you can talk directly to openssl.
from cryptography.hazmat.backends.openssl.backend import backend
import cffi
ffi = cffi.FFI()
lib = backend._lib
print(lib.FIPS_mode())
lib.FIPS_mode_set(1)
print(lib.FIPS_mode())
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
digest = hashes.Hash(hashes.MD5(), default_backend())
digest.update(b"abc")
digest.update(b"123")
print(digest.finalize())
0
1
Traceback (most recent call last):
File "/python_downloads/Python-3.9.2/t1.py", line 12, in <module>
digest = hashes.Hash(hashes.MD5(), default_backend())
File "/usr/local/lib/python3.9/site-packages/cryptography/hazmat/primitives/hashes.py", line 85, in __init__
self._ctx = self._backend.create_hash_ctx(self.algorithm)
File "/usr/local/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 342, in create_hash_ctx
return _HashContext(self, algorithm)
File "/usr/local/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/hashes.py", line 36, in __init__
self._backend.openssl_assert(res != 0)
File "/usr/local/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 234, in openssl_assert
return binding._openssl_assert(self._lib, ok)
File "/usr/local/lib/python3.9/site-packages/cryptography/hazmat/bindings/openssl/binding.py", line 69, in _openssl_assert
raise InternalError(
cryptography.exceptions.InternalError: Unknown OpenSSL error. This error is commonly encountered when another library is not cleaning up the OpenSSL error stack. If you are using cryptography with another library that uses OpenSSL try disabling it before reporting a bug. Otherwise please file an issue at https://github.com/pyca/cryptography/issues with information on how to reproduce this. ([_OpenSSLErrorWithText(code=101351587, lib=6, func=168, reason=163, reason_text=b'error:060A80A3:digital envelope routines:FIPS_DIGESTINIT:disabled for fips')])
Python3.9 has really started work towards FIPS. They have exposed a flag usedforsecurity
in each hashing function via hashlib. Default value is True
import ssl
print(ssl.OPENSSL_VERSION)
print(ssl.FIPS_mode())
ssl.FIPS_mode_set(1)
print(ssl.FIPS_mode())
import hashlib
print(hashlib.md5("test_str".encode('utf-8'), usedforsecurity=False).hexdigest())
You might question, I have enabled FIPS. Then why the hell, md5 still worked. Well, there are many situations where you would want to calculate md5, as its fast. And, many libraries where you might be checking for file changed or not, has support for only md5. So, you can not get away with md5.
The objective is that developer knows that he is using these algorithms and it is not for security.
Let me know if you have any query.
In previous post (Trigger Email on Blob Trigger), we saw how we can create such…
One of the biggest task while writing article or blog is to have right set of…
Introduction In this tutorial we will see, How to list and download storage…
Introduction Cyberark kind of tools are a must for security in your…
Introduction In this tutorial we will see: How to instantiate different classes…
Introduction This post has the complete code to send email through smtp server…
Introduction In this post we will see following: How to schedule a job on cron…
Introduction There are some cases, where I need another git repository while…
Introduction In this post, we will see how to fetch multiple credentials and…
Introduction I have an automation script, that I want to run on different…
Introduction I had to write a CICD system for one of our project. I had to…
Introduction Java log4j has many ways to initialize and append the desired…