Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

C/C++ FFI ブリッジ

edgesentry-bridgeは、 Ed25519 署名と BLAKE3 ハッシュチェーン検証を安定した C ABI として公開する独立した Rust クレートです。 C および C++のファームウェアやゲートウェイは、全面的な書き直しなしに Rust ライブラリと同じセキュリティロジックを呼び出せます。


ライブラリのビルド

cargo build -p edgesentry-bridge --release

生成されるファイル:

プラットフォームファイル
macOStarget/release/libedgesentry_bridge.dylibおよび.a
Linuxtarget/release/libedgesentry_bridge.soおよび.a

ヘッダーcrates/edgesentry-bridge/include/edgesentry_bridge.hbuild.rscbindgenを使って自動的に再生成します。


C/C++からのリンク

macOS:

cc -o my_app main.c \
   -I path/to/edgesentry-bridge/include \
   -L path/to/target/release \
   -ledgesentry_bridge \
   -framework Security -framework CoreFoundation

Linux:

cc -o my_app main.c \
   -I path/to/edgesentry-bridge/include \
   -L path/to/target/release \
   -ledgesentry_bridge \
   -lpthread -ldl

既製のMakefilecrates/edgesentry-bridge/examples/c_integration/に用意されています。


API リファレンス

エラーコード

定数意味
EDS_OK0成功
EDS_ERR_NULL_PTR-1必須ポインタが NULL だった
EDS_ERR_INVALID_UTF8-2文字列引数が有効な UTF-8 でない
EDS_ERR_INVALID_KEY-3鍵またはハッシュバッファが無効
EDS_ERR_STRING_TOO_LONG-4文字列が固定バッファサイズを超えている
EDS_ERR_CHAIN_INVALID-5ハッシュチェーン検証に失敗
EDS_ERR_PANIC-6予期しない内部エラー
EDS_ERR_HASH_MISMATCH-7ペイロードハッシュが期待値と一致しない
EDS_ERR_BAD_SIGNATURE-8Ed25519 署名が無効

負のエラーコードを返す呼び出しの後は、eds_last_error_message() を呼び出すと失敗の人間が読めるメッセージを取得できます。

レコード構造体

typedef struct {
    uint64_t sequence;           /* monotonic record index (starts at 1) */
    uint64_t timestamp_ms;       /* Unix epoch in milliseconds           */
    uint8_t  payload_hash[32];   /* BLAKE3 hash of the raw payload        */
    uint8_t  signature[64];      /* Ed25519 signature over payload_hash   */
    uint8_t  prev_record_hash[32]; /* hash of preceding record (zero for first) */
    uint8_t  device_id[256];     /* null-terminated device identifier     */
    uint8_t  object_ref[512];    /* null-terminated storage reference     */
} EdsAuditRecord;

EdsAuditRecord呼び出し元が確保 します。 Rust はmallocを呼び出したりヒープポインタを返したりしません。そのため_free関数は不要です。

関数

/* Generate an Ed25519 keypair via OS CSPRNG.
   private_key_out and public_key_out must each point to 32 bytes. */
int32_t eds_keygen(uint8_t *private_key_out, uint8_t *public_key_out);

/* Hash payload with BLAKE3, sign with Ed25519, fill *out.
   Pass NULL for prev_record_hash to use the zero hash (first record). */
int32_t eds_sign_record(const char    *device_id,
                        uint64_t       sequence,
                        uint64_t       timestamp_ms,
                        const uint8_t *payload,
                        size_t         payload_len,
                        const uint8_t *prev_record_hash,
                        const char    *object_ref,
                        const uint8_t *private_key,
                        EdsAuditRecord *out);

/* Compute the per-record hash (used as prev_record_hash for the next record).
   hash_out must point to 32 bytes. */
int32_t eds_record_hash(const EdsAuditRecord *record, uint8_t *hash_out);

/* Verify Ed25519 signature. Returns 1 valid, 0 invalid, negative on error. */
int32_t eds_verify_record(const EdsAuditRecord *record,
                          const uint8_t *public_key);

/* Verify the entire hash chain. Returns EDS_OK or EDS_ERR_CHAIN_INVALID. */
int32_t eds_verify_chain(const EdsAuditRecord *records, size_t count);

/* インストール前にソフトウェアアップデートを検証する(CLS-03 / STAR-2 R2.2)。
   BLAKE3(payload) == payload_hash を確認し、次に payload_hash に対する
   Ed25519 パブリッシャー署名を検証する。
   payload_hash は 32 バイト、signature は 64 バイト、
   publisher_key は 32 バイトを指す必要がある。
   成功時 EDS_OK、失敗時 EDS_ERR_HASH_MISMATCH / EDS_ERR_BAD_SIGNATURE、
   入力不正時 EDS_ERR_INVALID_KEY / EDS_ERR_NULL_PTR を返す。 */
int32_t eds_verify_update(const uint8_t *payload,
                          size_t         payload_len,
                          const uint8_t *payload_hash,
                          const uint8_t *signature,
                          const uint8_t *publisher_key);

/* スレッドローカルに保存された最後のエラーメッセージを返す。
   ポインタは同スレッドで次の eds_* 呼び出しまで有効。
   エラーがない場合は "" を返す。NULL を返すことはない。 */
const char *eds_last_error_message(void);

最小限の C サンプル

#include "edgesentry_bridge.h"
#include <string.h>
#include <assert.h>

int main(void) {
    uint8_t priv_key[32], pub_key[32];
    if (eds_keygen(priv_key, pub_key) != EDS_OK) {
        fprintf(stderr, "keygen failed: %s\n", eds_last_error_message());
        return 1;
    }

    const char *payload = "check=door,status=ok";
    EdsAuditRecord rec;
    memset(&rec, 0, sizeof(rec));

    int rc = eds_sign_record("lift-01", 1, 1700000000000ULL,
                             (const uint8_t *)payload, strlen(payload),
                             NULL,              /* zero hash — first record */
                             "lift-01/1.bin",
                             priv_key, &rec);
    if (rc != EDS_OK) {
        fprintf(stderr, "sign_record failed: %s\n", eds_last_error_message());
        return 1;
    }

    assert(eds_verify_record(&rec, pub_key) == 1);
    return 0;
}

完全なサンプルはcrates/edgesentry-bridge/examples/c_integration/main.cを参照してください。


メモリ安全規約

規約詳細
ヒープ確保なしEdsAuditRecordは呼び出し元が確保。 Rust はmallocを呼び出さない
NULL チェックすべてのポインタ引数はチェック済み。失敗時はEDS_ERR_NULL_PTRを返す
固定長文字列device_idは最大 255 文字、object_refは最大 511 文字。超過入力はEDS_ERR_STRING_TOO_LONGを返す
パニック安全性すべての FFI 関数をstd::panic::catch_unwindでラップ。 Rust パニックは C 境界を越えてアンワインドする代わりにEDS_ERR_PANICを返す
鍵サイズprivate_keypublic_keyはちょうど 32 バイトを指していなければならない。ハッシュバッファは 32 バイト、署名バッファは 64 バイト

HSM パス

CLS レベル 4 では、秘密鍵は抽出可能なバイト配列として存在すべきではありません。計画中の HSM 統合(#54)では、鍵バイトを呼び出し元に公開することなくeds_sign_record操作を HSM バックのプロバイダーに委譲します。