Introduction
Federal Information Processing Standard (FIPS) are a set of encryption algorithms and is mandatory in all computer systems and software used by non-military American government agencies, government contractors and vendors who work with the agencies. When new software is developed, it needs to be FIPS-compliant. Thus, there is a need to enable Python with FIPS, but the default Python package comes without FIPS as shown in screenshot below.
This blog will explain, step-by-step, how to enable Python 3 with the OpenSSL/FIPS standard on a Microsoft Windows platform so that any new software compiled out of it, is FIPS-compliant.
Prerequisites
- Cygwin environment
- Python 3
- Visual Studio 2017
STEPS
Step 1 Download the OpenSSL and FIPS source from http://www.openssl.org and the Python 3 source from http://www.python.org
Step 2 Convert all symlinks in the archive to regular files. This is done in Linux, Cygwin environment.
Untar
Zip -9$ tar -zxvf openssl-fips-2.0.16.tar.gz $ tar -zxvf openssl-1.0.2u.tar.gz $ tar -zxvf Python-3.8.6.tgz
Finally, unzip in Windows to the c:\work\ folder.$ zip -9 -r openssl-fips-2.0.16.zip openssl-fips-2.0.16 $ zip -9 -r openssl-1.0.2u.zip openssl-1.0.2u $ zip -9 -r Python-3.8.6.zip Python-3.8.6
Step 3 Install NASM for x64 and copy the contents of C:\Program Files\NASM to the C:\work\openssl-1.0.2u\ folder.
Note: NASM is a netwide assembler program and can be downloaded from [https://www.nasm.us/pub/nasm/releasebuilds]
Step 4 Build the FIPS module using the VS 2015 Native Tools Command prompt.
Rename the folder “out32dll” to “lib”.> cd openssl-fips-2.0.16 > ms\do_fips
Rename the folder “util” to “bin”.
Move “fips_standalone_sha1.exe” from “lib” to “bin”.
This is done so that OpenSSL can compile in the next steps.
Step 5 Build OpenSSL module using the VS 2015 Native Tools Command prompt.
cd openssl-1.0.2u perl Configure VC-WIN64A no-zlib no-idea no-mdc2 no-rc5 no-ssl2 no-ssl3 fips --with-fipslibdir=C:\usr\local\ssl\fips-2.0 ms\do_win64a nmake -f ms\nt.mak all nmake -f ms\nt.mak install
The openssl.exe and libeay32.dll and ssleay32.dll files are generated be in the C:\usr\local\ssl\bin\ folder.
Step 6 Unzip Python in Windows and create an 'externals' directory at the root (c:\work\Python-3.8.6) folder.
Under 'externals', create a directory for openssl-1.0.2u and copy all the contents of c:\usr\local\ssl\ to this directory.
Step 7 Under 'externals', create a directory for openssl-bin-1.0.2u/amd64 and copy all the files from c:\work\openssl-1.2.u\out32dll to this directory.
Also, copy all the files from c:\work\openssl-1.2.u\inc32 to the openssl-bin-1.0.2u/amd64/include directory.
Step 8 Patch/Add/Modify these codes to files as shown below under Python-3.8.6 source (c:\work\Python-3.8.6).
Lib\ssl.py:
Modules/_ssl.c:try: from _ssl import FIPS_mode, FIPS_mode_set print('successful import') except ImportError as e: print('error in importing') print(e)
Modules/clinic/_ssl.c.h: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; } static PyMethodDef PySSL_methods[] = { _SSL__TEST_DECODE_CERT_METHODDEF _SSL_RAND_ADD_METHODDEF _SSL_RAND_BYTES_METHODDEF _SSL_RAND_PSEUDO_BYTES_METHODDEF _SSL_RAND_EGD_METHODDEF _SSL_RAND_STATUS_METHODDEF _SSL_GET_DEFAULT_VERIFY_PATHS_METHODDEF _SSL_ENUM_CERTIFICATES_METHODDEF _SSL_ENUM_CRLS_METHODDEF _SSL_TXT2OBJ_METHODDEF _SSL_NID2OBJ_METHODDEF _SSL_FIPS_MODE_METHODDEF _SSL_FIPS_MODE_SET_METHODDEF {NULL, NULL} /* Sentinel */ };
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; }
The above code is used to enable functions ssl.FIPS_mode() and ssl.FIPS_mode_set().
Step 9 Modify PCbuild/openssl.props as shown below:
Step 10 Open PCbuild/python.props and change entries as shown below:
Step 11 Open Python Solution under PCbuild/pcbuild.sln in VS 2017/2015.
Change the link settings of _hashlib and _ssl projects under Python as shown below:
Change compile settings _hashlib and _ssl projects as shown below:
Step 12 Now, build _hashlib.pyd and _ssl.pyd in VS 2017/2015.
Step 13 Copy these built pyd files to a Python binary installation directory c:\python38\DLLs folder.
Copy ssl.py to c:\python38\Lib folder.
Copy OpenSSL DLLs (libeay32.dll and ssleay32.DLL) to the c:\python38\DLLs folder.
Step 14 Start Python and use these commands to check the OpenSSL/FIPS version.
Voila...now Python 3.8 has OpenSSL with FIPS.
Summary
In this blog, I have covered the following steps in regards to enabling Python 3 with FIPS.
- Download the required packages.
- Compile both OpenSSL and FIPS and link them both.
- Make the required changes to Python source before linking to the new OpenSSL and compile.
- Copy the newly generated binaries to the installed Python location.
- Test the version and check if FIPS is enabled.
I hope this blog is useful to the entire developer community!! Make sure you check out other blog posts on HPE DEV for more useful tutorials.
Related

Announcing Chapel 2.3!
Dec 12, 2024
Announcing Chapel 2.4!
Mar 20, 2025
Comparing Standard Library Sorts: The Impact of Parallelism
Jan 30, 2024