How to Check Fips 140-2 Support in Openssl

How to check FIPS 140-2 support in OpenSSL?


How do I check whether OpenSSL has is providing FIPS validated cryptography or not?

It depends on how and when you want to check. It also depends on the application.

FIPS could be available but not used. So an application must enable the validated cryptography via FIPS_mode_set, and the call must succeed.


If you want to check if the FIPS Capable Library, such as OpenSSL 1.0.1e, was configured to use the FIPS Object Module, then you can:

$ cat /usr/local/ssl/include/openssl/opensslconf.h  | grep -A 2 -i fips
#ifndef OPENSSL_FIPS
# define OPENSSL_FIPS
#endif

OPENSSL_FIPS tells you the FIPS Capable Library was configured to use FIPS Object Module. So the FIPS validated cryptography is available.

OPENSSL_FIPS does not mean the application is using the FIPS validated cryptography, though. The application must call FIPS_mode_set, and the function must return success.


At runtime, you can print the string associated with the following (its taken from code I use specifically for this):

ostringstream oss;
oss << OPENSSL_VERSION_TEXT;
LogVersion(oss.str().c_str());

The code will produce a log entry similar to the following:

Version: OpenSSL 1.0.1f-fips 6 Jan 2014

You can audit the module with a few tricks. For example, the following will test for some symbols that must be present if executable is truly FIPS.

In this case, I'm testing the OpenSSL FIPS Capable shared object. If the application links to libcrypto.a, then you can audit the program rather than the OpenSSL shared object.

$ nm /usr/local/ssl/lib/libcrypto.so | grep -i fips_*
00000000000c7f60 T ERR_load_FIPS_strings
00000000000c2250 T FIPS_add_error_data
00000000000c3900 T FIPS_add_lock
0000000000082820 T FIPS_bn_bin2bn
0000000000082980 T FIPS_bn_bn2bin
0000000000082760 T FIPS_bn_clear
0000000000082350 T FIPS_bn_clear_free
00000000000823d0 T FIPS_bn_free
0000000000087c90 T FIPS_bn_generate_prime_ex
0000000000082790 T FIPS_bn_get_word
0000000000082d20 T FIPS_bn_is_bit_set
0000000000087c80 T FIPS_bn_is_prime_ex
0000000000087750 T FIPS_bn_is_prime_fasttest_ex
...

You also have the symbols from fips_premain.c:

$ nm /usr/local/ssl/lib/libcrypto.so | grep -i fips_text_*
00000000000c4520 T FIPS_text_end
000000000007b340 T FIPS_text_start
$ nm /usr/local/ssl/lib/libcrypto.so | grep -i fips_rodata*
00000000001e1e20 R FIPS_rodata_end
00000000001d8ce0 R FIPS_rodata_start
$ nm /usr/local/ssl/lib/libcrypto.so | grep -i fips_signature*
00000000004696c0 B FIPS_signature
$ nm /usr/local/ssl/lib/libcrypto.so | grep -i fips_incore*
000000000007b5a0 T FIPS_incore_fingerprint

Now, this is really sneaky. You can check that the module includes the self tests. For example, fips_drbg_selftest.h will include the following bytes its self tests:

0x2e,0xbf,0x98,0xf9,0x85,0x27,0x8b,0xff,0x36,0xb9,0x40,0x0b,
0xc0,0xa1,0xa0,0x13,0x20,0x06,0xcc,0xe6,0x2a,0x03,0x77,0x7d,
0xee,0xde,0xcc,0x34,0xe3,0xcd,0x77,0xea,0xd0,0x3e,0xbe,0xdd,
0xf6,0x15,0xfb,0xa7,0xd7,0x8e,0xd0,0x2e,0x2f,0x82,0x4c,0xc7,
0x87,0xb1,0x6f,0xc5,0xf8,0x5c,0x78,0xde,0x77,0x9b,0x15,0x9a,
0xb9,0x3c,0x38

And you can verify the developer ran incore or macho_incore on their executable to embed the FIPS fingerprint by dumping the 20 bytes of the symbol FIPS_signature. If its 20 bytes of 0's (the default from fips_premain.c), then the fingerprint was not embedded and FIPS_mode_set will fail. So its not possible to use FIPS validated cryptography in this case.


Update: I uploaded a slide deck I have on the subject to the OpenSSL wiki. Its called Building Applications using OpenSSL Validated Cryptography: Notes from the Field for Developers and Auditors. You will want to review the material starting around Slide 18.

I built the slide deck for OWASP but there's was no interest in receiving it. I know Stack Overflow frowns upon links like the one on the OpenSSL wiki, but I don't know how to provide a 35+ slide deck here.

How can I verify that my Tomcat app server correctly supports FIPS 140-2?

It may not be obvious, but this isn't a <Connector> option, but instead an APR option which gets configured in the APRLifecycleListener in CATALINA_BASE/conf/server.xml.

You can read the documentation for the APRLifecycleListener and see that there is a FIPSMode setting that allows you to control the use of FIPS mode. I think you want FIPSMode="on".

This will force Tomcat (really OpenSSL) to operate in a FIPS-compliant manner. The client has no effect on this, and will therefore have to conform to the server's (FIPS-compliant) behavior.

How to enable FIPS mode for libcrypto and libssl packaged with Python?

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 ./code00.py
MD5(./code00.py)= 47fb26ec5d1ca16d3537fe7fd12ea529
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code00.py
SHA1(./code00.py)= 5188a221ba61309e78e70004285bc6fd148701b6
[064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl sha1 ./code00.py
SHA1(./code00.py)= 5188a221ba61309e78e70004285bc6fd148701b6
[064bit-prompt]> OPENSSL_FIPS=1 LD_LIBRARY_PATH=ssl/build/lib ssl/build/bin/openssl md5 ./code00.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:

  • [OpenSSL.Wiki]: FIPS mode()

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

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.

code00.py:

#!/usr/bin/env python3


import ctypes as ct
import ssl
import sys


libcrypto = ct.CDLL("libcrypto.so.1.0.0")

#ssleay = libcrypto.SSLeay
#ssleay.argtypes = ()
#ssleay.restype = ct.c_ulong

fips_mode = libcrypto.FIPS_mode
fips_mode.argtypes = ()
fips_mode.restype = ct.c_int

fips_mode_set = libcrypto.FIPS_mode_set
fips_mode_set.argtypes = (ct.c_int,)
fips_mode_set.restype = ct.c_int


def main(*argv):
text = b""

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()))
#print("SSLeay: {:X}".format(ssleay()))

import hashlib
print("SHA1: {:s}".format(hashlib.sha1(text).hexdigest()))
print("MD5: {:s}".format(hashlib.md5(text).hexdigest()))


if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)

Notes:

  • Set argtypes and restype for the 2 functions. Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for more details

  • The md5 hashing algorithm is provided at Python level by [Python.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

Output:

[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code00.py
Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit on linux

OPENSSL_VERSION: OpenSSL 1.0.2h-fips 3 May 2016
FIPS_mode(): 0
FIPS_mode(): 0
SHA1: da39a3ee5e6b4b0d3255bfef95601890afd80709
MD5: d41d8cd98f00b204e9800998ecf8427e

Done.
[064bit-prompt]> LD_LIBRARY_PATH=ssl/build/lib ./code00.py 1
Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit 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 Nix 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:

  • 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

Some references that might be useful (although last ones could be a bit too "deep"):

  • [SO]: How to compile python3 on RHEL with SSL? SSL cannot be imported (@CristiFati's answer)

  • [SO]: How to implement FIPS_mode() and FIPS_mode_set() in Python 3.6's ssl module? (@CristiFati's answer)

  • [SO]: OpenSSL FIPS_mode_set not working in Python cryptography library (@CristiFati's answer)



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 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]> ./code00.py 1
Python 3.5.2 (default, Nov 23 2017, 16:37:01) [GCC 5.4.0 20160609] 064bit 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

Done.

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

How to meet FIPS 140-2 by building source code for Android L


How to meet FIPS 140-2 by building source code for Android L

Android L is an Operational Environment (OE) in FIPS terminology. Looking at the OpenSSL FIPS 2.0 Security Policy, Table 2, pp. 10-12, the OE has not been validated under Certificate 1747. So the short answer is, You Can't.

The longer answer is, You can contact the OpenSSL Foundation, and maybe get a change letter or private label validation. It may build upon the short answer of You Can't by turning it into a You Can by using Certificate 1747 as a starting point and then satisfying additional bureaucracy requirements.


The really long answer is, You Can't because the CMVP recently changed some rules. The CMVP wanted the rule change to to apply retroactively to existing - already approved - validations. If OpenSSL did not agree, then the CMVP would not approve future change letters and private validations based upon Certificate 1747.

OpenSSL did not agree because it applied retroactively to existing validations (effectively, it unvalidated exiting validations), and it was not fair to the folks who funded those validations. The CMVP responded by withdrawaling a number of previous validations under the 1747 certificate.

If you have been following these event, this is the core of the The FIPS 140-2 "Hostage" Issue. I'm told a major news outlet with investigative reporting is getting ready to publish an article about the CMVP's actions, and how its harmed open source software, internet users and US Federal Agencies. It should be along the lines of The U.S. Government: Paying to Undermine Internet Security, Not to Fix It article.


Two related resources if you have an approved Operational Environment are FIPS Library and Android and OpenSSL and Android. OpenSSL provides them through its wiki.


If you need more information or guidance on how to proceed, then contact Steve Marquess of the OpenSSL Foundation.

Can MySQL with OpenSSL run in FIPS mode?


Can MySQL with OpenSSL run in FIPS mode?

Likely not. FIPS 140-2 does not allow use of algorithms MD5 and SHA-1 (some hand waiving, because there are explicit exemptions provided in, for example, the PRF used in TLS).

Unfortunately, some versions of MySQL still relies on SHA-1 for some internal functions like password hashing. That includes the latest version of MySQL, which is 5.7 at the time of this writing.

In the past I've seen patches which allow MySQL to meet FIPS 140-2 criteria, but they are provided by third parties. However, the application itself would still likely need a formal evaluation once it gets to the point it can actually pass the check box items from FIPS 140-2.

Making OpenLDAP FIPS 140-2 Validated

OpenLDAP uses OpenSSL. It is OpenSSL that you need to comply with FIPS 140-2, if it doesn't already. Nothing to do with OpenLDAP per we at all. Quite possibly this is just a configuration issue.



Related Topics



Leave a reply



Submit