1 /*
2 
3   client_keyagr.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 2001 - 2014 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
17 
18 */
19 
20 #include "silc.h"
21 #include "silcclient.h"
22 #include "client_internal.h"
23 
24 /************************** Types and definitions ***************************/
25 
26 /* Key agreement context, used by responder */
27 struct SilcClientKeyAgreementStruct {
28   SilcClient client;			  /* Client */
29   SilcClientConnection conn;		  /* Server connection */
30   SilcClientListener listener;	          /* Listener */
31   SilcKeyAgreementCallback completion;	  /* Key agreement completion */
32   void *context;			  /* User context */
33 };
34 
35 /************************ Static utility functions **************************/
36 
37 /* Destroyes key agreement session */
38 
silc_client_keyagr_free(SilcClient client,SilcClientConnection conn,SilcClientEntry client_entry)39 static void silc_client_keyagr_free(SilcClient client,
40 				    SilcClientConnection conn,
41 				    SilcClientEntry client_entry)
42 {
43   SilcClientKeyAgreement ke = client_entry->internal.ke;
44 
45   silc_client_listener_free(ke->listener);
46   silc_schedule_task_del_by_context(conn->internal->schedule, client_entry);
47   if (client_entry->internal.op)
48     silc_async_abort(client_entry->internal.op, NULL, NULL);
49   client_entry->internal.op = NULL;
50   client_entry->internal.ke = NULL;
51   client_entry->internal.prv_resp = FALSE;
52   silc_client_unref_client(client, conn, client_entry);
53   silc_free(ke);
54 }
55 
56 /* Key agreement timeout callback */
57 
SILC_TASK_CALLBACK(silc_client_keyagr_timeout)58 SILC_TASK_CALLBACK(silc_client_keyagr_timeout)
59 {
60   SilcClientEntry client_entry = context;
61   SilcClientKeyAgreement ke = client_entry->internal.ke;
62 
63   if (!ke)
64     return;
65 
66   SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
67 
68   ke->completion(ke->client, ke->conn, client_entry,
69 		 SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
70 
71   silc_client_keyagr_free(ke->client, ke->conn, client_entry);
72 }
73 
74 /* Client resolving callback.  Continues with the key agreement processing */
75 
silc_client_keyagr_resolved(SilcClient client,SilcClientConnection conn,SilcStatus status,SilcDList clients,void * context)76 static void silc_client_keyagr_resolved(SilcClient client,
77 					SilcClientConnection conn,
78 					SilcStatus status,
79 					SilcDList clients,
80 					void *context)
81 {
82   /* If no client found, ignore the packet, a silent error */
83   if (!clients)
84     silc_fsm_next(context, silc_client_key_agreement_error);
85 
86   /* Continue processing the packet */
87   SILC_FSM_CALL_CONTINUE(context);
88 }
89 
90 /* Key exchange completion callback.  Called after connected to remote host
91    and performed key exchange, when we are initiator.  As responder, this is
92    called after the remote has connected to us and have performed the key
93    exchange. */
94 
silc_client_keyagr_completion(SilcClient client,SilcClientConnection conn,SilcClientConnectionStatus status,SilcStatus error,const char * message,void * context)95 static void silc_client_keyagr_completion(SilcClient client,
96 					  SilcClientConnection conn,
97 					  SilcClientConnectionStatus status,
98 					  SilcStatus error,
99 					  const char *message,
100 					  void *context)
101 {
102   SilcClientEntry client_entry = context;
103   SilcClientKeyAgreement ke = client_entry->internal.ke;
104   SilcSKEKeyMaterial keymat;
105 
106   client_entry->internal.op = NULL;
107 
108   switch (status) {
109   case SILC_CLIENT_CONN_SUCCESS:
110     SILC_LOG_DEBUG(("Key agreement %p successful", ke));
111 
112     keymat = silc_ske_get_key_material(conn->internal->ske);
113     ke->completion(ke->client, ke->conn, client_entry, SILC_KEY_AGREEMENT_OK,
114 		   keymat, ke->context);
115     break;
116 
117   case SILC_CLIENT_CONN_ERROR_TIMEOUT:
118     SILC_LOG_DEBUG(("Key agreement %p timeout", ke));
119     ke->completion(ke->client, ke->conn, client_entry,
120 		   SILC_KEY_AGREEMENT_TIMEOUT, NULL, ke->context);
121     break;
122 
123   default:
124     SILC_LOG_DEBUG(("Key agreement %p error %d", ke, status));
125     ke->completion(ke->client, ke->conn, client_entry,
126 		   SILC_KEY_AGREEMENT_FAILURE, NULL, ke->context);
127     break;
128   }
129 
130   /* Close the connection */
131   if (conn)
132     silc_client_close_connection(ke->client, conn);
133 
134   silc_client_keyagr_free(ke->client, ke->conn, client_entry);
135 }
136 
137 /*************************** Key Agreement API ******************************/
138 
139 /* Sends key agreement packet to remote client.  If IP addresses are provided
140    creates also listener for �ncoming key agreement connection.  Supports
141    both TCP and UDP transports. */
142 
silc_client_send_key_agreement(SilcClient client,SilcClientConnection conn,SilcClientEntry client_entry,SilcClientConnectionParams * params,SilcPublicKey public_key,SilcPrivateKey private_key,SilcKeyAgreementCallback completion,void * context)143 void silc_client_send_key_agreement(SilcClient client,
144 				    SilcClientConnection conn,
145 				    SilcClientEntry client_entry,
146 				    SilcClientConnectionParams *params,
147 				    SilcPublicKey public_key,
148 				    SilcPrivateKey private_key,
149 				    SilcKeyAgreementCallback completion,
150 				    void *context)
151 {
152   SilcClientKeyAgreement ke = NULL;
153   SilcBuffer buffer;
154   SilcUInt16 port = 0, protocol = 0;
155   char *local_ip = NULL;
156 
157   SILC_LOG_DEBUG(("Sending key agreement"));
158 
159   if (!client_entry)
160     return;
161   if (conn->internal->disconnected)
162     return;
163 
164   if (client_entry->internal.ke) {
165     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ALREADY_STARTED,
166 	       NULL, context);
167     return;
168   }
169 
170   if (client_entry == conn->local_entry) {
171     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
172 	       NULL, context);
173     return;
174   }
175 
176   /* If local IP is provided, create listener.  If this is not provided,
177      we'll just send empty key agreement payload */
178   if (params && (params->local_ip || params->bind_ip)) {
179     ke = silc_calloc(1, sizeof(*ke));
180     if (!ke) {
181       completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
182 		 NULL, context);
183       return;
184     }
185 
186     /* Create listener */
187     ke->listener = silc_client_listener_add(client, conn->internal->schedule,
188 					    params, public_key, private_key,
189 					    silc_client_keyagr_completion,
190 					    client_entry);
191     if (!ke->listener) {
192       completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
193 		 NULL, context);
194       return;
195     }
196 
197     local_ip = params->local_ip;
198     protocol = params->udp;
199 
200     ke->client = client;
201     ke->conn = conn;
202     ke->completion = completion;
203     ke->context = context;
204     silc_client_ref_client(client, conn, client_entry);
205     client_entry->internal.ke = ke;
206     client_entry->internal.prv_resp = TRUE;
207   }
208 
209   /* Encode the key agreement payload */
210   buffer = silc_key_agreement_payload_encode(local_ip, protocol, port);
211   if (!buffer) {
212     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
213 	       NULL, context);
214     silc_client_keyagr_free(client, conn, client_entry);
215     return;
216   }
217 
218   /* Send the key agreement packet to the client */
219   if (!silc_packet_send_ext(conn->stream, SILC_PACKET_KEY_AGREEMENT, 0,
220 			    0, NULL, SILC_ID_CLIENT, &client_entry->id,
221 			    silc_buffer_datalen(buffer), NULL, NULL)) {
222     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
223 	       NULL, context);
224     silc_client_keyagr_free(client, conn, client_entry);
225     silc_buffer_free(buffer);
226     return;
227   }
228 
229   /* Add key agreement timeout task */
230   if (params && params->timeout_secs)
231     silc_schedule_task_add_timeout(conn->internal->schedule,
232 				   silc_client_keyagr_timeout,
233 				   client_entry, params->timeout_secs, 0);
234 
235   silc_buffer_free(buffer);
236 }
237 
238 /* Perform key agreement protocol as initiator.  Conneects to remote host. */
239 
silc_client_perform_key_agreement(SilcClient client,SilcClientConnection conn,SilcClientEntry client_entry,SilcClientConnectionParams * params,SilcPublicKey public_key,SilcPrivateKey private_key,char * hostname,int port,SilcKeyAgreementCallback completion,void * context)240 void silc_client_perform_key_agreement(SilcClient client,
241 				       SilcClientConnection conn,
242 				       SilcClientEntry client_entry,
243 				       SilcClientConnectionParams *params,
244 				       SilcPublicKey public_key,
245 				       SilcPrivateKey private_key,
246 				       char *hostname, int port,
247 				       SilcKeyAgreementCallback completion,
248 				       void *context)
249 {
250   SilcClientKeyAgreement ke;
251 
252   SILC_LOG_DEBUG(("Performing key agreement"));
253 
254   if (!client_entry || !hostname || !port) {
255     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
256 	       NULL, context);
257     return;
258   }
259 
260   if (client_entry == conn->local_entry) {
261     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
262 	       NULL, context);
263     return;
264   }
265 
266   ke = silc_calloc(1, sizeof(*ke));
267   if (!ke) {
268     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
269 	       NULL, context);
270     return;
271   }
272   ke->client = client;
273   ke->conn = conn;
274   ke->completion = completion;
275   ke->context = context;
276   silc_client_ref_client(client, conn, client_entry);
277   client_entry->internal.ke = ke;
278 
279   if (params)
280     params->no_authentication = TRUE;
281 
282   /* Connect to the remote client.  Performs key exchange automatically. */
283   client_entry->internal.op =
284     silc_client_connect_to_client(client, params, public_key,
285 				  private_key, hostname, port,
286 				  silc_client_keyagr_completion,
287 				  client_entry);
288   if (!client_entry->internal.op) {
289     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
290 	       NULL, context);
291     silc_client_keyagr_free(client, conn, client_entry);
292     return;
293   }
294 }
295 
296 /* Same as above but caller has created connection. */
297 
298 void
silc_client_perform_key_agreement_stream(SilcClient client,SilcClientConnection conn,SilcClientEntry client_entry,SilcClientConnectionParams * params,SilcPublicKey public_key,SilcPrivateKey private_key,SilcStream stream,SilcKeyAgreementCallback completion,void * context)299 silc_client_perform_key_agreement_stream(SilcClient client,
300 					 SilcClientConnection conn,
301 					 SilcClientEntry client_entry,
302 					 SilcClientConnectionParams *params,
303 					 SilcPublicKey public_key,
304 					 SilcPrivateKey private_key,
305 					 SilcStream stream,
306 					 SilcKeyAgreementCallback completion,
307 					 void *context)
308 {
309   SilcClientKeyAgreement ke;
310 
311   SILC_LOG_DEBUG(("Performing key agreement"));
312 
313   if (!client_entry || !stream) {
314     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
315 	       NULL, context);
316     return;
317   }
318 
319   if (client_entry == conn->local_entry) {
320     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_SELF_DENIED,
321 	       NULL, context);
322     return;
323   }
324 
325   ke = silc_calloc(1, sizeof(*ke));
326   if (!ke) {
327     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_NO_MEMORY,
328 	       NULL, context);
329     return;
330   }
331   ke->client = client;
332   ke->conn = conn;
333   ke->completion = completion;
334   ke->context = context;
335   silc_client_ref_client(client, conn, client_entry);
336   client_entry->internal.ke = ke;
337 
338   if (params)
339     params->no_authentication = TRUE;
340 
341   /* Perform key exchange protocol */
342   client_entry->internal.op =
343     silc_client_key_exchange(client, params, public_key,
344 			     private_key, stream, SILC_CONN_CLIENT,
345 			     silc_client_keyagr_completion,
346 			     client_entry);
347   if (!client_entry->internal.op) {
348     completion(client, conn, client_entry, SILC_KEY_AGREEMENT_ERROR,
349 	       NULL, context);
350     silc_client_keyagr_free(client, conn, client_entry);
351     return;
352   }
353 }
354 
355 /* This function can be called to unbind the hostname and the port for
356    the key agreement protocol. However, this function has effect only
357    before the key agreement protocol has been performed. After it has
358    been performed the library will automatically unbind the port. The
359    `client_entry' is the client to which we sent the key agreement
360    request. */
361 
silc_client_abort_key_agreement(SilcClient client,SilcClientConnection conn,SilcClientEntry client_entry)362 void silc_client_abort_key_agreement(SilcClient client,
363 				     SilcClientConnection conn,
364 				     SilcClientEntry client_entry)
365 {
366   SilcClientKeyAgreement ke;
367 
368   if (!client_entry || !client_entry->internal.ke)
369     return;
370 
371   ke = client_entry->internal.ke;
372 
373   SILC_LOG_DEBUG(("Abort key agreement ke %p for client %p on connection %p",
374                   ke, client, conn));
375 
376   ke->completion(client, conn, client_entry,
377 		 SILC_KEY_AGREEMENT_ABORTED, NULL, ke->context);
378 
379   silc_client_keyagr_free(client, conn, client_entry);
380 }
381 
382 /* Key agreement packet received */
383 
SILC_FSM_STATE(silc_client_key_agreement)384 SILC_FSM_STATE(silc_client_key_agreement)
385 {
386   SilcClientConnection conn = fsm_context;
387   SilcClient client = conn->client;
388   SilcPacket packet = state_context;
389   SilcClientID remote_id;
390   SilcClientEntry remote_client;
391   SilcKeyAgreementPayload payload;
392 
393   if (packet->src_id_type != SILC_ID_CLIENT) {
394     /** Invalid packet */
395     silc_fsm_next(fsm, silc_client_key_agreement_error);
396     return SILC_FSM_CONTINUE;
397   }
398 
399   if (!silc_id_str2id(packet->src_id, packet->src_id_len, SILC_ID_CLIENT,
400 		      &remote_id, sizeof(remote_id))) {
401     /** Invalid source ID */
402     silc_fsm_next(fsm, silc_client_key_agreement_error);
403     return SILC_FSM_CONTINUE;
404   }
405 
406   /* Check whether we know this client already */
407   remote_client = silc_client_get_client_by_id(client, conn, &remote_id);
408   if (!remote_client || !remote_client->internal.valid) {
409     /** Resolve client info */
410     silc_client_unref_client(client, conn, remote_client);
411     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
412 					 client, conn, &remote_id, NULL,
413 					 silc_client_keyagr_resolved, fsm));
414     /* NOT REACHED */
415   }
416 
417   /* Parse the key agreement payload */
418   payload = silc_key_agreement_payload_parse(silc_buffer_data(&packet->buffer),
419 					     silc_buffer_len(&packet->buffer));
420   if (!payload) {
421     /** Malformed Payload */
422     SILC_LOG_DEBUG(("Malformed key agreement payload"));
423     silc_fsm_next(fsm, silc_client_key_agreement_error);
424     return SILC_FSM_CONTINUE;
425   }
426 
427   /* If remote did not provide connection endpoint, we will assume that we
428      will provide it and will be responder. */
429   if (!silc_key_agreement_get_hostname(payload))
430     remote_client->internal.prv_resp = TRUE;
431   else
432     remote_client->internal.prv_resp = FALSE;
433 
434   /* Notify application for key agreement request */
435   client->internal->ops->key_agreement(
436 				   client, conn, remote_client,
437 				   silc_key_agreement_get_hostname(payload),
438 				   silc_key_agreement_get_protocol(payload),
439 				   silc_key_agreement_get_port(payload));
440 
441   silc_key_agreement_payload_free(payload);
442 
443   silc_packet_free(packet);
444   return SILC_FSM_FINISH;
445 }
446 
447 /* Key agreement packet processing error */
448 
SILC_FSM_STATE(silc_client_key_agreement_error)449 SILC_FSM_STATE(silc_client_key_agreement_error)
450 {
451   SilcPacket packet = state_context;
452   silc_packet_free(packet);
453   return SILC_FSM_FINISH;
454 }
455