1 #include "group_session_builder.h"
2 
3 #include <assert.h>
4 #include <string.h>
5 #include "sender_key_record.h"
6 #include "sender_key_state.h"
7 #include "sender_key.h"
8 #include "protocol.h"
9 #include "key_helper.h"
10 #include "signal_protocol_internal.h"
11 
12 struct group_session_builder
13 {
14     signal_protocol_store_context *store;
15     signal_context *global_context;
16 };
17 
group_session_builder_create(group_session_builder ** builder,signal_protocol_store_context * store,signal_context * global_context)18 int group_session_builder_create(group_session_builder **builder,
19         signal_protocol_store_context *store, signal_context *global_context)
20 {
21     group_session_builder *result = 0;
22 
23     assert(store);
24     assert(global_context);
25 
26     result = malloc(sizeof(group_session_builder));
27     if(!result) {
28         return SG_ERR_NOMEM;
29     }
30     memset(result, 0, sizeof(group_session_builder));
31 
32     result->store = store;
33     result->global_context = global_context;
34 
35     *builder = result;
36     return 0;
37 }
38 
group_session_builder_process_session(group_session_builder * builder,const signal_protocol_sender_key_name * sender_key_name,sender_key_distribution_message * distribution_message)39 int group_session_builder_process_session(group_session_builder *builder,
40         const signal_protocol_sender_key_name *sender_key_name,
41         sender_key_distribution_message *distribution_message)
42 {
43     int result = 0;
44     sender_key_record *record = 0;
45 
46     assert(builder);
47     assert(builder->store);
48     signal_lock(builder->global_context);
49 
50     result = signal_protocol_sender_key_load_key(builder->store, &record, sender_key_name);
51     if(result < 0) {
52         goto complete;
53     }
54 
55     result = sender_key_record_add_sender_key_state(record,
56             sender_key_distribution_message_get_id(distribution_message),
57             sender_key_distribution_message_get_iteration(distribution_message),
58             sender_key_distribution_message_get_chain_key(distribution_message),
59             sender_key_distribution_message_get_signature_key(distribution_message));
60     if(result < 0) {
61         goto complete;
62     }
63 
64     result = signal_protocol_sender_key_store_key(builder->store, sender_key_name, record);
65 
66 complete:
67     SIGNAL_UNREF(record);
68     signal_unlock(builder->global_context);
69     return result;
70 }
71 
group_session_builder_create_session(group_session_builder * builder,sender_key_distribution_message ** distribution_message,const signal_protocol_sender_key_name * sender_key_name)72 int group_session_builder_create_session(group_session_builder *builder,
73         sender_key_distribution_message **distribution_message,
74         const signal_protocol_sender_key_name *sender_key_name)
75 {
76     int result = 0;
77     sender_key_record *record = 0;
78     sender_key_state *state = 0;
79     uint32_t sender_key_id = 0;
80     signal_buffer *sender_key = 0;
81     ec_key_pair *sender_signing_key = 0;
82     sender_chain_key *chain_key = 0;
83     signal_buffer *seed = 0;
84 
85     assert(builder);
86     assert(builder->store);
87     signal_lock(builder->global_context);
88 
89     result = signal_protocol_sender_key_load_key(builder->store, &record, sender_key_name);
90     if(result < 0) {
91         goto complete;
92     }
93 
94     if(sender_key_record_is_empty(record)) {
95         result = signal_protocol_key_helper_generate_sender_key_id(&sender_key_id, builder->global_context);
96         if(result < 0) {
97             goto complete;
98         }
99 
100         result = signal_protocol_key_helper_generate_sender_key(&sender_key, builder->global_context);
101         if(result < 0) {
102             goto complete;
103         }
104 
105         result = signal_protocol_key_helper_generate_sender_signing_key(&sender_signing_key, builder->global_context);
106         if(result < 0) {
107             goto complete;
108         }
109 
110         result = sender_key_record_set_sender_key_state(record, sender_key_id, 0, sender_key, sender_signing_key);
111         if(result < 0) {
112             goto complete;
113         }
114 
115         result = signal_protocol_sender_key_store_key(builder->store, sender_key_name, record);
116         if(result < 0) {
117             goto complete;
118         }
119     }
120 
121     result = sender_key_record_get_sender_key_state(record, &state);
122     if(result < 0) {
123         goto complete;
124     }
125 
126     chain_key = sender_key_state_get_chain_key(state);
127     seed = sender_chain_key_get_seed(chain_key);
128 
129     result = sender_key_distribution_message_create(distribution_message,
130             sender_key_state_get_key_id(state),
131             sender_chain_key_get_iteration(chain_key),
132             signal_buffer_data(seed), signal_buffer_len(seed),
133             sender_key_state_get_signing_key_public(state),
134             builder->global_context);
135 
136 complete:
137     signal_buffer_free(sender_key);
138     SIGNAL_UNREF(sender_signing_key);
139     SIGNAL_UNREF(record);
140     signal_unlock(builder->global_context);
141     return result;
142 }
143 
group_session_builder_free(group_session_builder * builder)144 void group_session_builder_free(group_session_builder *builder)
145 {
146     if(builder) {
147         free(builder);
148     }
149 }
150