博客 / 詳情

返回

OpenSSL 3.0.0 設計(四)|代碼維護、FIPS 測試

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

螞蟻集團開發工程師
負責國產化密碼庫 Tongsuo 的開發和維護
專注於密碼學、高性能網絡、網絡安全等領域

本文 2862 字 閲讀 8 分鐘

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

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

由於文章篇幅較長,今天帶來的是 《代碼維護、FIPS 測試》 部分內

後續內容將隨每週推送完整發布,請持續關注銅鎖

代碼維護

源代碼結構/目錄樹的清理

密碼學實現(crypto/evp/e_*.c和大部分crypto/evp/m_*.c,以及任何定義EVP_CIPHEREVP_MDEVP_PKEY_METHODEVP_MACEVP_KDF的代碼)必須移出 evp 目錄,它們最終將成為一個或兩個 Provider 的一部分,因此它們應該位於特定 Provider 的子目錄中。

將創建一個新的目錄providers/,用於存放特定 Provider 的代碼。providers/build.info定義了哪些源文件在哪些 Provider 模塊中使用。

共享源代碼

FIPS Provider 模塊和默認 Provider 將共享相同的源代碼,在不同的條件下,例如不同的#include路徑或定義的宏不同(後者需要在構建系統中添加支持)。下面是一個示例build.info文件,實現了這一點:

PROVIDERS=p_fips p_default

SOURCE[p_fips]=foo.c
INCLUDE[p_fips]=include/fips

SOURCE[p_default]=foo.c
INCLUDE[p_default]=include/default

或者,使用宏:

PROVIDERS=p_fips p_default

SOURCE[p_fips]=foo.c
DEFINE[p_fips]=FIPS_MODE

SOURCE[p_default]=foo.c

注意:一些關鍵字還不是 build.info 語言的一部分。

條件代碼

我們需要對編譯時包含 FIPS 特定代碼的方法進行一致處理,並在某些情況下排除 FIPS 不允許的代碼。

編譯時的控制將通過#ifdef FIPS_MODE來進行,這確保所有相關的文件都明確地為非 FIPS 或在 FIPS 模塊內部進行編譯,由於每個文件都將被編譯兩次(在默認 Provider 和 FIPS 模塊中各一次),一次使用每個設置,因此使用具有恆定值的運行時if語句沒有好處。(此外,運行時設置並不總是有效(例如在擴展諸如BLOCK_CIPHER_custom之類的宏時,會創建全局變量或函數指針。)

構建系統將通過使用-DFIPS_MODE編譯 FIPS Provider 對象文件,以及不帶命令行定義的來自相同源的默認 Provider 對象文件來支持此操作。

對於運行時檢查,將需要檢查 TLS 連接是否處於 FIPS 模式,這可以通過以通用方式檢查與特定SSL_CTXSSL對象關聯的屬性查詢字符串來完成,以查看是否設置了“fips”屬性。

FIPS 測試

需要進行以下類型的測試:

  • 用於 CMVP 驗證算法的 CAVS 測試;
  • 能夠運行所有 FIPS 模塊算法的 FIPS 測試套件;
  • 啓動後故障測試;
  • Acumen 將編寫使用 libcrypto 的應用程序,通過 EVP 層訪問 FIPS Provider。

任何需要返回中間值(例如 CAVS 密鑰生成)以顯示信息(自檢狀態)或更改 FIPS 模塊代碼的正常流程的特殊情況代碼(例如自檢失敗或在提供固定隨機值的密鑰生成循環中失敗),將通過將回調函數嵌入到FIPS模塊代碼中進行控制。

建議將這些回調代碼以條件編譯的方式編入模塊中中,因為其中一些值不應該被返回(例如,FIPS 模塊不應該輸出密鑰生成中的中間值)。

針對需要使用固定 rand_bytes 的測試,將對rand_bytes()進行重寫。

FIPS 測試回調

應用程序可以選擇提供一個回調函數,用於處理從 FIPS 模塊接收到的值(如果需要,可以註冊多個回調函數)。

可選的應用程序回調函數的形式如下:

static int fips_test_callback(const char *type, void *arg)
{
    return 1;
}

回調函數的返回值可用於控制 FIPS 模塊代碼中的特殊情況的流程。

類型由 FIPS 模塊鈎子傳入,FIPS模塊中的每個不同的鈎子應具有唯一的類型,類型決定了參數 arg 的內容(可以是結構體(例如中間值)、名稱或整數)。

FIPS 模塊中的回調函數的形式如下:

MY_STRUCT  data;   /* values that need to be returned to the application */
data.i = 1;
.....
if (FIPS_test_cb != NULL)
    FIPS_test_cb(FIPS_TEST_CB_RSA_KEYGEN_GET, (void *)&data);

POST 故障測試和日誌記錄

為了支持多個測試的失敗,所有測試將始終運行而不提前退出(只是標記失敗),在所有測試完成後,將返回失敗狀態。

用於日誌記錄或失敗的參數將為:

struct {
    const char *desc;
    const char *state;
    const char *fail_reason;
};

其中:

  • type 是“post_integrity”、“post_cipher”、“post_digest”、“post_signature”、“post_drbg”等之一;
  • desc 是標識性名稱,例如 AES_128_CBC
  • state 是以下之一:

<!---->

    • “start” - 表示測試開始
    • “corrupt” - 如果返回值為0,則測試將失敗
    • “pass” - 表示測試通過
    • “fail” - 表示測試失敗

<!---->

  • fail_reason - 是失敗的具體原因(例如,無法讀取完整性模塊文件或完整性校驗和文件)。

CAVS測試

CAVS 測試將由實驗室執行。

然而,每個 CAVS 測試文件也可以進行抽樣,並添加到單元測試中,這意味着可以將單個測試的文件數據轉換為單元測試內的二進制數據。

DRBG_ctr 是已經實現了此功能的示例)。

這將確保以下內容:

  • CAVS 測試將可訪問所需的接口(某些 CAVS 測試需要訪問通常不需要的內部接口);
  • 算法的正常工作;
  • 覆蓋率。

如果與實驗室之間有良好的溝通,我們可以跳過此步驟,但如果實驗室發現缺少對內部訪問器的訪問,可能需要在代碼中添加一些額外的回調鈎子。

user avatar nick_58a54a169c75f 頭像 wucao 頭像
2 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.