mirror of
https://dev.narayana.im/narayana/telegabber.git
synced 2026-08-05 04:07:07 +00:00
204 lines
9.1 KiB
Go
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 (signal_protocol.h's get_sub_device_sessions_func: "all
|
|
// known devices with active sessions for a recipient").
|
|
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()
|
|
}
|