DMTF / libspdm

BSD 3-Clause "New" or "Revised" License
111 stars 101 forks source link

[Feature request] Support FIPS 140-3 level 1 compliance #1260

Closed xiaoyuruan closed 1 year ago

xiaoyuruan commented 2 years ago

FIPS 140-3 is a US government government standard for crypto and security modules. Some open source libraries are certified for compliance with FIPS 140-3 level 1. For example, OpenSSL 3.0 achieved FIPS 140-3 level 1 certificate (https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4282).

Though libspdm does not have to acquire FIPS 140-3 certificate, compliance with FIPS 140-3 makes easier for adopters of the libspdm to achieve FIPS 140-3 certificates for their products.

Detailed requirements to make libspdm FIPS compliant and design suggestions:

  1. FIPS SKU: Create a "FIPS" configuration for compile / build and hence a FIPS SKU of libspdm. Following requirements apply only for the FIPS SKU of libspdm.
  2. zeroization: explicitly zeroize (memset_s to 0) within the function as as soon as a variable holding key (including public key) is no longer needed. libspdm_reset_context() API should zeroize all keys in context (I believe it is already doing so).
  3. Only Approved algorithms: Only allow use of NIST-Approved algorithms, listed at https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-140Cr1.pdf.
  4. module_id API: libspdm exposes an API that returns version number of the libspdm build.
  5. run_selftests API: libspdm exposes an API that triggers running of all selftests and returns the results.
  6. selftest_results API: libspdm exposes an API that returns results of last selftests.
  7. integrity selftest: at libspdm load (e.g., DLLmain()), read the binary of libspdm and underlying crypto library (if applicable) that's loaded to memory and calculate HMAC-SHA256 (using the function in crypto lib) of it, with a hardcoded key (could be 32-bytes of 0x00's). Compare the resulted 32-byte HMAC with a reference value, which is calculated at build and shipped in a separate file shipped alongside libspdm. If they do not match, then disable all APIs except module_id and selftest_results (which shows the integrity selftest failure).
  8. pre-operational selftest: libspdm performs pre-operational selftests before first use of the algorithm (or at load). see Section 10 of FIPS Implementation Guidance (https://csrc.nist.gov/CSRC/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf).
    • For most algorithms, implement known answer selftest (KAT), i.e., pass hardcoded input data and key to underlying crypto library and compare returned output data with hardcoded answer.
    • This is usually not possible for DRBG (SP 800-90A), as the crypto library usually does not allow caller to specify seed. So DRBG (SP 800-90A) KAT should be implemented within the crypto library, before first use of the DRBG.
    • Entropy selftest is not possible from libspdm. The crypto library should implement.
    • KEY_EXCHANGE uses ECDH (SP 800-56Arev3), which has comprehensive pairwise consistency selftest requirement for ephemeral ECC keypair. See the IG.
steven-bellock commented 2 years ago

I think 1 through 4 is fine. 5, 6, and 8 only concern the cryptography software and hardware, correct? If so I don't think libspdm needs to expose any interfaces. Whomever is integrating libspdm into a Requester or Responder can perform those functions outside of libspdm. I think 7 assumes that libspdm is a standalone dynamically linked library in which case we could support integrity checking. But if libspdm is integrated into a larger executable or another library then integrity checking needs to be done at a higher level.

xiaoyuruan commented 2 years ago

Yes, agreed with all your points. 5, 6, 8 can be implemented in the SW crypto lib; if the crypto is HW (and assumingly hard to change), then libspdm or new "crypto driver" SW/FW could help with 5, 6, 8.

jyao1 commented 2 years ago

I think we need a clear definition on FIPS boundary. For example, FIPS boundary == SPDM lib (responder and/or requester) + crypto lib.

We also need determine how libspdm integrates the existing crypto lib, which may already have FIPS MODE. (e.g. https://www.openssl.org/docs/fips.html, or https://www.wolfssl.com/license/fips/). For example: . using binary(DLL) linking - need item 7. . using source build - no need item 7.

Proposal as first step:

  1. Add LIBSPDM_FIPS_MODE.
  2. Double check
  3. Ensure non-approved algo is undefined when LIBSPDM_FIPS_MODE=1.
  4. Expose module_id API when LIBSPDM_FIPS_MODE=1.
  5. Run run_selftests API when LIBSPDM_FIPS_MODE=1. Open: Do we let integrator to run it? Or add it to libspdm_init_context() ?
  6. Run selftest_results API when LIBSPDM_FIPS_MODE=1.
  7. Defer
  8. Integrate KAT when LIBSPDM_FIPS_MODE=1.

Reference: https://icmconference.org/wp-content/uploads/C22b-RuanX.pdf

jyao1 commented 1 year ago

ref: https://github.com/DMTF/libspdm/discussions/1406 for API proposal.

jyao1 commented 1 year ago

Summary is at https://github.com/DMTF/libspdm/discussions/1406.