Derive Realm keys from a user password (Argon2id, no private key on disk). Login claims the sole chair with handover; peers share parliament context; --new-project clears it. CLI peer/discover helpers and Docker alpine recipe included; headless empty-answer retries raised for unattended runs. Co-authored-by: Cursor <cursoragent@cursor.com>
75 lines
2.9 KiB
C
75 lines
2.9 KiB
C
#ifndef CST_REALM_H
|
|
#define CST_REALM_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* User Realm keys (Ed25519). The seed is the durable secret; sk is the
|
|
* Monocypher expanded secret (seed||pk). Same Realm public key ⇒ peers may
|
|
* auto-discover and auto-connect. */
|
|
typedef struct cst_realm_keys {
|
|
uint8_t seed[32];
|
|
uint8_t sk[64];
|
|
uint8_t pk[32];
|
|
} cst_realm_keys_t;
|
|
|
|
/* Instance certificate signed by the Realm private key. */
|
|
typedef struct cst_realm_cert {
|
|
char instance_id[64];
|
|
char label[128];
|
|
uint8_t instance_pk[32];
|
|
int64_t not_after; /* unix seconds; 0 = no expiry */
|
|
uint8_t realm_pk[32];
|
|
uint8_t sig[64];
|
|
} cst_realm_cert_t;
|
|
|
|
/* Directory helpers: <config>/realm/{private.key,public.key,revoked}. */
|
|
int cst_realm_dir(char *out, size_t n);
|
|
int cst_realm_generate(cst_realm_keys_t *out);
|
|
int cst_realm_derive(cst_realm_keys_t *out, const uint8_t seed[32]);
|
|
int cst_realm_save(const char *dir, const cst_realm_keys_t *k);
|
|
int cst_realm_load(const char *dir, cst_realm_keys_t *out);
|
|
/* 32 hex chars (blake2b-128 of pk). */
|
|
int cst_realm_fingerprint(const uint8_t pk[32], char out[33]);
|
|
|
|
/* Password-string Realm: Argon2id(password, salt) → seed. Private key is not
|
|
* stored; only salt + public.key live on disk. Unlock derives sk in memory. */
|
|
int cst_realm_derive_password(cst_realm_keys_t *out, const char *password,
|
|
const uint8_t salt[16]);
|
|
int cst_realm_init_password(const char *dir, const char *password);
|
|
int cst_realm_unlock_password(const char *dir, const char *password,
|
|
cst_realm_keys_t *out);
|
|
int cst_realm_is_password_mode(const char *dir);
|
|
|
|
int cst_realm_enroll(const cst_realm_keys_t *realm, const char *instance_id,
|
|
const char *label, int64_t not_after, cst_realm_cert_t *cert,
|
|
uint8_t instance_seed[32], uint8_t instance_sk[64]);
|
|
int cst_realm_verify_cert(const uint8_t realm_pk[32], const cst_realm_cert_t *cert,
|
|
int64_t now_unix);
|
|
char *cst_realm_cert_to_json(const cst_realm_cert_t *cert);
|
|
int cst_realm_cert_from_json(const char *json, cst_realm_cert_t *out);
|
|
|
|
int cst_realm_challenge_sign(const uint8_t instance_sk[64], const void *chal,
|
|
size_t n, uint8_t sig[64]);
|
|
int cst_realm_challenge_check(const cst_realm_cert_t *cert, const void *chal,
|
|
size_t n, const uint8_t sig[64]);
|
|
|
|
int cst_realm_revoke_add(const char *dir, const char *instance_id);
|
|
int cst_realm_revoked(const char *dir, const char *instance_id);
|
|
|
|
/* Persist an enrolled instance under <realm>/instances/<id>/. */
|
|
int cst_realm_instance_save(const char *instance_id, const cst_realm_cert_t *cert,
|
|
const uint8_t instance_seed[32]);
|
|
int cst_realm_instance_load(const char *instance_id, cst_realm_cert_t *cert,
|
|
uint8_t instance_sk[64]);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|