package libsignal /* #include #include // 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() }