Skip to content

gln_key_store_t is the EBICS key-material abstraction. It lets an embedder keep subscriber keys and bank-key staging in a file, secure enclave, HSM, PKCS#11 token, cloud KMS, or application database while exposing one C vtable to Galanthus.

Functions

GLN_API gln_status_t GLN_CALL gln_create_key_store(
    const gln_key_store_vtable_t* in_vtable,
    gln_key_store_t**             out_store,
    gln_error_t*                  out_error);

GLN_API gln_status_t GLN_CALL gln_create_file_key_store(
    const char*       in_key_blob_path,
    const char*       in_sidecar_key_path_or_null,
    gln_key_store_t** out_store,
    gln_error_t*      out_error);

GLN_API void GLN_CALL gln_destroy_key_store(gln_key_store_t* in_store);

gln_open_ebics_backend consumes the key store:

GLN_API gln_status_t GLN_CALL gln_open_ebics_backend(
    const gln_ebics_config_t* in_config,
    gln_key_store_t*          in_key_store,
    gln_backend_t**           out_backend,
    gln_error_t*              out_error);

The backend retains the underlying key-store implementation during open, so the C key-store handle itself can be destroyed after a successful EBICS backend open. The object referenced by a custom vtable's user_data remains host-owned; keep it alive until no live key-store handle or retained EBICS backend can invoke the callbacks.

The bundled file-backed implementation stores an encrypted key blob at in_key_blob_path. in_sidecar_key_path_or_null selects the sidecar key path; pass NULL for the implementation default. If the helper is unavailable in the current build or platform, it returns GLN_ERR_NOT_SUPPORTED.

Vtable

typedef struct {
    gln_status_t (GLN_CALL *generate_keys)(void* in_user_data);
    gln_status_t (GLN_CALL *has_keys)(
        void* in_user_data,
        int*  out_has_keys);
    gln_status_t (GLN_CALL *authentication_public_key_json)(
        void*  in_user_data,
        char** out_json);
    gln_status_t (GLN_CALL *encryption_public_key_json)(
        void*  in_user_data,
        char** out_json);
    gln_status_t (GLN_CALL *signature_public_key_json)(
        void*  in_user_data,
        char** out_json);
    gln_status_t (GLN_CALL *sign_authentication)(
        void*          in_user_data,
        const uint8_t* in_digest,
        size_t         in_digest_len,
        uint8_t**      out_signature,
        size_t*        out_len);
    gln_status_t (GLN_CALL *sign_order)(
        void*          in_user_data,
        const uint8_t* in_digest,
        size_t         in_digest_len,
        uint8_t**      out_signature,
        size_t*        out_len);
    gln_status_t (GLN_CALL *decrypt_transaction_key)(
        void*          in_user_data,
        const uint8_t* in_encrypted_key,
        size_t         in_encrypted_key_len,
        uint8_t**      out_key,
        size_t*        out_len);
    gln_status_t (GLN_CALL *authentication_certificate_der)(
        void*     in_user_data,
        uint8_t** out_data,
        size_t*   out_len);
    gln_status_t (GLN_CALL *encryption_certificate_der)(
        void*     in_user_data,
        uint8_t** out_data,
        size_t*   out_len);
    gln_status_t (GLN_CALL *signature_certificate_der)(
        void*     in_user_data,
        uint8_t** out_data,
        size_t*   out_len);
    gln_status_t (GLN_CALL *store_bank_keys_json)(
        void*       in_user_data,
        const char* in_bank_keys_json);
    gln_status_t (GLN_CALL *load_bank_keys_json)(
        void*  in_user_data,
        char** out_bank_keys_json);
    gln_status_t (GLN_CALL *store_pending_bank_keys_json)(
        void*       in_user_data,
        const char* in_bank_keys_json);
    gln_status_t (GLN_CALL *load_pending_bank_keys_json)(
        void*  in_user_data,
        char** out_bank_keys_json);
    gln_status_t (GLN_CALL *promote_pending_bank_keys_json)(
        void*  in_user_data,
        char** out_bank_keys_json);
    gln_status_t (GLN_CALL *reset_bank_keys)(void* in_user_data);
    gln_status_t (GLN_CALL *clear_pending_bank_keys)(void* in_user_data);
    gln_status_t (GLN_CALL *reset_client_keys)(void* in_user_data);
    void (GLN_CALL *free_buffer)(void* in_user_data, void* in_buffer);
    void* user_data;
} gln_key_store_vtable_t;

Every function pointer is required. user_data may be NULL. gln_create_key_store returns GLN_ERR_INVALID_ARG when the vtable pointer, output slot, or a required callback is missing.

Callback Groups

Client key lifecycle:

  • generate_keys creates the authentication, encryption, and signature key material if it is not already present. Implement it idempotently where the backing store allows that.
  • has_keys writes 1 to *out_has_keys only when all required client keys are present; otherwise write 0.
  • reset_client_keys erases the local client key material.

Public material:

  • authentication_public_key_json, encryption_public_key_json, and signature_public_key_json return freshly allocated JSON strings.
  • authentication_certificate_der, encryption_certificate_der, and signature_certificate_der return freshly allocated DER byte buffers and lengths.

Cryptographic operations:

  • sign_authentication signs in_digest[0..in_digest_len) with the authentication key and writes a freshly allocated signature buffer.
  • sign_order signs with the order-signing key.
  • decrypt_transaction_key decrypts in_encrypted_key with the encryption private key and writes a freshly allocated transaction key buffer.

Bank key staging:

  • store_bank_keys_json persists trusted bank keys. The input string is library-owned and valid only for the callback.
  • load_bank_keys_json returns trusted bank keys or GLN_ERR_NOT_FOUND.
  • store_pending_bank_keys_json persists downloaded but not-yet-trusted bank keys.
  • load_pending_bank_keys_json returns pending bank keys or GLN_ERR_NOT_FOUND.
  • promote_pending_bank_keys_json atomically promotes pending keys to trusted keys and returns the trusted JSON, or returns GLN_ERR_NOT_FOUND if there is nothing to promote.
  • reset_bank_keys clears trusted bank keys.
  • clear_pending_bank_keys clears only pending bank keys.

Bookkeeping:

  • free_buffer releases every non-null buffer produced by one of the output callbacks above. It receives both char* strings and uint8_t* byte buffers as void*.
  • user_data is passed unchanged to each callback.

Ownership Rules

Every output callback allocates with the embedder's allocator and returns the fresh pointer through an out_ parameter. The library reads that buffer and later calls free_buffer(in_user_data, pointer) exactly once.

Every const input pointer is borrowed from the library for the duration of the callback. Do not retain it. Copy it into the backing store if it must live after the callback returns.

This means the embedder controls allocation for key-store outputs, but also owns matching deallocation through free_buffer. Cross-allocator release is a process-heap bug.

Minimal Custom Shape

struct hsm_key_store {
    void* session;
    const char* trusted_bank_keys_path;
    const char* pending_bank_keys_path;
};

static gln_status_t hsm_sign_authentication(
    void* in_user_data,
    const uint8_t* in_digest,
    size_t in_digest_len,
    uint8_t** out_signature,
    size_t* out_len)
{
    struct hsm_key_store* store = (struct hsm_key_store*)in_user_data;
    (void)store;
    (void)in_digest;
    (void)in_digest_len;

    /* Allocate *out_signature with malloc or the store allocator. */
    *out_signature = NULL;
    *out_len = 0;
    return GLN_OK;
}

static gln_status_t hsm_load_bank_keys_json(
    void* in_user_data,
    char** out_bank_keys_json)
{
    struct hsm_key_store* store = (struct hsm_key_store*)in_user_data;
    (void)store;

    /* Return GLN_ERR_NOT_FOUND if no trusted bank keys exist yet. */
    *out_bank_keys_json = NULL;
    return GLN_ERR_NOT_FOUND;
}

static void hsm_free_buffer(void* in_user_data, void* in_buffer)
{
    (void)in_user_data;
    free(in_buffer);
}

The real vtable must fill every callback, not only the callbacks shown above.

See Also

  • Conventions - status, error, and ownership model.
  • Stores - the state and continuation vtable pattern.
  • Troubleshooting - key-store allocator and platform issues.