博客 / 詳情

返回

OpenSSL 3.0.0 設計(三)|FIPS 模塊

譯|王祖熙 (花名:金九 )

螞蟻集團開發工程師

負責國產化密碼庫 Tongsuo 的開發和維護

專注於密碼學、高性能網絡、網絡安全等領域

本文 9658 字 閲讀 20 分鐘

本文翻譯 OpenSSL 官網文檔:https://www.openssl.org/docs/OpenSSL300Design.html

Tongsuo-8.4.0 是基於 OpenSSL-3.0.3 開發,所以本文對 Tongsuo 開發者同樣適用,內容豐富,值得一讀!

由於文章篇幅較長,今天帶來的是 《FIPS模塊》 部分內容,已發佈文章《介紹、術語與架構》、《Core 和 Provider 設計》可看發表記錄。後續內容將隨每週推送完整發布,請持續關注銅鎖

FIPS 模塊

這是一個經過 FIPS 140-2 驗證的加密模塊,它是一個只包含經過 FIPS 驗證/批准的加密算法的 Provider,非 FIPS 算法將由默認 Provider(而不是 FIPS 模塊)提供。

該模塊是可以動態加載的,不支持靜態鏈接。

FIPS 模塊本身不會有 "FIPS 模式",可以使用 FIPS Provider 的 OpenSSL 將具有與 FIPS-Module-2.0.0 兼容的"模式"概念。

FIPS 模塊版本編號

版本將為 FIPS-Module-3.0。

任何後續的修訂版本將以與先前發佈類似的方式進行標記,例如 3.0.x。

對於更改通知或重新驗證,FIPS 模塊的版本號將更新以匹配當前的 OpenSSL 庫版本。

檢測 FIPS 邊界內的變更

為了進行驗證,我們需要檢測是否有任何相關的源代碼發生了變化。

可以使用一個腳本來對 C 源代碼進行標記化處理,就像 C 預處理器一樣,但還要教會它忽略源代碼中的某些部分:

  • 系統的#include指令。
  • 在 FIPS 模式下被條件排除的代碼(如下文中所述的條件代碼)。

(提醒:C 預處理器可以將所有非換行空白字符合並,並在每個標記之間留下標準的單個空格,對於此目的,註釋被視為空白字符)

標記化處理的結果可以通過校驗和進行處理,該校驗和存儲在與源代碼文件相對應的文件中,並最終進行版本控制。

該過程大致如下(並非完全相同,這只是一個代碼示例,用於展示整個過程):

    for f in $(FIPS_SOURCES); do
        perl ./util/fips-tokenize $f | openssl sha256 -r
    done | openssl sha256 -hex -out fips.checksum

還會有一些機制來提醒我們有關變化的信息,以便我們可以採取適當的措施。例如:

    git diff --quiet fips.checksum || \
        (git rev-parse HEAD > fips.commit; scream)

關於 scream 的具體操作尚待確定。

更新 fips.checksum 應該作為正常的 make update 的一部分進行,這是通常用於更改和檢查版本控制文件的方法,OpenSSL 的持續集成已經運行了此命令,以確保沒有遺漏任何內容,並且如果有內容被更改,將中斷構建過程,運行make update也是正常的 OpenSSL 發佈流程的一部分。

如何對已簽名校驗和的更改做出反應

儘管發生了變更,但我們倉庫中的校驗和更改本身並沒有什麼大不了的,它只是提醒我們需要額外關注 FIPS 源代碼。

有兩種可能的情況:

  1. 當即將發佈新版本,並且 fips.checksum 不再包含上一個經過驗證的源代碼的校驗和時,將 FIPS 源代碼發送給實驗室,並開始更新驗證流程。
  2. 在發佈新版本的同時,fips.checksum 不再包含上一個經過驗證的源代碼的校驗和時,將 FIPS 源代碼(包括 diff 文件和變更列表)發送給實驗室,並啓動相應的更新驗證流程。

已驗證的校驗和列表將在其他地方列出(稍後確定具體位置)。

編譯

對於每個 FIPS Provider 的源文件,我們計算該文件的校驗和,並將其與 fips.checksum 中收集的校驗和進行比對,如果存在不匹配,將拒絕編譯。

FIPS 模式

FIPS 模塊僅包含經過 FIPS 驗證的密碼算法,任何 FIPS 模式的“切換邏輯”將位於 FIPS 模塊邊界之外 - 這將由“fips”屬性處理。

與 FIPS 模式相關的條件代碼在單獨的部分中討論。

以下的 FIPS API 將繼續可供應用程序使用(為了保持一致性,使用了與 1.1.1 版本中相同的名稱):

  • int FIPS_mode_set(int on)

確保當前全局屬性設置中設置了“fips=yes”(當 on != 0 時),或者未設置“fips”(當 on == 0 時)。這還將嘗試使用屬性“fips=yes”獲取 HMAC-SHA256 算法,並確保它成功返回。

  • int FIPS_mode(void)

如果當前的全局屬性字符串包含屬性“fips=yes”(或“fips”),則返回1,否則返回0。

我們可以檢查當前是否有提供 FIPS 算法的 Provider 可用,並稍微以不同的方式處理。

  • int FIPS_self_test(void)

如果 FIPS_mode() 返回true,則運行 KATs。

完整性測試將不在此處涵蓋,如果我們決定提供它,它將是一個單獨的函數。

成功時返回1,失敗或沒有 OpenSSL FIPS Provider 時返回0。

注意:這些函數只能在 OpenSSL FIPS Provider 的上下文中運行,而不能在其他任何 FIPS Provider的上下文中運行。這些是過時的遺留接口,應使用EVP_set_default_alg_properties()函數進行非遺留配置。

角色和身份認證

有兩個隱含的角色 - 密碼官(CO)和用户。這兩個角色都支持相同的服務,唯一的區別是 CO 負責安裝軟件,該模塊不應支持用户身份驗證(對於1級而言不是必需的),所有這些都可以在安全策略中解釋,而無需編寫具體的代碼。

有限狀態模型(FIPS 140-2第4.4節)

需要定義一個狀態機。

我們將需要以下狀態:

  • 自檢狀態 - 初始化、運行、自檢、錯誤、關閉(可能還包括後觸發狀態)
  • 錯誤狀態 - 如果自檢失敗,模塊應返回該操作的錯誤。可以嘗試清除錯誤並重復操作,如果失敗仍然存在,模塊應進入錯誤狀態,這可以是一個硬錯誤狀態,其中所有加密操作都失敗,或者是一個功能降級狀態,其中失敗的組件僅在使用時返回錯誤。

觸發自檢失敗的方式包括:

    1. 連續測試(生成密鑰對的成對測試(簽名/驗證)和從熵源比較測試中驗證輸入到 DRBG 的隨機數不相同)。
    2. DRBG 健康測試 - 這可以始終在 RNG 中引發錯誤(而不是設置全局錯誤狀態)。
    3. 安裝、啓動或按需的 POST 完整性測試失敗。
    4. 啓動或按需的 POST KAT 失敗。

將提供一個內部 API 來設置上述情況的失敗狀態。

狀態機

在狀態機中未顯示的狀態以虛線表示。進入和離開錯誤狀態的邊緣以虛線表示,以表明不希望遍歷這些邊緣。

| 狀態模型由這些狀態組成:1. 電源關閉(Power Off):FIPS 模塊未加載到應用程序中,共享庫不在內存中。

  1. 電源開啓(Power On):FIPS 模塊已被應用程序加載,並且共享庫在內存中。默認入口點構造函數將被啓動。
  2. 初始化(Initialisation):調用OSSL_provider_init。
  3. 完整性檢查(Integrity Check)(POST 完整性):模塊對自身進行校驗,並驗證其是否被惡意更改。(在 FIPS 提供程序的 OSSL_provider_init() 期間運行)。
  4. 自檢(Self Test)(POST KAT):FIPS 模塊在安裝期間執行其自檢,或者在通過 API 調用進行按需自檢。
  5. 運行(Running):FIPS 模塊處於正常運行狀態,可以使用所有 API,並進行連續測試。
  6. 錯誤(Error):FIPS 模塊進入錯誤狀態,調用所有加密 API 將返回錯誤。
  7. 關閉(Shutdown):FIPS 模塊正在被終止並從使用應用程序中卸載。

狀態之間的邊緣關係如下:

  1. 從電源關閉(Power Off)到電源開啓(Power On):此轉換由操作系統在將共享庫加載到應用程序時執行。
  2. 從電源開啓(Power On)到初始化(Initialisation):當調用共享庫的構造函數時發生此轉換。
  3. 從電源開啓(Power On)到關閉(Shutdown):如果無法調用構造函數或構造函數失敗,將觸發此轉換。
  4. 從初始化(Initialisation)到完整性檢查(Integrity Check):此轉換在初始化代碼完成後發生,計算模塊完整性校驗和,並與預期值進行比較。
  5. 從初始化(Initialisation)到錯誤(Error):如果初始化代碼在啓動自測之前遇到錯誤,將觸發此轉換。
  6. 從完整性檢查(Integrity Check)到運行(Running):對於所有啓動過程中完整性檢查成功的情況,發生此轉換。
  7. 從完整性檢查(Integrity Check)到自測(Self Test):在安裝過程中,如果完整性檢查成功,發生此轉換。
  8. 從完整性檢查(Integrity Check)到錯誤(Error):如果完整性檢查失敗,將觸發此轉換。
  9. 從運行(Running)到關閉(Shutdown):當 FIPS 模塊最終化時發生此轉換。
  10. 從運行(Running)到錯誤(Error):如果連續測試中的任何一個失敗,將觸發此轉換。
  11. 從運行(Running)到自測(Self Test):應用程序手動啓動自測時觸發此轉換。不重新運行完整性檢查。
  12. 從自測(Self Test)到運行(Running):自測通過時發生此轉換。
  13. 從自測(Self Test)到錯誤(Error):如果自測失敗,將觸發此轉換。
  14. 從關閉(Shutdown)到電源關閉(Power Off):當 FIPS 模塊從應用程序的內存中卸載時發生此轉換。
  15. 從錯誤(Error)到關閉(Shutdown):當 FIPS 模塊最終化時發生此轉換。

如果可能的話,我們應該儘量在運行狀態下注冊算法,任何進入運行狀態的轉換都應該允許註冊/緩存密碼算法,而任何進入錯誤或關閉狀態的轉換都應該清除 libcrypto 中的所有緩存算法,通過採用這種方法,我們可以避免在所有密碼工廠函數中檢查狀態,這樣可以避免為自我測試(手動啓動時)提供特殊情況訪問權限,同時阻止外部調用者的訪問。

服務

FIPS模塊提供以下服務。

  • 顯示狀態。如果“運行”狀態處於活動狀態,則返回1,否則返回0。
  • 密碼服務,如HMAC、SHS、加密。請參閲附錄3-算法。
  • 自檢(按需執行)- libcrypto 中提供了一個名為FIPS_self_test()的公共 API來訪問此方法。所使用的方法必須與初始化時觸發的方法相同,安全策略將指明只有在沒有其他密碼服務運行時才能訪問此方法。
  • 密鑰清零。請參閲 CSP/Key 清零。

這些服務僅在運行狀態下運行,在任何其他狀態下嘗試訪問服務將返回錯誤,如果自檢失敗,則任何嘗試訪問任何服務的操作都應返回錯誤。

自測試

自測試包括上電自測試(POST)和運行時測試(例如,確保熵不會重複作為 RNG 的輸入)。

POST 包括模塊完整性檢查(每次運行使用 FIPS 的應用程序時運行)以及算法 KAT(可以在安裝時運行一次)。

POST 測試在調用 FIPS 模塊的OSSL_provider_init()入口點時運行。

為了按照正確的順序實現完整性測試和 KAT,模塊需要訪問以下數據項:

  1. 庫的路徑;
  2. 庫內容的 HMAC-SHA256(或包含該值的文件的路徑);
  3. 指示庫已安裝並通過 KAT 的指示器;
  4. 該指示器的 HMAC-SHA256。

這些值將成為可以通過OSSL_PROVIDER對象和相關的OSSL_PARAM getter獲取的參數的一部分。將使用一個“更安全”的獲取值函數來獲取這些值,該函數不會展開環境變量等。此外,還需要傳遞用於訪問和返回庫內容的函數(可能是基於 BIO 的,通過將 Core 傳遞給模塊的調度表中的少量 BIO 函數來實現),以便模塊可以生成自己的庫摘要。

新的 OpenSSL“fips” 應用程序將提供安裝(運行 KAT 並輸出配置文件數據)和檢查(檢查配置文件中的值是否有效)的功能。

模塊的默認入口點(DEP),即 Linux 庫中的 “.init” 函數,將設置一個模塊變量(可能是狀態變量),在OSSL_provider_init()中將檢查此變量,並且如果設置了(通常會設置),則驗證文件中的值。這個兩步過程滿足了 FIPS 要求,即 DEP 確保測試運行,但允許我們在正常運行時初始化模塊的其餘部分時實現這些測試。

作為構建過程的一部分,必須將 FIPS 模塊的完整性校驗和保存到文件中,這可以通過腳本完成,它只是使用已知固定密鑰對整個 FIPS 模塊文件進行 HMAC_SHA256 運算的結果,如果庫已簽名,則必須在應用簽名之後計算校驗和。

至少具有112位的固定密鑰將嵌入到 FIPS 模塊中,用於所有 HMAC 完整性操作,這個密鑰也將提供給外部構建腳本。

出於測試目的,即使其中一個或多個測試失敗,所有活動的 POST 測試也會運行。

完整性校驗和的位置

完整性校驗和將在安裝過程中保存到一個單獨的文件中,默認情況下,該文件將與 FIPS 模塊本身位於相同的位置,但可以配置為位於不同的位置。

已知答案測試

KAT 的目的是對密碼模塊進行健康檢查,以識別在電源週期之間的模塊的嚴重故障或變化,而不是驗證實現是否正確。

FIPS 140-2 IG 的規則指定了需要測試每個已支持的算法(不是每個模式),如果一個算法作為另一個測試的組成部分進行了測試,則不需要單獨的測試,以下是需要進行測試的算法列表:

  • 加密/解密算法
    • AES_128_GCM2
    • TDES_CBC
  • 哈希算法
    • SHA1
    • SHA256 在其他地方已經要求測試
    • SHA512
    • SHA3-256
  • 簽名/驗證測試
    • DSA_2048
    • RSA_SHA256(使用PKCS #1 v1.5填充)
    • ECDSA P256
  • 任何支持的 DRBG 機制的 DRBG 健康測試
    • CTR(AES_128_CTR)
    • HASH - SHA256
    • HMAC - SHA256
  • 派生測試(計算Z)
    • ECDSA P256
    • ECDH
    • KDF(密鑰派生函數)
    • KBKDF(用於 TLS 的 HKDF)

注意:完整性測試使用 HMAC-SHA-256,因此不需要單獨進行 HMAC 測試。

接口訪問

為了方便修改和更改運行的自測試,自測試應該是數據驅動的,POST 測試在註冊任何方法之前運行,但方法表仍然可以間接使用,仍然需要較低級別的 API 來設置密鑰(參數、公鑰/私鑰),密鑰加載代碼應該在一個單獨的函數中進行隔離。

需要一個初始化方法來為高級函數設置所需的依賴項,例如在執行基本調用之前可能需要調用 set_cpuid。

應為摘要、密碼、簽名、DRBG、KDF、HMAC 提供不同類型的自測試 API。

傳遞給這些測試的參數是 KAT 數據。

安全強度

SP 800-131A rev2 在某些日期之後禁止使用特定的算法和密鑰長度,這些項目與安全強度相關聯。

允許具有至少112位安全強度的算法。

對於簽名驗證,為了遺留目的,允許使用安全強度至少為80且低於112的算法。

這兩個值可以在FIPS模塊中定義和執行,也可以在安全策略文檔中更簡單地處理。

可以通過公共API定義這些最小值,並允許設置它們。

還應添加目標安全強度的概念,該值將在密鑰生成算法中使用,這些算法通過其標準指定了目標安全強度參數。

SP800-56A & 56B

這些標準包含密鑰協商協議,為了測試這些協議,加密模塊需要包含以下低級原語。

  • 計算密鑰方法 - 這些已經存在。(例如 DH_compute_key())。
  • 密鑰生成 - (目前缺少 RSA FIPS 186-4 密鑰生成)。
  • 密鑰驗證 - (大部分已經實現)。

FIPS 186-4 RSA 密鑰生成

  • 已經編寫了 RSA 密鑰生成的初始代碼(https://github.com/openssl/openssl/pull/6652);

尚未完成的工作是將其整合到 FIPS 模塊中,OpenSSL FIPS Provider 將具有強制密鑰大小限制的邏輯;

  • 對於 RSA、DSA 和 ECDSA 密鑰對生成,需要進行成對一致性測試(條件自檢)。由於在密鑰生成過程中無法確定密鑰的用途,FIPS 140-2 IG 規定相同的成對測試可以用於簽名和加密兩種模式;
  • 不允許使用 1024 位的 RSA 密鑰生成;
  • 密鑰生成算法具有目標安全強度的概念。例如,RSA 的密鑰生成代碼需要進行以下檢查:
if (target_strength < 112
    || target_strength > 256
    || BN_security_bits(nbits) < target_strength)
    return 0;

DH 密鑰生成

  • DH 密鑰生成 - 可能需要將其拆分為符合標準步驟的形式。目前它是一個相當複雜用時也用於驗證的整體函數。

密鑰驗證

  • RSA SP 800-56B 密鑰驗證 - 公鑰、私鑰和密鑰對的檢查已添加到 PR#6652,符合標準的要求;
  • 需要檢查 DH 密鑰驗證是否符合標準;
  • EC 密鑰驗證符合標準要求;
  • AES-XTS 模式需要進行扭曲密鑰檢查。

對於KAS DH參數,支持兩種類型:

  1. 已批准的安全素數羣如下:

(其中 g=2,q=(p-1)/2,priv=[1, q-1],pub=[2, p-2])

TLS:(ffdhe2048, ffdhe3072, ffdhe4096, ffdhe6144, ffdhe8192)

IKE:(modp-2048, modp-3072, modp-4096, modp-6144, modp-8192)

只有上述安全素數可以進行驗證-其他任何素數都應該失敗。

安全素數可用於至少112位的安全強度,可能需要進行 FIPS 特定的檢查以驗證羣組。

  1. FIPS 186-4 參數集僅用於向後兼容性,安全強度僅為112位。羣組為 FB (2048, 224) 和 FC (2048, 256)。這需要保存種子和計數器以進行驗證。

如果需要同時支持兩種類型,則需要不同的密鑰驗證代碼。

現有的DH_Check()需要進行 FIPS 特定的檢查來驗證批准的類型。

密鑰生成對於兩者來説是相同的(安全強度和私鑰的最大位長度是輸入)。

DSA 在 FIPS 186-4 中定義為 “FFC”,DSA 密鑰生成/密鑰驗證可以重新設計,以更好地匹配標準步驟,這將有助於密鑰驗證,並且如果需要,可以在 DH 情況下進行重用。

GCM IV 生成

對於 FIPS 模塊,AES GCM 有與唯一密鑰/IV 對相關的要求,即:

  • 加密時密鑰/IV 對必須是唯一的;
  • IV 必須在 FIPS 邊界內生成;
  • 對於 TLS,IV 的計數部分必須由模塊設置,模塊必須確保當計數用盡時返回錯誤;
  • 對於給定的密鑰(對於任何 IV 長度),認證加密函數的總調用次數必須小於
  • 模塊斷電不應導致 IV 的重複使用。

IV 生成將使用隨機構造方法(來自SP 800-38D),其中包括一個自由字段(將為 NULL)和一個隨機字段,隨機字段將使用一個能提供至少96位熵強度的 DRBG,該 DRBG 需要由模塊進行種子生成。

現有代碼需要修改,以便在init()階段未設置 IV 時生成 IV,然後可以使用do_cipher()方法在需要時生成 IV。

int aes_gcm_cipher()
{
    ....
    /* old code just returned -1 if iv_set was zero */
    if (!gctx->iv_set) {
        if (ctx->encrypt) {
           if (!aes_gcm_iv_generate(gctx, 0))
               return -1;
           } else {
               return -1;
           }
        }
    }
}

生成代碼如下所示:

#define AES_GCM_IV_GENERATE(gctx, offset)                   \
    if (!gctx->iv_set) {                                    \
        int sz = gctx->ivlen - offset;                      \
        if (sz <= 0)                                        \
            return -1;                                      \
        /* Must be at least 96 bits */                      \
        if (gctx->ivlen < 12)                               \
            return -1;                                      \
        /* Use DRBG to generate random iv */                \
        if (RAND_bytes(gctx->iv + offset, sz) <= 0)         \
            return -1;                                      \
        gctx->iv_set = 1;                                   \
    }

生成的 IV 可以通過EVP_CIPHER_CTX_iv()方法獲取,因此不需要使用 ctrl id。

理想情況下,在 FIPS 模式下嘗試設置 GCM IV 參數將導致錯誤。實際上,可能仍然有一些應用程序需要設置 IV,因此建議將其指定為安全策略項。

安全策略還需要説明以下內容:(參見 FIPS 140-2 IG A.5)

  • 當電源斷開然後恢復時,應建立一個新的用於 AES GCM 加密的密鑰;
  • 使用相同密鑰的總調用次數必須小於
  • 場景1:IV 生成符合 TLS 協議;
  • 場景2:使用 NIST SP 800-38D(第8.2.2節)的 IV 生成方法。

CSP/Key 清零

當不再需要臨界安全參數(CSP)時,我們必須將其全部設置為零,這可能會在不同的上下文中發生:

  • 臨時的 CSP 副本可能是棧或堆分配的,並且將在其使用範圍內的相關函數中被清零;
  • 一些 CSP 將與 OpenSSL 對象(如 EVP_PKEY 或 EVP_CIPHER_CTX)關聯,具有與之相關聯的生命週期,在這種情況下,當這些對象被釋放時,CSP 將在該點被清零。在某些情況下,對象可能會被複用(例如,EVP_CIPHER_CTX 可以用於多個加密操作),在這種情況下,對象中仍存在的任何 CSP 將在其重新初始化為新操作時被清零。
  • 一些 CSP(例如內部 DRBG 狀態)可能會在加載 OpenSSL FIPS 模塊的整個時間內存在,在這種情況下,狀態將封裝在 OpenSSL 對象中。所有 OpenSSL Provider(包括 FIPS 模塊 Provider)都具有註冊“卸載”函數的能力,該函數在關閉 OpenSSL 時(或因其他原因卸載模塊)時將被調用,該卸載函數將釋放(因此將清零)包含 CSP 的對象。
  • 根據 FIPS 140-2 IG 4.7 的規定:僅用於執行 FIPS 140-2 第4.9.1節上電測試的密碼模塊使用的密碼密鑰不被視為 CSP,因此不需要滿足 FIPS 140-2 第4.7.6節的清零要求。

OpenSSL FIPS 模塊將包含其自己的標準OPENSSL_cleanse()函數的副本來執行清零操作,這是使用特定於平台的彙編語言實現的。

DRBG

在舊的 FIPS 模塊中存在以下 API,可能需要重新添加:

  • FIPS_drbg_health_check:按需運行 DRBG KAT 測試,我們需要使其可用。
  • FIPS_drbg_set_check_interval:設置運行 DRBG KAT 測試之間的間隔(生成調用的次數)。這似乎不是必需的,這些測試在上電時運行,但後續不需要運行,但這個調用對於故障測試很有用。

推導函數

根據 FIPS 140-2 IG 14.5 中的第2點要求,CTR DRBG 將無條件支持派生函數,如果禁用派生函數,當前的代碼在重新生成種子時會出現問題。此外,如果沒有派生函數,需要從實驗室獲得額外的理由支持。

測試要求

  • uninstantiate()函數中需要證明內部狀態已被清零;
  • 故障測試需要一個函數,使 DRBG 始終產生相同的輸出。

其他需要考慮的事項

除了下面描述的熵之外,還需要考慮以下幾點:

  • 應考慮實施 NIST SP 800-90C 10.1.2 中的熵擴展;
  • 需要更好的 DRBG 選擇機制,以在可用的 DRBG 之間進行選擇;
  • 支持預測抵抗,即在請求時嘗試從我們的來源收集更多熵。
  • 我們需要弄清楚 DRBG 層將是什麼樣子,代碼的很大一部分需要放在 FIPS 模塊內。目前,此代碼訪問 EVP 功能,而這些功能可能不會在模塊內部公開。例如,drbg_ctr_init() 從 NID 解析 EVP_CIPHER,然後設置一個 EVP_CIPHER_CTX。

對於所有平台,操作系統將提供熵。對於某些平台,還可以使用內置的硬件隨機數生成器,但這將引入額外的驗證需求。

對於類 UNIX 系統,將使用系統調用getrandomgetentropy或隨機設備/dev/random作為熵源,優先考慮使用系統調用。可以替代/dev/random的其他強隨機設備包括:/dev/srandom/dev/hwrng。請注意,/dev/urandom/dev/prandom/dev/wrandom/dev/arandom在沒有額外的證明的情況下不能用於 FIPS 操作。

在 Windows 上,將使用BCryptGenRandomCryptGenRandom作為熵源。

在 VMS 上,將使用各種系統狀態信息作為熵源。請注意,這將需要證明和分析以證明源的質量。

對於 iOS,將使用 SecRandomCopyBytes 生成具有密碼學安全性的隨機字節。

FIPS 僅允許將一個熵源歸因於模塊,因此 FIPS 模塊將完全依賴於前述的操作系統源,不會使用其他來源,例如 egd、硬件設備等。

完成熵解決方案的工作

需要將 DRBG 健康檢測添加到隨機框架中,以檢查輸入到 DRBG 的種子材料,檢查的目的是確保沒有連續的兩個種子材料塊是相同的,該檢查在所有熵源被合併在一起後進行,如果檢查失敗,則 DRBG 的種子重新生成操作將永遠失敗。我們可以定義使用的塊大小為64位,這是在意外接收到重複塊的概率()和從操作系統中獲取過多熵量之間的平衡(因為第一個塊會被丟棄),其他明顯可用的塊大小包括128位和256位。

使用後,初始數據塊必須被清零和丟棄。

GCM的初始化向量(IV)

FIPS 140-2 IG A.5 的最新更新指出,如果模塊聲稱為 GCM 生成隨機 IV,則需要提供證明,我們需要證明模塊能夠從操作系統獲取所需的96位熵,如果使用阻塞調用操作系統的隨機性源,並且至少使用這麼多熵素材作為 DRBG 的種子材料,那麼這應該不是無法解決的問題。

FIPS 模塊邊界

一旦進入 FIPS 模塊提供的算法,在任何其他的加密操作中我們必須仍然保持在 FIPS 模塊內部。根據 FIPS 規則,允許一個 FIPS 模塊使用另一個 FIPS 模塊。然而,在3.0設計中,為了簡化起見,我們假設不允許這樣做。例如,EVP_DigestSign*實現同時使用簽名算法和摘要算法,我們不允許其中一個算法來自 FIPS 模塊,另一個來自其他 Provider。

所有 Provider 在初始化時都被分配一個唯一的OSSL_PROVIDER對象,當 FIPS 模塊被要求使用某個算法時,它會驗證該算法的實現OSSL_PROVIDER對象是否與自己的OSSL_PROVIDER對象相同 (即傳遞給OSSL_provider_init的對象),例如,考慮使用 RSA 和 SHA256 的EVP_DigestSign*的情況,兩個算法都會通過 Core 在 FIPS 模塊外部進行查找,RSA 簽名算法是第一個入口點,"init" 調用將被傳遞給要使用的 SHA256 算法的引用,FIPS 模塊的實現將檢查與其被要求使用的 SHA256 實現關聯的OSSL_PROVIDER對象是否也在 FIPS 模塊邊界內,如果不是,則 "init" 操作將失敗。下面的圖示從 FIPS 模塊的角度説明了這個操作。

請注意,在 FIPS 模塊內部,我們使用了EVP的概念(如EVP_MD_CTXEVP_PKEY_CTX等)來實現這一點,這些是 libcrypto 中 EVP 實現的副本,FIPS 模塊沒有與 libcrypto 進行鏈接,這是為了確保完整的操作都在 FIPS 模塊的邊界內進行,而不調用外部的代碼。

ASN.1 代碼

ASN.1 DER (Distinguished Encoding Rules) 用於:

  • 序列化密鑰參數
  • 序列化由兩個值 r 和 s 組成的 DSA 和 ECDSA 簽名
  • 編碼放置在 RSA PKCS#1 填充中的簽名摘要 OBJECT IDENTIFIER(OID)
  • 序列化 X.509 證書和證書撤銷列表(CRL)
  • 其他 PDU,如 PKCS #7/CMS、OCSP、PKCS #12 等。

FIPS 模塊不會包含 ASN.1 DER 編碼器/解析器的副本,也不會要求任何 Provider 對由 OpenSSL 實現的算法執行 ASN.1 序列化/反序列化。

所有 ASN.1 序列化/反序列化操作將在 libcrypto 中執行,複合值的密鑰參數和簽名結構將作為項數組越過 Core/Provider 邊界,使用 附錄 2 - 參數傳遞 中定義的公共數據結構進行傳遞。

用於 RSA PKCS#1 填充的編碼摘要 OID 將預先生成(與舊 FIPS 模塊使用 SHA_DATA 宏相同)或根據需要使用簡單函數生成,這個函數僅為 PKCS #1 填充支持的小型摘要集合生成編碼的 OID,這些摘要 OID 在“OID 樹”下的一個公共節點下,驗證填充時將獲取預期摘要的編碼 OID,並將其字節與填充中的字節進行比較;不需要進行 DER 解析/解碼。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.