summaryrefslogtreecommitdiff
path: root/libs/libaxolotl/src/axolotl.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libaxolotl/src/axolotl.c')
-rw-r--r--libs/libaxolotl/src/axolotl.c1071
1 files changed, 1071 insertions, 0 deletions
diff --git a/libs/libaxolotl/src/axolotl.c b/libs/libaxolotl/src/axolotl.c
new file mode 100644
index 0000000000..7db1cbfc88
--- /dev/null
+++ b/libs/libaxolotl/src/axolotl.c
@@ -0,0 +1,1071 @@
+#include "axolotl.h"
+#include "axolotl_internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include "utlist.h"
+#include "utarray.h"
+
+#ifdef _WINDOWS
+#include "Windows.h"
+#include "WinBase.h"
+#endif
+
+#ifdef DEBUG_REFCOUNT
+int type_ref_count = 0;
+int type_unref_count = 0;
+#endif
+
+struct axolotl_store_context {
+ axolotl_context *global_context;
+ axolotl_session_store session_store;
+ axolotl_pre_key_store pre_key_store;
+ axolotl_signed_pre_key_store signed_pre_key_store;
+ axolotl_identity_key_store identity_key_store;
+ axolotl_sender_key_store sender_key_store;
+};
+
+void axolotl_type_init(axolotl_type_base *instance,
+ void (*destroy_func)(axolotl_type_base *instance))
+{
+ instance->ref_count = 1;
+ instance->destroy = destroy_func;
+#ifdef DEBUG_REFCOUNT
+ type_ref_count++;
+#endif
+}
+
+void axolotl_type_ref(axolotl_type_base *instance)
+{
+#ifdef DEBUG_REFCOUNT
+ type_ref_count++;
+#endif
+ assert(instance);
+ assert(instance->ref_count > 0);
+ instance->ref_count++;
+}
+
+void axolotl_type_unref(axolotl_type_base *instance)
+{
+ if(instance) {
+#ifdef DEBUG_REFCOUNT
+ type_unref_count++;
+#endif
+ assert(instance->ref_count > 0);
+ if(instance->ref_count > 1) {
+ instance->ref_count--;
+ }
+ else {
+ instance->destroy(instance);
+ }
+ }
+}
+
+#ifdef DEBUG_REFCOUNT
+int axolotl_type_ref_count(axolotl_type_base *instance)
+{
+ return instance->ref_count;
+}
+#endif
+
+/*------------------------------------------------------------------------*/
+
+axolotl_buffer *axolotl_buffer_alloc(size_t len)
+{
+ axolotl_buffer *buffer;
+ if(len > (SIZE_MAX - sizeof(struct axolotl_buffer)) / sizeof(uint8_t)) {
+ return 0;
+ }
+
+ buffer = malloc(sizeof(struct axolotl_buffer) + (sizeof(uint8_t) * len));
+ if(buffer) {
+ buffer->len = len;
+ }
+ return buffer;
+}
+
+axolotl_buffer *axolotl_buffer_create(const uint8_t *data, size_t len)
+{
+ axolotl_buffer *buffer = axolotl_buffer_alloc(len);
+ if(!buffer) {
+ return 0;
+ }
+
+ memcpy(buffer->data, data, len);
+ return buffer;
+}
+
+axolotl_buffer *axolotl_buffer_copy(const axolotl_buffer *buffer)
+{
+ return axolotl_buffer_create(buffer->data, buffer->len);
+}
+
+axolotl_buffer *axolotl_buffer_append(axolotl_buffer *buffer, const uint8_t *data, size_t len)
+{
+ size_t previous_size = buffer->len;
+ size_t previous_alloc = sizeof(struct axolotl_buffer) + (sizeof(uint8_t) * previous_size);
+ axolotl_buffer *tmp_buffer = realloc(buffer, previous_alloc + (sizeof(uint8_t) * len));
+ if(!tmp_buffer) {
+ return 0;
+ }
+
+ memcpy(tmp_buffer->data + previous_size, data, len);
+ tmp_buffer->len = previous_size + len;
+ return tmp_buffer;
+}
+
+uint8_t *axolotl_buffer_data(axolotl_buffer *buffer)
+{
+ return buffer->data;
+}
+
+size_t axolotl_buffer_len(axolotl_buffer *buffer)
+{
+ return buffer->len;
+}
+
+int axolotl_buffer_compare(axolotl_buffer *buffer1, axolotl_buffer *buffer2)
+{
+ if(buffer1 == buffer2) {
+ return 0;
+ }
+ else if(buffer1 == 0 && buffer2 != 0) {
+ return -1;
+ }
+ else if(buffer1 != 0 && buffer2 == 0) {
+ return 1;
+ }
+ else {
+ if(buffer1->len < buffer2->len) {
+ return -1;
+ }
+ else if(buffer1->len > buffer2->len) {
+ return 1;
+ }
+ else {
+ return axolotl_constant_memcmp(buffer1->data, buffer2->data, buffer1->len);
+ }
+ }
+}
+
+void axolotl_buffer_free(axolotl_buffer *buffer)
+{
+ if(buffer) {
+ free(buffer);
+ }
+}
+
+void axolotl_buffer_bzero_free(axolotl_buffer *buffer)
+{
+ if(buffer) {
+ axolotl_explicit_bzero(buffer->data, buffer->len);
+ free(buffer);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+typedef struct axolotl_buffer_list_node
+{
+ axolotl_buffer *buffer;
+ struct axolotl_buffer_list_node *next;
+} axolotl_buffer_list_node;
+
+struct axolotl_buffer_list
+{
+ int size;
+ axolotl_buffer_list_node *head;
+};
+
+struct axolotl_int_list
+{
+ UT_array *values;
+};
+
+axolotl_buffer_list *axolotl_buffer_list_alloc()
+{
+ axolotl_buffer_list *list = malloc(sizeof(axolotl_buffer_list));
+ if(list) {
+ memset(list, 0, sizeof(axolotl_buffer_list));
+ }
+ return list;
+}
+
+int axolotl_buffer_list_push(axolotl_buffer_list *list, axolotl_buffer *buffer)
+{
+ axolotl_buffer_list_node *node = 0;
+
+ assert(list);
+ assert(buffer);
+
+ node = malloc(sizeof(axolotl_buffer_list_node));
+
+ if(!node) {
+ return AX_ERR_NOMEM;
+ }
+
+ node->buffer = buffer;
+ LL_PREPEND(list->head, node);
+ list->size++;
+ return 0;
+}
+
+int axolotl_buffer_list_size(axolotl_buffer_list *list)
+{
+ assert(list);
+ return list->size;
+}
+
+void axolotl_buffer_list_free(axolotl_buffer_list *list)
+{
+ axolotl_buffer_list_node *cur_node;
+ axolotl_buffer_list_node *tmp_node;
+
+ assert(list);
+
+ LL_FOREACH_SAFE(list->head, cur_node, tmp_node) {
+ LL_DELETE(list->head, cur_node);
+ if(cur_node->buffer) {
+ axolotl_buffer_free(cur_node->buffer);
+ }
+ free(cur_node);
+ }
+ free(list);
+}
+axolotl_int_list *axolotl_int_list_alloc();
+
+/*------------------------------------------------------------------------*/
+
+axolotl_int_list *axolotl_int_list_alloc()
+{
+ axolotl_int_list *list = malloc(sizeof(axolotl_int_list));
+ if(!list) {
+ return 0;
+ }
+ memset(list, 0, sizeof(axolotl_int_list));
+ utarray_new(list->values, &ut_int_icd);
+ return list;
+}
+
+void axolotl_int_list_push_back(axolotl_int_list *list, int value)
+{
+ assert(list);
+ utarray_push_back(list->values, &value);
+}
+
+unsigned int axolotl_int_list_size(axolotl_int_list *list)
+{
+ assert(list);
+ return utarray_len(list->values);
+}
+
+int axolotl_int_list_at(axolotl_int_list *list, unsigned int index)
+{
+ int *value = 0;
+
+ assert(list);
+ assert(index >= 0 && index < utarray_len(list->values));
+
+ value = (int *)utarray_eltptr(list->values, index);
+
+ assert(value);
+
+ return *value;
+}
+
+void axolotl_int_list_free(axolotl_int_list *list)
+{
+ if(list) {
+ utarray_free(list->values);
+ free(list);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+int axolotl_context_create(axolotl_context **context, void *user_data)
+{
+ *context = malloc(sizeof(axolotl_context));
+ if(!(*context)) {
+ return AX_ERR_NOMEM;
+ }
+ memset(*context, 0, sizeof(axolotl_context));
+ (*context)->user_data = user_data;
+#ifdef DEBUG_REFCOUNT
+ type_ref_count = 0;
+ type_unref_count = 0;
+#endif
+ return 0;
+}
+
+int axolotl_context_set_crypto_provider(axolotl_context *context, const axolotl_crypto_provider *crypto_provider)
+{
+ assert(context);
+ if(!crypto_provider
+ || !crypto_provider->hmac_sha256_init_func
+ || !crypto_provider->hmac_sha256_update_func
+ || !crypto_provider->hmac_sha256_final_func
+ || !crypto_provider->hmac_sha256_cleanup_func) {
+ return AX_ERR_INVAL;
+ }
+ memcpy(&(context->crypto_provider), crypto_provider, sizeof(axolotl_crypto_provider));
+ return 0;
+}
+
+int axolotl_context_set_locking_functions(axolotl_context *context,
+ void (*lock)(void *user_data), void (*unlock)(void *user_data))
+{
+ assert(context);
+ if((lock && !unlock) || (!lock && unlock)) {
+ return AX_ERR_INVAL;
+ }
+
+ context->lock = lock;
+ context->unlock = unlock;
+ return 0;
+}
+
+int axolotl_context_set_log_function(axolotl_context *context,
+ void (*log)(int level, const char *message, size_t len, void *user_data))
+{
+ assert(context);
+ context->log = log;
+ return 0;
+}
+
+void axolotl_context_destroy(axolotl_context *context)
+{
+#ifdef DEBUG_REFCOUNT
+ fprintf(stderr, "Global REF count: %d\n", type_ref_count);
+ fprintf(stderr, "Global UNREF count: %d\n", type_unref_count);
+#endif
+ if(context) {
+ free(context);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+int axolotl_crypto_random(axolotl_context *context, uint8_t *data, size_t len)
+{
+ assert(context);
+ assert(context->crypto_provider.random_func);
+ return context->crypto_provider.random_func(data, len, context->crypto_provider.user_data);
+}
+
+int axolotl_hmac_sha256_init(axolotl_context *context, void **hmac_context, const uint8_t *key, size_t key_len)
+{
+ assert(context);
+ assert(context->crypto_provider.hmac_sha256_init_func);
+ return context->crypto_provider.hmac_sha256_init_func(hmac_context, key, key_len, context->crypto_provider.user_data);
+}
+
+int axolotl_hmac_sha256_update(axolotl_context *context, void *hmac_context, const uint8_t *data, size_t data_len)
+{
+ assert(context);
+ assert(context->crypto_provider.hmac_sha256_update_func);
+ return context->crypto_provider.hmac_sha256_update_func(hmac_context, data, data_len, context->crypto_provider.user_data);
+}
+
+int axolotl_hmac_sha256_final(axolotl_context *context, void *hmac_context, axolotl_buffer **output)
+{
+ assert(context);
+ assert(context->crypto_provider.hmac_sha256_final_func);
+ return context->crypto_provider.hmac_sha256_final_func(hmac_context, output, context->crypto_provider.user_data);
+}
+
+void axolotl_hmac_sha256_cleanup(axolotl_context *context, void *hmac_context)
+{
+ assert(context);
+ assert(context->crypto_provider.hmac_sha256_cleanup_func);
+ context->crypto_provider.hmac_sha256_cleanup_func(hmac_context, context->crypto_provider.user_data);
+}
+
+int axolotl_sha512_digest(axolotl_context *context, axolotl_buffer **output, const uint8_t *data, size_t data_len)
+{
+ assert(context);
+ assert(context->crypto_provider.sha512_digest_func);
+ return context->crypto_provider.sha512_digest_func(output, data, data_len, context->crypto_provider.user_data);
+}
+
+int axolotl_encrypt(axolotl_context *context,
+ axolotl_buffer **output,
+ int cipher,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *iv, size_t iv_len,
+ const uint8_t *plaintext, size_t plaintext_len)
+{
+ assert(context);
+ assert(context->crypto_provider.encrypt_func);
+ return context->crypto_provider.encrypt_func(
+ output, cipher, key, key_len, iv, iv_len,
+ plaintext, plaintext_len,
+ context->crypto_provider.user_data);
+}
+
+int axolotl_decrypt(axolotl_context *context,
+ axolotl_buffer **output,
+ int cipher,
+ const uint8_t *key, size_t key_len,
+ const uint8_t *iv, size_t iv_len,
+ const uint8_t *ciphertext, size_t ciphertext_len)
+{
+ assert(context);
+ assert(context->crypto_provider.decrypt_func);
+ return context->crypto_provider.decrypt_func(
+ output, cipher, key, key_len, iv, iv_len,
+ ciphertext, ciphertext_len,
+ context->crypto_provider.user_data);
+}
+
+void axolotl_lock(axolotl_context *context)
+{
+ if(context->lock) {
+ context->lock(context->user_data);
+ }
+}
+
+void axolotl_unlock(axolotl_context *context)
+{
+ if(context->unlock) {
+ context->unlock(context->user_data);
+ }
+}
+
+void axolotl_log(axolotl_context *context, int level, const char *format, ...)
+{
+ char buf[256];
+ int n;
+ if(context->log) {
+ va_list args;
+ va_start(args, format);
+ n = vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
+ if(n > 0) {
+ context->log(level, buf, strlen(buf), context->user_data);
+ }
+ }
+}
+
+void axolotl_explicit_bzero(void *v, size_t n)
+{
+#ifdef HAVE_SECUREZEROMEMORY
+ SecureZeroMemory(v, n);
+#elif HAVE_MEMSET_S
+ memset_s(v, n, 0, n);
+#else
+ volatile unsigned char *p = v;
+ while(n--) *p++ = 0;
+#endif
+}
+
+int axolotl_constant_memcmp(const void *s1, const void *s2, size_t n)
+{
+ size_t i;
+ const unsigned char *c1 = (const unsigned char *) s1;
+ const unsigned char *c2 = (const unsigned char *) s2;
+ unsigned char result = 0;
+
+ for (i = 0; i < n; i++) {
+ result |= c1[i] ^ c2[i];
+ }
+
+ return result;
+}
+
+void axolotl_str_serialize_protobuf(ProtobufCBinaryData *buffer, const char *str)
+{
+ assert(buffer);
+ assert(str);
+ buffer->data = (uint8_t *)str;
+ buffer->len = strlen(str);
+}
+
+char *axolotl_str_deserialize_protobuf(ProtobufCBinaryData *buffer)
+{
+ char *str = 0;
+ assert(buffer);
+
+ str = malloc(buffer->len + 1);
+ if(!str) {
+ return 0;
+ }
+
+ memcpy(str, buffer->data, buffer->len);
+ str[buffer->len] = '\0';
+
+ return str;
+}
+
+/*------------------------------------------------------------------------*/
+
+int axolotl_store_context_create(axolotl_store_context **context, axolotl_context *global_context)
+{
+ assert(global_context);
+ *context = malloc(sizeof(axolotl_store_context));
+ if(!(*context)) {
+ return AX_ERR_NOMEM;
+ }
+ memset(*context, 0, sizeof(axolotl_store_context));
+ (*context)->global_context = global_context;
+ return 0;
+}
+
+int axolotl_store_context_set_session_store(axolotl_store_context *context, const axolotl_session_store *store)
+{
+ if(!store) {
+ return AX_ERR_INVAL;
+ }
+ memcpy(&(context->session_store), store, sizeof(axolotl_session_store));
+ return 0;
+}
+
+int axolotl_store_context_set_pre_key_store(axolotl_store_context *context, const axolotl_pre_key_store *store)
+{
+ if(!store) {
+ return AX_ERR_INVAL;
+ }
+ memcpy(&(context->pre_key_store), store, sizeof(axolotl_pre_key_store));
+ return 0;
+}
+
+int axolotl_store_context_set_signed_pre_key_store(axolotl_store_context *context, const axolotl_signed_pre_key_store *store)
+{
+ if(!store) {
+ return AX_ERR_INVAL;
+ }
+ memcpy(&(context->signed_pre_key_store), store, sizeof(axolotl_signed_pre_key_store));
+ return 0;
+}
+
+int axolotl_store_context_set_identity_key_store(axolotl_store_context *context, const axolotl_identity_key_store *store)
+{
+ if(!store) {
+ return AX_ERR_INVAL;
+ }
+ memcpy(&(context->identity_key_store), store, sizeof(axolotl_identity_key_store));
+ return 0;
+}
+
+int axolotl_store_context_set_sender_key_store(axolotl_store_context *context, const axolotl_sender_key_store *store)
+{
+ if(!store) {
+ return AX_ERR_INVAL;
+ }
+ memcpy(&(context->sender_key_store), store, sizeof(axolotl_sender_key_store));
+ return 0;
+}
+
+void axolotl_store_context_destroy(axolotl_store_context *context)
+{
+ if(context) {
+ if(context->session_store.destroy_func) {
+ context->session_store.destroy_func(context->session_store.user_data);
+ }
+ if(context->pre_key_store.destroy_func) {
+ context->pre_key_store.destroy_func(context->pre_key_store.user_data);
+ }
+ if(context->signed_pre_key_store.destroy_func) {
+ context->signed_pre_key_store.destroy_func(context->signed_pre_key_store.user_data);
+ }
+ if(context->identity_key_store.destroy_func) {
+ context->identity_key_store.destroy_func(context->identity_key_store.user_data);
+ }
+ if(context->sender_key_store.destroy_func) {
+ context->sender_key_store.destroy_func(context->sender_key_store.user_data);
+ }
+ free(context);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+int axolotl_session_load_session(axolotl_store_context *context, session_record **record, const axolotl_address *address)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+ session_record *result_record = 0;
+
+ assert(context);
+ assert(context->session_store.load_session_func);
+
+ result = context->session_store.load_session_func(
+ &buffer, address,
+ context->session_store.user_data);
+ if(result < 0) {
+ goto complete;
+ }
+
+ if(result == 0) {
+ if(buffer) {
+ result = AX_ERR_UNKNOWN;
+ goto complete;
+ }
+ result = session_record_create(&result_record, 0, context->global_context);
+ }
+ else if(result == 1) {
+ if(!buffer) {
+ result = -1;
+ goto complete;
+ }
+ result = session_record_deserialize(&result_record,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer), context->global_context);
+ }
+ else {
+ result = AX_ERR_UNKNOWN;
+ }
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+ if(result >= 0) {
+ *record = result_record;
+ }
+ return result;
+}
+
+int axolotl_session_get_sub_device_sessions(axolotl_store_context *context, axolotl_int_list **sessions, const char *name, size_t name_len)
+{
+ assert(context);
+ assert(context->session_store.get_sub_device_sessions_func);
+
+ return context->session_store.get_sub_device_sessions_func(
+ sessions, name, name_len,
+ context->session_store.user_data);
+}
+
+int axolotl_session_store_session(axolotl_store_context *context, const axolotl_address *address, session_record *record)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+
+ assert(context);
+ assert(context->session_store.store_session_func);
+ assert(record);
+
+ result = session_record_serialize(&buffer, record);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = context->session_store.store_session_func(
+ address,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer),
+ context->session_store.user_data);
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+
+ return result;
+}
+
+int axolotl_session_contains_session(axolotl_store_context *context, const axolotl_address *address)
+{
+ assert(context);
+ assert(context->session_store.contains_session_func);
+
+ return context->session_store.contains_session_func(
+ address,
+ context->session_store.user_data);
+}
+
+int axolotl_session_delete_session(axolotl_store_context *context, const axolotl_address *address)
+{
+ assert(context);
+ assert(context->session_store.delete_session_func);
+
+ return context->session_store.delete_session_func(
+ address,
+ context->session_store.user_data);
+}
+
+int axolotl_session_delete_all_sessions(axolotl_store_context *context, const char *name, size_t name_len)
+{
+ assert(context);
+ assert(context->session_store.delete_all_sessions_func);
+
+ return context->session_store.delete_all_sessions_func(
+ name, name_len,
+ context->session_store.user_data);
+}
+
+/*------------------------------------------------------------------------*/
+
+int axolotl_pre_key_load_key(axolotl_store_context *context, session_pre_key **pre_key, uint32_t pre_key_id)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+ session_pre_key *result_key = 0;
+
+ assert(context);
+ assert(context->pre_key_store.load_pre_key);
+
+ result = context->pre_key_store.load_pre_key(
+ &buffer, pre_key_id,
+ context->pre_key_store.user_data);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = session_pre_key_deserialize(&result_key,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer), context->global_context);
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+ if(result >= 0) {
+ *pre_key = result_key;
+ }
+ return result;
+}
+
+int axolotl_pre_key_store_key(axolotl_store_context *context, session_pre_key *pre_key)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+ uint32_t id = 0;
+
+ assert(context);
+ assert(context->pre_key_store.store_pre_key);
+ assert(pre_key);
+
+ id = session_pre_key_get_id(pre_key);
+
+ result = session_pre_key_serialize(&buffer, pre_key);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = context->pre_key_store.store_pre_key(
+ id,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer),
+ context->pre_key_store.user_data);
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+
+ return result;
+}
+
+int axolotl_pre_key_contains_key(axolotl_store_context *context, uint32_t pre_key_id)
+{
+ int result = 0;
+
+ assert(context);
+ assert(context->pre_key_store.contains_pre_key);
+
+ result = context->pre_key_store.contains_pre_key(
+ pre_key_id, context->pre_key_store.user_data);
+
+ return result;
+}
+
+int axolotl_pre_key_remove_key(axolotl_store_context *context, uint32_t pre_key_id)
+{
+ int result = 0;
+
+ assert(context);
+ assert(context->pre_key_store.remove_pre_key);
+
+ result = context->pre_key_store.remove_pre_key(
+ pre_key_id, context->pre_key_store.user_data);
+
+ return result;
+}
+
+/*------------------------------------------------------------------------*/
+
+int axolotl_signed_pre_key_load_key(axolotl_store_context *context, session_signed_pre_key **pre_key, uint32_t signed_pre_key_id)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+ session_signed_pre_key *result_key = 0;
+
+ assert(context);
+ assert(context->signed_pre_key_store.load_signed_pre_key);
+
+ result = context->signed_pre_key_store.load_signed_pre_key(
+ &buffer, signed_pre_key_id,
+ context->signed_pre_key_store.user_data);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = session_signed_pre_key_deserialize(&result_key,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer), context->global_context);
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+ if(result >= 0) {
+ *pre_key = result_key;
+ }
+ return result;
+}
+
+int axolotl_signed_pre_key_store_key(axolotl_store_context *context, session_signed_pre_key *pre_key)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+ uint32_t id = 0;
+
+ assert(context);
+ assert(context->signed_pre_key_store.store_signed_pre_key);
+ assert(pre_key);
+
+ id = session_signed_pre_key_get_id(pre_key);
+
+ result = session_signed_pre_key_serialize(&buffer, pre_key);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = context->signed_pre_key_store.store_signed_pre_key(
+ id,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer),
+ context->signed_pre_key_store.user_data);
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+
+ return result;
+}
+
+int axolotl_signed_pre_key_contains_key(axolotl_store_context *context, uint32_t signed_pre_key_id)
+{
+ int result = 0;
+
+ assert(context);
+ assert(context->signed_pre_key_store.contains_signed_pre_key);
+
+ result = context->signed_pre_key_store.contains_signed_pre_key(
+ signed_pre_key_id, context->signed_pre_key_store.user_data);
+
+ return result;
+}
+
+int axolotl_signed_pre_key_remove_key(axolotl_store_context *context, uint32_t signed_pre_key_id)
+{
+ int result = 0;
+
+ assert(context);
+ assert(context->signed_pre_key_store.remove_signed_pre_key);
+
+ result = context->signed_pre_key_store.remove_signed_pre_key(
+ signed_pre_key_id, context->signed_pre_key_store.user_data);
+
+ return result;
+}
+
+/*------------------------------------------------------------------------*/
+
+int axolotl_identity_get_key_pair(axolotl_store_context *context, ratchet_identity_key_pair **key_pair)
+{
+ int result = 0;
+ axolotl_buffer *public_buf = 0;
+ axolotl_buffer *private_buf = 0;
+ ec_public_key *public_key = 0;
+ ec_private_key *private_key = 0;
+ ratchet_identity_key_pair *result_key = 0;
+
+ assert(context);
+ assert(context->identity_key_store.get_identity_key_pair);
+
+ result = context->identity_key_store.get_identity_key_pair(
+ &public_buf, &private_buf,
+ context->identity_key_store.user_data);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = curve_decode_point(&public_key, public_buf->data, public_buf->len, context->global_context);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = curve_decode_private_point(&private_key, private_buf->data, private_buf->len, context->global_context);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = ratchet_identity_key_pair_create(&result_key, public_key, private_key);
+ if(result < 0) {
+ goto complete;
+ }
+
+complete:
+ if(public_buf) {
+ axolotl_buffer_free(public_buf);
+ }
+ if(private_buf) {
+ axolotl_buffer_free(private_buf);
+ }
+ if(public_key) {
+ AXOLOTL_UNREF(public_key);
+ }
+ if(private_key) {
+ AXOLOTL_UNREF(private_key);
+ }
+ if(result >= 0) {
+ *key_pair = result_key;
+ }
+ return result;
+}
+
+int axolotl_identity_get_local_registration_id(axolotl_store_context *context, uint32_t *registration_id)
+{
+ int result = 0;
+
+ assert(context);
+ assert(context->identity_key_store.get_local_registration_id);
+
+ result = context->identity_key_store.get_local_registration_id(
+ context->identity_key_store.user_data, registration_id);
+
+ return result;
+}
+
+int axolotl_identity_save_identity(axolotl_store_context *context, const char *name, size_t name_len, ec_public_key *identity_key)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+
+ assert(context);
+ assert(context->identity_key_store.save_identity);
+
+ if(identity_key) {
+ result = ec_public_key_serialize(&buffer, identity_key);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = context->identity_key_store.save_identity(
+ name, name_len,
+ axolotl_buffer_data(buffer),
+ axolotl_buffer_len(buffer),
+ context->identity_key_store.user_data);
+ }
+ else {
+ result = context->identity_key_store.save_identity(
+ name, name_len, 0, 0,
+ context->identity_key_store.user_data);
+ }
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+
+ return result;
+}
+
+int axolotl_identity_is_trusted_identity(axolotl_store_context *context, const char *name, size_t name_len, ec_public_key *identity_key)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+
+ assert(context);
+ assert(context->identity_key_store.is_trusted_identity);
+
+ result = ec_public_key_serialize(&buffer, identity_key);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = context->identity_key_store.is_trusted_identity(
+ name, name_len,
+ axolotl_buffer_data(buffer),
+ axolotl_buffer_len(buffer),
+ context->identity_key_store.user_data);
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+
+ return result;
+}
+
+int axolotl_sender_key_store_key(axolotl_store_context *context, const axolotl_sender_key_name *sender_key_name, sender_key_record *record)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+
+ assert(context);
+ assert(context->sender_key_store.store_sender_key);
+ assert(record);
+
+ result = sender_key_record_serialize(&buffer, record);
+ if(result < 0) {
+ goto complete;
+ }
+
+ result = context->sender_key_store.store_sender_key(
+ sender_key_name,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer),
+ context->sender_key_store.user_data);
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+
+ return result;
+}
+
+int axolotl_sender_key_load_key(axolotl_store_context *context, sender_key_record **record, const axolotl_sender_key_name *sender_key_name)
+{
+ int result = 0;
+ axolotl_buffer *buffer = 0;
+ sender_key_record *result_record = 0;
+
+ assert(context);
+ assert(context->sender_key_store.load_sender_key);
+
+ result = context->sender_key_store.load_sender_key(
+ &buffer, sender_key_name,
+ context->sender_key_store.user_data);
+ if(result < 0) {
+ goto complete;
+ }
+
+ if(result == 0) {
+ if(buffer) {
+ result = AX_ERR_UNKNOWN;
+ goto complete;
+ }
+ result = sender_key_record_create(&result_record, context->global_context);
+ }
+ else if(result == 1) {
+ if(!buffer) {
+ result = -1;
+ goto complete;
+ }
+ result = sender_key_record_deserialize(&result_record,
+ axolotl_buffer_data(buffer), axolotl_buffer_len(buffer), context->global_context);
+ }
+ else {
+ result = AX_ERR_UNKNOWN;
+ }
+
+complete:
+ if(buffer) {
+ axolotl_buffer_free(buffer);
+ }
+ if(result >= 0) {
+ *record = result_record;
+ }
+ return result;
+}