SILC FSM API changes.
[silc.git] / lib / silcske / silcconnauth.c
1 /*
2
3   silcconnauth.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2005 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19
20 #include "silc.h"
21 #include "silcconnauth.h"
22
23 /************************** Types and definitions ***************************/
24
25 static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine,
26                                              SilcPacketStream stream,
27                                              SilcPacket packet,
28                                              void *callback_context,
29                                              void *app_context);
30
31 /* Connection authentication context */
32 struct SilcConnAuthStruct {
33   SilcSKE ske;
34   SilcFSM fsm;
35   SilcConnectionType conn_type;
36   SilcAuthMethod auth_method;
37   void *auth_data;
38   SilcUInt32 auth_data_len;
39   SilcConnAuthCompletion completion;
40   SilcConnAuthGetAuthData get_auth_data;
41   void *context;
42   SilcDList public_keys;
43   SilcSKRStatus skr_status;
44   SilcUInt32 timeout_secs;
45   SilcPacket packet;
46   unsigned int aborted   : 1;
47   unsigned int success   : 1;
48 };
49
50 /* Packet stream callbacks */
51 static SilcPacketCallbacks silc_connauth_stream_cbs =
52 {
53   silc_connauth_packet_receive, NULL, NULL
54 };
55
56
57 /************************ Static utility functions **************************/
58
59 /* Packet callback */
60
61 static SilcBool silc_connauth_packet_receive(SilcPacketEngine engine,
62                                              SilcPacketStream stream,
63                                              SilcPacket packet,
64                                              void *callback_context,
65                                              void *app_context)
66 {
67   SilcConnAuth connauth = callback_context;
68   connauth->packet = packet;
69   silc_fsm_continue(connauth->fsm);
70   return TRUE;
71 }
72
73 /* Async operation abortion callback */
74
75 static void silc_connauth_abort(SilcAsyncOperation op, void *context)
76 {
77   SilcConnAuth connauth = context;
78   connauth->aborted = TRUE;
79 }
80
81 /* Generates signature for public key based authentication */
82
83 static SilcBool silc_connauth_get_signature(SilcConnAuth connauth,
84                                             unsigned char **auth_data,
85                                             SilcUInt32 *auth_data_len)
86 {
87   int len;
88   SilcSKE ske;
89   SilcPrivateKey private_key;
90   SilcBuffer auth;
91
92   SILC_LOG_DEBUG(("Compute signature"));
93
94   ske = connauth->ske;
95   private_key = connauth->auth_data;
96
97   /* Make the authentication data. Protocol says it is HASH plus
98      KE Start Payload. */
99   len = ske->hash_len + silc_buffer_len(ske->start_payload_copy);
100   auth = silc_buffer_alloc_size(len);
101   if (!auth)
102     return FALSE;
103   silc_buffer_format(auth,
104                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
105                      SILC_STR_UI_XNSTRING(
106                                ske->start_payload_copy->data,
107                                silc_buffer_len(ske->start_payload_copy)),
108                      SILC_STR_END);
109
110   len = ((silc_pkcs_private_key_get_len(private_key) + 7) / 8) + 1;
111   *auth_data = silc_calloc(len, sizeof(**auth_data));
112   if (*auth_data == NULL) {
113     silc_buffer_free(auth);
114     return FALSE;
115   }
116
117   /* Compute signature */
118   if (!silc_pkcs_sign(private_key, auth->data, silc_buffer_len(auth),
119                       *auth_data, len, auth_data_len, ske->prop->hash)) {
120     silc_free(*auth_data);
121     silc_buffer_free(auth);
122     return FALSE;
123   }
124
125   silc_buffer_free(auth);
126   return TRUE;
127 }
128
129 /* Verifies digital signature */
130
131 static SilcBool silc_connauth_verify_signature(SilcConnAuth connauth,
132                                                SilcPublicKey pub_key,
133                                                unsigned char *sign,
134                                                SilcUInt32 sign_len)
135 {
136   int len;
137   SilcBuffer auth;
138   SilcSKE ske = connauth->ske;
139
140   if (!pub_key || !sign)
141     return FALSE;
142
143   /* Make the authentication data. Protocol says it is HASH plus
144      KE Start Payload. */
145   len = ske->hash_len + silc_buffer_len(ske->start_payload_copy);
146   auth = silc_buffer_alloc_size(len);
147   if (!auth)
148     return FALSE;
149   silc_buffer_format(auth,
150                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
151                      SILC_STR_UI_XNSTRING(
152                                   ske->start_payload_copy->data,
153                                   silc_buffer_len(ske->start_payload_copy)),
154                      SILC_STR_END);
155
156   /* Verify signature */
157   if (!silc_pkcs_verify(pub_key, sign, sign_len, auth->data,
158                         silc_buffer_len(auth), ske->prop->hash)) {
159     silc_buffer_free(auth);
160     return FALSE;
161   }
162
163   silc_buffer_free(auth);
164
165   return TRUE;
166 }
167
168 /* Timeout */
169
170 SILC_TASK_CALLBACK(silc_connauth_timeout)
171 {
172   SilcConnAuth connauth = context;
173   SILC_LOG_DEBUG(("Protocol timeout"));
174   connauth->aborted = TRUE;
175   silc_fsm_continue_sync(connauth->fsm);
176 }
177
178 /* SKR callback */
179
180 static void silc_connauth_skr_callback(SilcSKR skr, SilcSKRFind find,
181                                        SilcSKRStatus status,
182                                        SilcDList results, void *context)
183 {
184   SilcConnAuth connauth = context;
185
186   silc_skr_find_free(find);
187
188   connauth->public_keys = results;
189   connauth->skr_status = status;
190
191   SILC_FSM_CALL_CONTINUE(connauth->fsm);
192 }
193
194 /* FSM destructor */
195
196 static void silc_connauth_fsm_destructor(SilcFSM fsm, void *fsm_context,
197                                          void *destructor_context)
198 {
199   silc_fsm_free(fsm);
200 }
201
202
203 /******************************* Protocol API *******************************/
204
205 /* Allocate connection authentication context */
206
207 SilcConnAuth silc_connauth_alloc(SilcSchedule schedule,
208                                  SilcSKE ske,
209                                  SilcUInt32 timeout_secs)
210 {
211   SilcConnAuth connauth;
212
213   if (!schedule || !ske)
214     return NULL;
215
216   connauth = silc_calloc(1, sizeof(*connauth));
217   if (!connauth)
218     return NULL;
219
220   connauth->fsm = silc_fsm_alloc(connauth, silc_connauth_fsm_destructor,
221                                  NULL, schedule);
222   if (!connauth->fsm) {
223     silc_connauth_free(connauth);
224     return NULL;
225   }
226
227   connauth->timeout_secs = timeout_secs;
228   connauth->ske = ske;
229
230   return connauth;
231 }
232
233 /* Free connection authentication context */
234
235 void silc_connauth_free(SilcConnAuth connauth)
236 {
237   if (connauth->public_keys)
238     silc_dlist_uninit(connauth->public_keys);
239   silc_free(connauth);
240 }
241
242 /* Return associated SKE context */
243
244 SilcSKE silc_connauth_get_ske(SilcConnAuth connauth)
245 {
246   return connauth->ske;
247 }
248
249
250 /******************************** Initiator *********************************/
251
252 SILC_FSM_STATE(silc_connauth_st_initiator_start);
253 SILC_FSM_STATE(silc_connauth_st_initiator_result);
254 SILC_FSM_STATE(silc_connauth_st_initiator_failure);
255
256 SILC_FSM_STATE(silc_connauth_st_initiator_start)
257 {
258   SilcConnAuth connauth = fsm_context;
259   SilcBuffer packet;
260   int payload_len = 0;
261   unsigned char *auth_data = NULL;
262   SilcUInt32 auth_data_len = 0;
263   SilcPacketFlags flags = 0;
264
265   SILC_LOG_DEBUG(("Start"));
266
267   if (connauth->aborted) {
268     /** Aborted */
269     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
270     SILC_FSM_CONTINUE;
271   }
272
273   /* Start timeout */
274   if (connauth->timeout_secs)
275     silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
276                                    silc_connauth_timeout, connauth,
277                                    connauth->timeout_secs, 0);
278
279   switch (connauth->auth_method) {
280   case SILC_AUTH_NONE:
281     /* No authentication required */
282     break;
283
284   case SILC_AUTH_PASSWORD:
285     auth_data = silc_memdup(connauth->auth_data, connauth->auth_data_len);
286     if (!auth_data) {
287       /** Out of memory */
288       silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
289       SILC_FSM_CONTINUE;
290     }
291     auth_data_len = connauth->auth_data_len;
292     flags = SILC_PACKET_FLAG_LONG_PAD;
293     break;
294
295   case SILC_AUTH_PUBLIC_KEY:
296     if (!silc_connauth_get_signature(connauth, &auth_data, &auth_data_len)) {
297       /** Error computing signature */
298       silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
299       SILC_FSM_CONTINUE;
300     }
301     break;
302   }
303
304   payload_len = 4 + auth_data_len;
305   packet = silc_buffer_alloc_size(payload_len);
306   if (!packet) {
307     /** Out of memory */
308     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
309     SILC_FSM_CONTINUE;
310   }
311
312   silc_buffer_format(packet,
313                      SILC_STR_UI_SHORT(payload_len),
314                      SILC_STR_UI_SHORT(connauth->conn_type),
315                      SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
316                      SILC_STR_END);
317
318   /* Send the packet */
319   if (!silc_packet_send(connauth->ske->stream, SILC_PACKET_CONNECTION_AUTH,
320                         flags, packet->data, silc_buffer_len(packet))) {
321     /** Error sending packet */
322     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
323     SILC_FSM_CONTINUE;
324   }
325
326   if (auth_data) {
327     memset(auth_data, 0, auth_data_len);
328     silc_free(auth_data);
329   }
330   silc_buffer_free(packet);
331
332   /** Wait for responder */
333   silc_fsm_next(fsm, silc_connauth_st_initiator_result);
334   SILC_FSM_WAIT;
335 }
336
337 SILC_FSM_STATE(silc_connauth_st_initiator_result)
338 {
339   SilcConnAuth connauth = fsm_context;
340
341   SILC_LOG_DEBUG(("Start"));
342
343   if (connauth->aborted) {
344     /** Aborted */
345     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
346     SILC_FSM_CONTINUE;
347   }
348
349   /* Check the status of authentication */
350   if (connauth->packet->type == SILC_PACKET_SUCCESS) {
351     SILC_LOG_DEBUG(("Authentication successful"));
352     connauth->success = TRUE;
353   } else {
354     SILC_LOG_DEBUG(("Authentication failed"));
355     connauth->success = FALSE;
356   }
357   silc_packet_free(connauth->packet);
358
359   silc_packet_stream_unlink(connauth->ske->stream,
360                             &silc_connauth_stream_cbs, connauth);
361   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
362
363   /* Call completion callback */
364   connauth->completion(connauth, connauth->success, connauth->context);
365
366   SILC_FSM_FINISH;
367 }
368
369 SILC_FSM_STATE(silc_connauth_st_initiator_failure)
370 {
371   SilcConnAuth connauth = fsm_context;
372   unsigned char error[4];
373
374   SILC_LOG_DEBUG(("Start"));
375
376   /* Send FAILURE packet */
377   SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
378   silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
379
380   /* Call completion callback */
381   connauth->completion(connauth, FALSE, connauth->context);
382
383   silc_packet_stream_unlink(connauth->ske->stream,
384                             &silc_connauth_stream_cbs, connauth);
385   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
386
387   SILC_FSM_FINISH;
388 }
389
390 SilcAsyncOperation
391 silc_connauth_initiator(SilcConnAuth connauth,
392                         SilcConnectionType conn_type,
393                         SilcAuthMethod auth_method, void *auth_data,
394                         SilcUInt32 auth_data_len,
395                         SilcConnAuthCompletion completion,
396                         void *context)
397 {
398   SilcAsyncOperation op;
399
400   SILC_LOG_DEBUG(("Connection authentication as initiator"));
401
402   if (auth_method == SILC_AUTH_PASSWORD && !auth_data) {
403     completion(connauth, FALSE, context);
404     return NULL;
405   }
406
407   if (auth_method == SILC_AUTH_PUBLIC_KEY && !auth_data) {
408     completion(connauth, FALSE, context);
409     return NULL;
410   }
411
412   connauth->conn_type = conn_type;
413   connauth->auth_method = auth_method;
414   connauth->auth_data = auth_data;
415   connauth->auth_data_len = auth_data_len;
416   connauth->completion = completion;
417   connauth->context = context;
418
419   /* Link to packet stream to get packets */
420   silc_packet_stream_link(connauth->ske->stream,
421                           &silc_connauth_stream_cbs, connauth, 1000000,
422                           SILC_PACKET_SUCCESS,
423                           SILC_PACKET_FAILURE, -1);
424
425   /* Start the protocol */
426   op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
427   silc_fsm_start(connauth->fsm, silc_connauth_st_initiator_start);
428
429   return op;
430 }
431
432
433 /******************************** Responder *********************************/
434
435 SILC_FSM_STATE(silc_connauth_st_responder_start);
436 SILC_FSM_STATE(silc_connauth_st_responder_authenticate);
437 SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk);
438 SILC_FSM_STATE(silc_connauth_st_responder_success);
439 SILC_FSM_STATE(silc_connauth_st_responder_failure);
440
441 SILC_FSM_STATE(silc_connauth_st_responder_start)
442 {
443   SilcConnAuth connauth = fsm_context;
444
445   SILC_LOG_DEBUG(("Start"));
446
447   if (connauth->aborted) {
448     /** Aborted */
449     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
450     SILC_FSM_CONTINUE;
451   }
452
453   /* Start timeout */
454   if (connauth->timeout_secs)
455     silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
456                                    silc_connauth_timeout, connauth,
457                                    connauth->timeout_secs, 0);
458
459   /** Wait for initiator */
460   silc_fsm_next(fsm, silc_connauth_st_responder_authenticate);
461   SILC_FSM_WAIT;
462 }
463
464 SILC_FSM_STATE(silc_connauth_st_responder_authenticate)
465 {
466   SilcConnAuth connauth = fsm_context;
467   SilcUInt16 payload_len;
468   SilcUInt16 conn_type;
469   unsigned char *auth_data = NULL, *passphrase = NULL;
470   SilcUInt32 passphrase_len;
471   SilcSKR repository = NULL;
472   int ret;
473
474   SILC_LOG_DEBUG(("Start"));
475
476   if (connauth->aborted) {
477     /** Aborted */
478     silc_packet_free(connauth->packet);
479     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
480     SILC_FSM_CONTINUE;
481   }
482
483   if (connauth->packet->type != SILC_PACKET_CONNECTION_AUTH) {
484     /** Protocol failure */
485     silc_packet_free(connauth->packet);
486     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
487     SILC_FSM_CONTINUE;
488   }
489
490   /* Parse the received authentication data packet. The received
491      payload is Connection Auth Payload. */
492   ret = silc_buffer_unformat(&connauth->packet->buffer,
493                              SILC_STR_UI_SHORT(&payload_len),
494                              SILC_STR_UI_SHORT(&conn_type),
495                              SILC_STR_END);
496   if (ret == -1) {
497     /** Bad payload */
498     SILC_LOG_ERROR(("Bad payload in authentication packet"));
499     silc_packet_free(connauth->packet);
500     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
501     SILC_FSM_CONTINUE;
502   }
503
504   if (payload_len != silc_buffer_len(&connauth->packet->buffer)) {
505     /** Bad payload length */
506     SILC_LOG_ERROR(("Bad payload length in authentication packet"));
507     silc_packet_free(connauth->packet);
508     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
509     SILC_FSM_CONTINUE;
510   }
511
512   payload_len -= 4;
513
514   if (conn_type < SILC_CONN_CLIENT || conn_type > SILC_CONN_ROUTER) {
515     /** Bad connection type */
516     SILC_LOG_ERROR(("Bad connection type (%d) in authentication packet",
517                     conn_type));
518     silc_packet_free(connauth->packet);
519     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
520     SILC_FSM_CONTINUE;
521   }
522
523   if (payload_len > 0) {
524     /* Get authentication data */
525     ret = silc_buffer_unformat(&connauth->packet->buffer,
526                                SILC_STR_OFFSET(4),
527                                SILC_STR_UI_XNSTRING(&auth_data,
528                                                     payload_len),
529                                SILC_STR_END);
530     if (ret == -1) {
531       /** Bad payload */
532       SILC_LOG_DEBUG(("Bad payload in authentication payload"));
533       silc_packet_free(connauth->packet);
534       silc_fsm_next(fsm, silc_connauth_st_responder_failure);
535       SILC_FSM_CONTINUE;
536     }
537   }
538   silc_packet_free(connauth->packet);
539
540   SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
541
542   /* Get authentication data */
543   if (!connauth->get_auth_data(connauth, conn_type, &passphrase,
544                                &passphrase_len, &repository,
545                                connauth->context)) {
546     /** Connection not configured */
547     SILC_LOG_ERROR(("Remote connection not configured"));
548     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
549     SILC_FSM_CONTINUE;
550   }
551
552   /* Verify */
553
554   /* Passphrase authentication */
555   if (passphrase && passphrase_len) {
556     SILC_LOG_DEBUG(("Passphrase authentication"));
557     if (!memcmp(auth_data, passphrase, passphrase_len)) {
558       /** Authentication failed */
559       silc_fsm_next(fsm, silc_connauth_st_responder_failure);
560       SILC_FSM_CONTINUE;
561     }
562   } else if (repository) {
563     /* Digital signature */
564     SilcSKRFind find;
565
566     SILC_LOG_DEBUG(("Digital signature authentication"));
567
568     connauth->auth_data = silc_memdup(auth_data, payload_len);
569     connauth->auth_data_len = payload_len;
570
571     /* Allocate search constraints for finding the key */
572     find = silc_skr_find_alloc();
573
574     if (!find || !connauth->auth_data) {
575       /** Out of memory */
576       silc_fsm_next(fsm, silc_connauth_st_responder_failure);
577       SILC_FSM_CONTINUE;
578     }
579
580     silc_skr_find_set_pkcs_type(find, connauth->ske->pk_type);
581     silc_skr_find_set_public_key(find, connauth->ske->public_key);
582     silc_skr_find_set_usage(find, (SILC_SKR_USAGE_AUTH |
583                                    SILC_SKR_USAGE_KEY_AGREEMENT));
584
585     /** Find public key */
586     silc_fsm_next(fsm, silc_connauth_st_responder_authenticate_pk);
587     SILC_FSM_CALL(silc_skr_find(repository, find, silc_connauth_skr_callback,
588                                 connauth));
589     /* NOT REACHED */
590   }
591
592   /* Passphrase auth Ok, or no authentication required */
593
594   /** Authentication successful */
595   silc_fsm_next(fsm, silc_connauth_st_responder_success);
596   SILC_FSM_CONTINUE;
597 }
598
599 SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk)
600 {
601   SilcConnAuth connauth = fsm_context;
602   SilcSKRKey key;
603
604   if (connauth->aborted) {
605     /** Aborted */
606     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
607     SILC_FSM_CONTINUE;
608   }
609
610   if (connauth->skr_status != SILC_SKR_OK) {
611     /** Public key not found */
612     SILC_LOG_DEBUG(("Public key not found, error %d", connauth->skr_status));
613     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
614     SILC_FSM_CONTINUE;
615   }
616
617   SILC_LOG_DEBUG(("Found %d public keys",
618                   silc_dlist_count(connauth->public_keys)));
619
620   /* Verify signature */
621   key = silc_dlist_get(connauth->public_keys);
622   if (!silc_connauth_verify_signature(connauth, key->key,
623                                       connauth->auth_data,
624                                       connauth->auth_data_len)) {
625     /** Invalid signature */
626     SILC_LOG_DEBUG(("Invalid signature"));
627     silc_free(connauth->auth_data);
628     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
629     SILC_FSM_CONTINUE;
630   }
631
632   silc_free(connauth->auth_data);
633
634   /** Authentication successful */
635   silc_fsm_next(fsm, silc_connauth_st_responder_success);
636   SILC_FSM_CONTINUE;
637 }
638
639 SILC_FSM_STATE(silc_connauth_st_responder_success)
640 {
641   SilcConnAuth connauth = fsm_context;
642   unsigned char tmp[4];
643
644   SILC_LOG_DEBUG(("Authentication successful"));
645
646   /* Send FAILURE packet */
647   SILC_PUT32_MSB(SILC_AUTH_OK, tmp);
648   silc_packet_send(connauth->ske->stream, SILC_PACKET_SUCCESS, 0, tmp, 4);
649
650   /* Call completion callback */
651   connauth->completion(connauth, TRUE, connauth->context);
652
653   silc_packet_stream_unlink(connauth->ske->stream,
654                             &silc_connauth_stream_cbs, connauth);
655   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
656
657   SILC_FSM_FINISH;
658 }
659
660 SILC_FSM_STATE(silc_connauth_st_responder_failure)
661 {
662   SilcConnAuth connauth = fsm_context;
663   unsigned char error[4];
664
665   SILC_LOG_ERROR(("Authentication failed"));
666
667   /* Send FAILURE packet */
668   SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
669   silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
670
671   /* Call completion callback */
672   connauth->completion(connauth, FALSE, connauth->context);
673
674   silc_packet_stream_unlink(connauth->ske->stream,
675                             &silc_connauth_stream_cbs, connauth);
676   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
677
678   SILC_FSM_FINISH;
679 }
680
681 SilcAsyncOperation
682 silc_connauth_responder(SilcConnAuth connauth,
683                         SilcConnAuthGetAuthData get_auth_data,
684                         SilcConnAuthCompletion completion,
685                         void *context)
686 {
687   SilcAsyncOperation op;
688
689   SILC_LOG_DEBUG(("Connection authentication as responder"));
690
691   connauth->get_auth_data = get_auth_data;
692   connauth->completion = completion;
693   connauth->context = context;
694
695   /* Link to packet stream to get packets */
696   silc_packet_stream_link(connauth->ske->stream,
697                           &silc_connauth_stream_cbs, connauth, 1000000,
698                           SILC_PACKET_CONNECTION_AUTH,
699                           SILC_PACKET_FAILURE, -1);
700
701   /* Start the protocol */
702   op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
703   silc_fsm_start(connauth->fsm, silc_connauth_st_responder_start);
704
705   return op;
706 }