APISIX: Be FIPS 140-2 Compliant

Jinhua Luo

January 6, 2023

Products

What is FIPS 140-2?

FIPS stands for Federal Information Processing Standards, a set of computer security standards established by the US federal Department of Commerce’s National Institute of Standards and Technology (NIST).

The goal of FIPS is to create a uniform level of security for all federal agencies to protect sensitive but unclassified information - a large portion of electronic data not considered secret or higher.

Security levels of FIPS 140-2

FIPS 140-2/3 are frequently used standards in the cyber-security context. They both relate to the standard security requirements for cryptographic modules. FIPS 140-3 will eventually replace FIPS 140-2, and this transition is currently underway.

  • Level 1 – The lowest security level that imposes minimum requirements and requires all components to be ‘production grade’. FIPS 140-2 Level 1 relates specifically to software cryptographic modules and makes stipulations about the cryptographic algorithms that may be used and the self‑tests that must be conducted to verify their integrity.
  • Level 2 – Added requirements for physical-tamper evidence as well as role-based authentication.
  • Level 3 – Further obligation to strengthen security against attackers, the use of identity-based authentication, as well as physical separation between interfaces.
  • Level 4 – The most stringent level that necessitates robust physical security measures against environmental attacks.

For example, a cryptographic module that is validated FIPS 140-2 Level 1 provides that basic level of security by encrypting data going through it to the level of protection provided by AES. However, a cryptographic module that is validated to FIPS 140-2 Level 2 not only provides AES electronic encryption but also physical security of the device itself.

This means that a FIPS 140-2 Level 2 validated cryptographic module cannot be tampered with unless the seals on the solution housing are broken, in which circumstance the so-called cryptographic officer will know immediately information security has been compromised and she can then take action at once to remediate any data breach.

Why FIPS is important?

FIPS 140-2 validated cryptographic modules are required by law for all US federal agencies that handle sensitive but unclassified information. And other industry verticals are making FIPS 140-2 Level 2 a nonnegotiable item for their backhaul security, including finance, healthcare, legal services, mobile operators, and public safety industries.

APISIX compliant with FIPS 140-2

How to be compliant with FIPS 140-2?

When used with a FIPS 140-2 validated build of OpenSSL 3.0 operating in FIPS mode, APISIX is compliant with the requirements of FIPS 140-2 (Level 1) concerning the decryption and encryption of SSL/TLS‑encrypted network traffic.

Influences

FIPS mode disables the following ciphers:

  • TLS_ECDH_anon_WITH_RC4_128_SHA
  • TLS_ECDHE_RSA_WITH_RC4_128_SHA
  • TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
  • TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
  • TLS_RSA_WITH_IDEA_CBC_SHA
  • TLS_RSA_WITH_RC4_128_MD5
  • TLS_RSA_WITH_RC4_128_SHA
  • TLS_RSA_WITH_SEED_CBC_SHA

And, FIPS does not support RSA keys smaller than 2048 bits.

Build OpenSSL

Build and install OpenSSL with FIPS enabled

apt install -y build-essential
git clone https://github.com/openssl/openssl
cd openssl
./Configure --prefix=/usr/local/openssl-3.0 enable-fips
make install
bash -c "echo /usr/local/openssl-3.0/lib64 > /etc/ld.so.conf.d/openssl3.conf"
ldconfig
/usr/local/openssl-3.0/bin/openssl fipsinstall -out /usr/local/openssl-3.0/ssl/fipsmodule.cnf \
-module /usr/local/openssl-3.0/lib64/ossl-modules/fips.so
sed_expr='s@# .include fipsmodule.cnf@.include /usr/local/openssl-3.0/ssl/fipsmodule.cnf@g;'
sed_expr+=' s/# \(fips = fips_sect\)/\1\nbase = base_sect\n\n[base_sect]\nactivate=1\n/g'
sed -i "$sed_expr" /usr/local/openssl-3.0/ssl/openssl.cnf

bash -c "echo /usr/local/openssl-3.0/lib64 > /etc/ld.so.conf.d/openssl3.conf"
ldconfig

Verify OpenSSL

Verify the configuration file (/usr/local/openssl-3.0/ssl/openssl.cnf).

Ensure it matches below snippet:

config_diagnostics = 1
openssl_conf = openssl_init

.include /usr/local/ssl/fipsmodule.cnf

[openssl_init]
providers = provider_sect

[provider_sect]
fips = fips_sect
base = base_sect

[base_sect]
activate = 1

Determine whether OpenSSL can perform SHA1 hashes: This test verifies the correct operation of OpenSSL. The SHA1 hash algorithm is permitted in all modes, so a failure of this command indicates that the OpenSSL implementation does not work correctly:

# openssl sha1 /dev/null
SHA1(/dev/null)= da39a3ee5e6b4b0d3255bfef95601890afd80709

Determine whether OpenSSL can perform MD5 hashes: This test verifies that OpenSSL is running in FIPS mode. MD5 is not a permitted hash algorithm in FIPS mode, so an attempt to use it fails:

# openssl md5 /dev/null
Error setting digest
80920FA8DA7F0000:error:0308010C:digital envelope routines:
inner_evp_generic_fetch:unsupported:crypto/evp/evp_fetch.c:341:
Global default library context, Algorithm (MD5 : 100), Properties ()

If OpenSSL is not running in FIPS mode, the MD5 hash functions normally:

# /usr/bin/openssl md5 /dev/null
MD5(/dev/null)= d41d8cd98f00b204e9800998ecf8427e

Build APISIX with FIPS

# install pcre and zlib dependencies
wget -O - https://openresty.org/package/pubkey.gpg | apt-key add -
echo "deb http://openresty.org/package/${arch_path}ubuntu $(lsb_release -sc) main" | \
tee /etc/apt/sources.list.d/openresty.list
apt-get update
apt-get install -y openresty-pcre-dev openresty-zlib-dev

# specify compile and link options
export zlib_prefix=/usr/local/openresty/zlib
export pcre_prefix=/usr/local/openresty/pcre
export cc_opt="-DNGX_LUA_ABORT_AT_PANIC -I${zlib_prefix}/include -I${pcre_prefix}/include"
cc_opt+="-I/usr/local/openssl-3.0/include"
export ld_opt="-L${zlib_prefix}/lib -L${pcre_prefix}/lib -L/usr/local/openssl-3.0/lib64"
ld_opt+="-Wl,-rpath,${zlib_prefix}/lib:${pcre_prefix}/lib:/usr/local/openssl-3.0/lib64"

# build and install apisix-base
wget https://raw.githubusercontent.com/api7/apisix-build-tools/master/build-apisix-base.sh
bash build-apisix-base.sh latest

Configure a test route

curl http://127.0.0.1:9180/apisix/admin/routes/httpbin -H 'X-API-KEY: YOUR-KEY' -X PUT -i -d '
{
    "uri": "/anything",
    "hosts": ["*.httpbin.org"],
    "methods": ["GET"],
    "upstream": {
        "type": "roundrobin",
        "nodes": {
            "httpbin.org": 1
        }
    }
}'

Test validate private key

Test normal case, we exepect it's successful.

Create an auxiliary python script to upload cert:

cfg_ssl.py

import sys
import requests

if len(sys.argv) <= 3:
    print("bad argument")
    sys.exit(1)

with open(sys.argv[1]) as f:
    cert = f.read()

with open(sys.argv[2]) as f:
    key = f.read()

sni = sys.argv[3]
api_key = "edd1c9f034335f136f87ad84b625c8f1"

resp = requests.put("http://127.0.0.1:9180/apisix/admin/ssls/1", json={
    "cert": cert,
    "key": key,
    "snis": [sni],
}, headers={
    "X-API-KEY": api_key,
})
print(resp.status_code)
print(resp.text)

Create a bash function to ease key generation:

genkey() {
    keylen=${1:-4096}
    /usr/bin/openssl genrsa -out apisix.key $keylen
    /usr/bin/openssl req -key apisix.key -new -out apisix.csr -subj '/C=/ST=/L=/O=/OU=web/CN=*.httpbin.org'
    /usr/bin/openssl x509 -req -in apisix.csr -signkey apisix.key -out apisix.crt -days 3650 -sha256
}

Test:

cd $(mktemp -d)
genkey 2048
python3 ssl.py apisix.crt apisix.key '*.httpbin.org'
curl --resolve 'www.httpbin.org:9443:127.0.0.1' https://www.httpbin.org:9443/uuid -vvv -k

Output:

...
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: OU=web; CN=*.httpbin.org
*  start date: Dec 22 05:52:58 2022 GMT
*  expire date: Dec 19 05:52:58 2032 GMT
*  issuer: OU=web; CN=*.httpbin.org
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55e125a24e30)
> GET /uuid HTTP/2
> Host: www.httpbin.org:9443
> user-agent: curl/7.68.0
> accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200
< content-type: application/json
< content-length: 53
< date: Thu, 22 Dec 2022 06:35:04 GMT
< access-control-allow-origin: *
< access-control-allow-credentials: true
< server: APISIX/3.0.0
<
{
  "uuid": "1827f239-376f-47ec-9b54-d5addaa8c7f9"
}

Test key smaller than 2048 bits

FIPS does not support RSA keys smaller than 2048 bits. So, let's test if it fails with small key.

genkey 1024
python3 cfg_ssl.py apisix.crt apisix.key '*.httpbin.org'
curl --resolve 'www.httpbin.org:9443:127.0.0.1' https://www.httpbin.org:9443/uuid -vvv -k

Output:

...
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
* Closing connection 0
curl: (35) error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error

Conclusion

Given the rigorous testing that FIPS entail, they are considered a dependable security standard. Plus, they're a useful baseline for any entities that need to implement security standards within their infrastructure.

It's easy to add FIPS support in APISIX. APISIX can be used to decrypt and encrypt SSL/TLS‑encrypted network traffic in deployments that require FIPS 140-2 Level 1 compliance.

For more information about API gateway, please visit our blogs or contact us.

Tags:
APISIX BasicsAPI SecurityData Management