1 /*
2 
3   client_listener.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 2007 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 /* Listener context */
27 struct SilcClientListenerStruct {
28   SilcClient client;			  /* Client */
29   SilcSchedule schedule;		  /* Scheduler */
30   SilcClientConnectCallback callback;	  /* Connection callback */
31   void *context;			  /* User context */
32   SilcClientConnectionParams params;      /* Connection parameters */
33   SilcPublicKey public_key;		  /* Responder public key */
34   SilcPrivateKey private_key;		  /* Responder private key */
35   SilcNetListener tcp_listener;	          /* TCP listener */
36   SilcPacketStream udp_listener;	  /* UDP listener */
37 };
38 
39 /************************ Static utility functions **************************/
40 
41 /* Called after application has verified remote host's public key. */
42 
silc_client_listener_verify_key_cb(SilcBool success,void * context)43 static void silc_client_listener_verify_key_cb(SilcBool success, void *context)
44 {
45   SilcVerifyKeyContext verify = context;
46 
47   /* Call the completion callback back to the SKE */
48   verify->completion(verify->ske, success ? SILC_SKE_STATUS_OK :
49 		     SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
50 		     verify->completion_context);
51 
52   silc_free(verify);
53 }
54 
55 /* Verify remote host's public key. */
56 
57 static void
silc_client_listener_verify_key(SilcSKE ske,SilcPublicKey public_key,void * context,SilcSKEVerifyCbCompletion completion,void * completion_context)58 silc_client_listener_verify_key(SilcSKE ske,
59 				SilcPublicKey public_key,
60 				void *context,
61 				SilcSKEVerifyCbCompletion completion,
62 				void *completion_context)
63 {
64   SilcClientConnection conn = context;
65   SilcClient client = conn->client;
66   SilcVerifyKeyContext verify;
67 
68   /* If we provided repository for SKE and we got here the key was not
69      found from the repository. */
70   if (conn->internal->params.repository &&
71       !conn->internal->params.verify_notfound) {
72     completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
73 	       completion_context);
74     return;
75   }
76 
77   SILC_LOG_DEBUG(("Verify remote public key"));
78 
79   verify = silc_calloc(1, sizeof(*verify));
80   if (!verify) {
81     completion(ske, SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY,
82 	       completion_context);
83     return;
84   }
85   verify->ske = ske;
86   verify->completion = completion;
87   verify->completion_context = completion_context;
88 
89   /* Verify public key in application */
90   client->internal->ops->verify_public_key(client, conn,
91 					   SILC_CONN_CLIENT, public_key,
92 					   silc_client_listener_verify_key_cb,
93 					   verify);
94 }
95 
96 /* Key exchange protocol completion callback. */
97 
silc_client_listener_completion(SilcSKE ske,SilcSKEStatus status,SilcSKESecurityProperties prop,SilcSKEKeyMaterial keymat,SilcSKERekeyMaterial rekey,void * context)98 static void silc_client_listener_completion(SilcSKE ske,
99 					    SilcSKEStatus status,
100 					    SilcSKESecurityProperties prop,
101 					    SilcSKEKeyMaterial keymat,
102 					    SilcSKERekeyMaterial rekey,
103 					    void *context)
104 {
105   SilcClientConnection conn = context;
106   SilcCipher send_key, receive_key;
107   SilcHmac hmac_send, hmac_receive;
108 
109   SILC_LOG_DEBUG(("Key exchange completed"));
110 
111   if (status != SILC_SKE_STATUS_OK) {
112     /* Key exchange failed */
113     conn->callback(conn->client, conn,
114 		   status == SILC_SKE_STATUS_TIMEOUT ?
115 		   SILC_CLIENT_CONN_ERROR_TIMEOUT :
116 		   SILC_CLIENT_CONN_ERROR_KE, conn->internal->error,
117 		   conn->internal->disconnect_message,
118 		   conn->callback_context);
119     return;
120   }
121 
122   /* Allocate the cipher and HMAC contexts */
123   if (!silc_ske_set_keys(ske, keymat, prop, &send_key, &receive_key,
124 			 &hmac_send, &hmac_receive, &conn->internal->hash)) {
125     conn->callback(conn->client, conn,
126 		   SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
127 		   conn->callback_context);
128     return;
129   }
130 
131   /* Set the keys into the packet stream.  After this call packets will be
132      encrypted with these keys. */
133   if (!silc_packet_set_keys(conn->stream, send_key, receive_key, hmac_send,
134 			    hmac_receive, FALSE)) {
135     conn->callback(conn->client, conn,
136 		   SILC_CLIENT_CONN_ERROR_KE, 0, NULL,
137 		   conn->callback_context);
138     return;
139   }
140 
141   /* Key exchange successful */
142   conn->callback(conn->client, conn, SILC_CLIENT_CONN_SUCCESS, 0, NULL,
143 		 conn->callback_context);
144 }
145 
146 /* Starts key agreement as responder. */
147 
148 static void
silc_client_listener_new_connection(SilcClientListener listener,SilcPacketStream stream)149 silc_client_listener_new_connection(SilcClientListener listener,
150 				    SilcPacketStream stream)
151 {
152   SilcClient client = listener->client;
153   SilcClientConnection conn;
154   SilcSKEParamsStruct params = {};
155   const char *hostname = NULL, *ip = NULL;
156   SilcUInt16 port;
157 
158   /* Get remote information */
159   silc_socket_stream_get_info(silc_packet_stream_get_stream(stream),
160 			      NULL, &hostname, &ip, &port);
161   if (!ip || !port) {
162     listener->callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL,
163 		       listener->context);
164     silc_packet_stream_destroy(stream);
165     return;
166   }
167   if (!hostname)
168     hostname = ip;
169 
170   /* Add new connection */
171   conn = silc_client_add_connection(client, SILC_CONN_CLIENT, FALSE,
172 				    &listener->params,
173 				    listener->public_key,
174 				    listener->private_key,
175 				    (char *)hostname, port,
176 				    listener->callback, listener->context);
177   if (!conn) {
178     listener->callback(client, NULL, SILC_CLIENT_CONN_ERROR, 0, NULL,
179 		       listener->context);
180     silc_packet_stream_destroy(stream);
181     return;
182   }
183   conn->stream = stream;
184   conn->internal->schedule = listener->schedule;
185   silc_packet_set_context(conn->stream, conn);
186 
187   SILC_LOG_DEBUG(("Processing new incoming connection %p", conn));
188 
189   /* Allocate SKE */
190   conn->internal->ske =
191     silc_ske_alloc(client->rng, conn->internal->schedule,
192 		   listener->params.repository, listener->public_key,
193 		   listener->private_key, listener);
194   if (!conn->internal->ske) {
195     conn->callback(conn->client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
196 		   conn->callback_context);
197     return;
198   }
199 
200   /* Set SKE parameters */
201   params.version = client->internal->silc_client_version;
202   params.flags = SILC_SKE_SP_FLAG_MUTUAL;
203   if (listener->params.udp) {
204     params.flags |= SILC_SKE_SP_FLAG_IV_INCLUDED;
205     params.session_port = listener->params.local_port;
206   }
207 
208   silc_ske_set_callbacks(conn->internal->ske, silc_client_listener_verify_key,
209 			 silc_client_listener_completion, conn);
210 
211   /* Start key exchange as responder */
212   conn->internal->op = silc_ske_responder(conn->internal->ske,
213 					  conn->stream, &params);
214   if (!conn->internal->op)
215     conn->callback(conn->client, conn, SILC_CLIENT_CONN_ERROR, 0, NULL,
216 		   conn->callback_context);
217 }
218 
219 /* TCP network listener callback.  Accepts new key agreement connection.
220    Responder function. */
221 
silc_client_listener_tcp_accept(SilcNetStatus status,SilcStream stream,void * context)222 static void silc_client_listener_tcp_accept(SilcNetStatus status,
223 					    SilcStream stream,
224 					    void *context)
225 {
226   SilcClientListener listener = context;
227   SilcPacketStream packet_stream;
228 
229   SILC_LOG_DEBUG(("New incoming TCP connection"));
230 
231   /* Create packet stream */
232   packet_stream =
233     silc_packet_stream_create(listener->client->internal->packet_engine,
234 			      listener->schedule, stream);
235   if (!packet_stream) {
236     silc_stream_destroy(stream);
237     return;
238   }
239 
240   /* Process session */
241   silc_client_listener_new_connection(listener, packet_stream);
242 }
243 
244 /* UDP network listener callback.  Accepts new key agreement session.
245    Responder function. */
246 
silc_client_udp_accept(SilcPacketEngine engine,SilcPacketStream stream,SilcPacket packet,void * callback_context,void * stream_context)247 static SilcBool silc_client_udp_accept(SilcPacketEngine engine,
248                                        SilcPacketStream stream,
249                                        SilcPacket packet,
250                                        void *callback_context,
251                                        void *stream_context)
252 {
253   SilcClientListener listener = callback_context;
254   SilcPacketStream packet_stream;
255   SilcUInt16 port;
256   const char *ip;
257 
258   SILC_LOG_DEBUG(("New incoming UDP connection"));
259 
260   /* We want only key exchange packet.  Eat other packets so that default
261      packet callback doesn't get them. */
262   if (packet->type != SILC_PACKET_KEY_EXCHANGE) {
263     silc_packet_free(packet);
264     return TRUE;
265   }
266 
267   /* Create packet stream for this remote UDP session */
268   if (!silc_packet_get_sender(packet, &ip, &port)) {
269     silc_packet_free(packet);
270     return TRUE;
271   }
272   packet_stream = silc_packet_stream_add_remote(stream, ip, port, packet);
273   if (!packet_stream) {
274     silc_packet_free(packet);
275     return TRUE;
276   }
277 
278   /* Process session */
279   silc_client_listener_new_connection(listener, packet_stream);
280   return TRUE;
281 }
282 
283 /* Packet stream callbacks */
284 static SilcPacketCallbacks silc_client_listener_stream_cb =
285 {
286   silc_client_udp_accept, NULL, NULL
287 };
288 
289 /***************************** Listner routines *****************************/
290 
291 /* Adds network listener.  The `callback' will be called after new conection
292    has arrived and key exchange protocol has been completed. */
293 
294 SilcClientListener
silc_client_listener_add(SilcClient client,SilcSchedule schedule,SilcClientConnectionParams * params,SilcPublicKey public_key,SilcPrivateKey private_key,SilcClientConnectCallback callback,void * context)295 silc_client_listener_add(SilcClient client,
296 			 SilcSchedule schedule,
297 			 SilcClientConnectionParams *params,
298 			 SilcPublicKey public_key,
299 			 SilcPrivateKey private_key,
300 			 SilcClientConnectCallback callback,
301 			 void *context)
302 {
303   SilcClientListener listener;
304   SilcStream stream;
305 
306   if (!client || !schedule ||
307       !params || (!params->local_ip && !params->bind_ip))
308     return NULL;
309 
310   SILC_LOG_DEBUG(("Adding new listener"));
311 
312   listener = silc_calloc(1, sizeof(*listener));
313   if (!listener)
314     return NULL;
315   listener->client = client;
316   listener->schedule = schedule;
317   listener->callback = callback;
318   listener->context = context;
319   listener->params = *params;
320   listener->public_key = public_key;
321   listener->private_key = private_key;
322 
323   /* Create network listener */
324   if (params->udp) {
325     /* UDP listener */
326     stream = silc_net_udp_connect(params->bind_ip ? params->bind_ip :
327 				  params->local_ip, params->local_port,
328 				  NULL, 0, schedule);
329     listener->udp_listener =
330       silc_packet_stream_create(client->internal->packet_engine,
331 				schedule, stream);
332     if (!listener->udp_listener) {
333       client->internal->ops->say(
334 		     client, NULL, SILC_CLIENT_MESSAGE_ERROR,
335 		     "Cannot create UDP listener on %s on port %d: %s",
336 		     params->bind_ip ? params->bind_ip :
337 		     params->local_ip, params->local_port, strerror(errno));
338       silc_client_listener_free(listener);
339       if (stream)
340 	silc_stream_destroy(stream);
341       return NULL;
342     }
343     silc_packet_stream_link(listener->udp_listener,
344 			    &silc_client_listener_stream_cb, listener,
345 			    1000000, SILC_PACKET_ANY, -1);
346 
347     if (!params->local_port) {
348       /* Get listener port */
349       SilcSocket sock;
350       silc_socket_stream_get_info(stream, &sock, NULL, NULL, NULL);
351       listener->params.local_port = silc_net_get_local_port(sock);
352     }
353   } else {
354     /* TCP listener */
355     listener->tcp_listener =
356       silc_net_tcp_create_listener(params->bind_ip ?
357 				   (const char **)&params->bind_ip :
358 				   (const char **)&params->local_ip,
359 				   1, params->local_port, TRUE, FALSE,
360 				   schedule, silc_client_listener_tcp_accept,
361 				   listener);
362     if (!listener->tcp_listener) {
363       client->internal->ops->say(
364 		     client, NULL, SILC_CLIENT_MESSAGE_ERROR,
365 		     "Cannot create listener on %s on port %d: %s",
366 		     params->bind_ip ? params->bind_ip :
367 		     params->local_ip, params->local_port, strerror(errno));
368 
369       silc_client_listener_free(listener);
370       return NULL;
371     }
372 
373     if (!params->local_port) {
374       /* Get listener port */
375       SilcUInt16 *ports;
376       ports = silc_net_listener_get_port(listener->tcp_listener, NULL);
377       listener->params.local_port = ports[0];
378       silc_free(ports);
379     }
380   }
381 
382   SILC_LOG_DEBUG(("Bound listener to %s:%d",
383 		  params->bind_ip ? params->bind_ip : params->local_ip,
384 		  listener->params.local_port));
385 
386   return listener;
387 }
388 
389 /* Close and free listner */
390 
silc_client_listener_free(SilcClientListener listener)391 void silc_client_listener_free(SilcClientListener listener)
392 {
393   if (listener->tcp_listener)
394     silc_net_close_listener(listener->tcp_listener);
395   silc_packet_stream_destroy(listener->udp_listener);
396   silc_free(listener);
397 }
398 
399 /* Return listner bound port */
400 
silc_client_listener_get_local_port(SilcClientListener listener)401 SilcUInt16 silc_client_listener_get_local_port(SilcClientListener listener)
402 {
403   return listener->params.local_port;
404 }
405