telegabber/e2ee/omemo/libsignal/store.go
2026-07-28 00:38:46 -04:00

204 lines
9.1 KiB
Go

package libsignal
/*
#include <signal_protocol.h>
#include <stdint.h>
// Forward declarations of the Go-exported store callbacks implemented in
// callbacks.go. See context.go for why these are hand-written rather than
// relying on a generated header, and why const-qualifier differences from
// the "true" cgo-generated prototypes are harmless here.
extern int go_get_identity_key_pair(signal_buffer **public_data, signal_buffer **private_data, void *user_data);
extern int go_get_local_registration_id(void *user_data, uint32_t *registration_id);
extern int go_save_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data);
extern int go_is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data);
extern void go_identity_destroy(void *user_data);
extern int go_load_pre_key(signal_buffer **record, uint32_t pre_key_id, void *user_data);
extern int go_store_pre_key(uint32_t pre_key_id, uint8_t *record, size_t record_len, void *user_data);
extern int go_contains_pre_key(uint32_t pre_key_id, void *user_data);
extern int go_remove_pre_key(uint32_t pre_key_id, void *user_data);
extern void go_pre_key_destroy(void *user_data);
extern int go_load_signed_pre_key(signal_buffer **record, uint32_t signed_pre_key_id, void *user_data);
extern int go_store_signed_pre_key(uint32_t signed_pre_key_id, uint8_t *record, size_t record_len, void *user_data);
extern int go_contains_signed_pre_key(uint32_t signed_pre_key_id, void *user_data);
extern int go_remove_signed_pre_key(uint32_t signed_pre_key_id, void *user_data);
extern void go_signed_pre_key_destroy(void *user_data);
extern int go_load_session(signal_buffer **record, signal_buffer **user_record, const signal_protocol_address *address, void *user_data);
extern int go_get_sub_device_sessions(signal_int_list **sessions, const char *name, size_t name_len, void *user_data);
extern int go_store_session(const signal_protocol_address *address, uint8_t *record, size_t record_len, uint8_t *user_record, size_t user_record_len, void *user_data);
extern int go_contains_session(const signal_protocol_address *address, void *user_data);
extern int go_delete_session(const signal_protocol_address *address, void *user_data);
extern int go_delete_all_sessions(const char *name, size_t name_len, void *user_data);
extern void go_session_destroy(void *user_data);
static void telegabber_fill_identity_key_store(signal_protocol_identity_key_store *s, void *user_data) {
s->get_identity_key_pair = go_get_identity_key_pair;
s->get_local_registration_id = go_get_local_registration_id;
s->save_identity = go_save_identity;
s->is_trusted_identity = go_is_trusted_identity;
s->destroy_func = go_identity_destroy;
s->user_data = user_data;
}
static void telegabber_fill_pre_key_store(signal_protocol_pre_key_store *s, void *user_data) {
s->load_pre_key = go_load_pre_key;
s->store_pre_key = go_store_pre_key;
s->contains_pre_key = go_contains_pre_key;
s->remove_pre_key = go_remove_pre_key;
s->destroy_func = go_pre_key_destroy;
s->user_data = user_data;
}
static void telegabber_fill_signed_pre_key_store(signal_protocol_signed_pre_key_store *s, void *user_data) {
s->load_signed_pre_key = go_load_signed_pre_key;
s->store_signed_pre_key = go_store_signed_pre_key;
s->contains_signed_pre_key = go_contains_signed_pre_key;
s->remove_signed_pre_key = go_remove_signed_pre_key;
s->destroy_func = go_signed_pre_key_destroy;
s->user_data = user_data;
}
static void telegabber_fill_session_store(signal_protocol_session_store *s, void *user_data) {
s->load_session_func = go_load_session;
s->get_sub_device_sessions_func = go_get_sub_device_sessions;
s->store_session_func = go_store_session;
s->contains_session_func = go_contains_session;
s->delete_session_func = go_delete_session;
s->delete_all_sessions_func = go_delete_all_sessions;
s->destroy_func = go_session_destroy;
s->user_data = user_data;
}
*/
import "C"
import (
"runtime/cgo"
"unsafe"
)
// IdentityStore persists the local identity key pair/registration id and
// tracks trust for remote identities.
type IdentityStore interface {
// GetIdentityKeyPair returns this store's own identity key pair
// (public and private key, in the library's serialized form).
GetIdentityKeyPair() (public, private []byte, err error)
// GetLocalRegistrationID returns this store's own registration id.
GetLocalRegistrationID() (uint32, error)
// SaveIdentity records addr's identity key as trusted. A nil key
// means: forget the key material but keep any other bookkeeping.
SaveIdentity(addr Address, key []byte) error
// IsTrustedIdentity reports whether key is the trusted identity key
// for addr. Per the library's TOFU convention, an address with no
// stored identity at all is trusted implicitly (return true, nil) -
// only a *mismatching* stored key should be rejected.
IsTrustedIdentity(addr Address, key []byte) (bool, error)
}
// PreKeyStore persists this identity's own one-time prekeys.
type PreKeyStore interface {
LoadPreKey(id uint32) (record []byte, found bool, err error)
StorePreKey(id uint32, record []byte) error
ContainsPreKey(id uint32) bool
RemovePreKey(id uint32) error
}
// SignedPreKeyStore persists this identity's own signed prekeys.
type SignedPreKeyStore interface {
LoadSignedPreKey(id uint32) (record []byte, found bool, err error)
StoreSignedPreKey(id uint32, record []byte) error
ContainsSignedPreKey(id uint32) bool
RemoveSignedPreKey(id uint32) error
}
// SessionStore persists per-device Double Ratchet session state.
type SessionStore interface {
LoadSession(addr Address) (record []byte, found bool, err error)
// GetSubDeviceSessions returns the device IDs of all known sessions
// for name, excluding the sentinel device ID 1 (per library
// convention - see get_sub_device_sessions_func in signal_protocol.h).
GetSubDeviceSessions(name string) ([]uint32, error)
StoreSession(addr Address, record []byte) error
ContainsSession(addr Address) bool
DeleteSession(addr Address) error
// DeleteAllSessions removes every session for name and returns how
// many were deleted.
DeleteAllSessions(name string) (int, error)
}
// Store is the full persistence contract libomemo-c requires: one local
// identity's keys, prekeys, and remote sessions/trust state.
type Store interface {
IdentityStore
PreKeyStore
SignedPreKeyStore
SessionStore
}
// StoreContext wraps a signal_protocol_store_context bound to a Go Store
// implementation via a runtime/cgo.Handle (C void* cannot safely hold a Go
// interface value directly - see callbacks.go for the recovery side).
type StoreContext struct {
raw *C.signal_protocol_store_context
ctx *Context
handle cgo.Handle
}
// NewStoreContext creates a signal_protocol_store_context that dispatches
// every callback to store. ctx must outlive the returned StoreContext.
func NewStoreContext(ctx *Context, store Store) (*StoreContext, error) {
var raw *C.signal_protocol_store_context
if code := C.signal_protocol_store_context_create(&raw, ctx.raw); code != C.SG_SUCCESS {
return nil, newError("signal_protocol_store_context_create", int(code))
}
handle := cgo.NewHandle(store)
// go vet flags this as "possible misuse of unsafe.Pointer" - expected,
// see the note in crypto.go's go_crypto_hmac_sha256_init: a cgo.Handle
// is an opaque uintptr token, never dereferenced as a real address, and
// the vtable structs' user_data fields require void* here.
userData := unsafe.Pointer(uintptr(handle))
var idStore C.signal_protocol_identity_key_store
C.telegabber_fill_identity_key_store(&idStore, userData)
if code := C.signal_protocol_store_context_set_identity_key_store(raw, &idStore); code != C.SG_SUCCESS {
handle.Delete()
return nil, newError("signal_protocol_store_context_set_identity_key_store", int(code))
}
var pkStore C.signal_protocol_pre_key_store
C.telegabber_fill_pre_key_store(&pkStore, userData)
if code := C.signal_protocol_store_context_set_pre_key_store(raw, &pkStore); code != C.SG_SUCCESS {
handle.Delete()
return nil, newError("signal_protocol_store_context_set_pre_key_store", int(code))
}
var spkStore C.signal_protocol_signed_pre_key_store
C.telegabber_fill_signed_pre_key_store(&spkStore, userData)
if code := C.signal_protocol_store_context_set_signed_pre_key_store(raw, &spkStore); code != C.SG_SUCCESS {
handle.Delete()
return nil, newError("signal_protocol_store_context_set_signed_pre_key_store", int(code))
}
var sessStore C.signal_protocol_session_store
C.telegabber_fill_session_store(&sessStore, userData)
if code := C.signal_protocol_store_context_set_session_store(raw, &sessStore); code != C.SG_SUCCESS {
handle.Delete()
return nil, newError("signal_protocol_store_context_set_session_store", int(code))
}
return &StoreContext{raw: raw, ctx: ctx, handle: handle}, nil
}
// Close destroys the underlying signal_protocol_store_context and releases
// the Go-side handle keeping the Store alive. Do not use the StoreContext
// (or anything built from it) afterward.
func (sc *StoreContext) Close() {
if sc.raw != nil {
C.signal_protocol_store_context_destroy(sc.raw)
sc.raw = nil
}
sc.handle.Delete()
}