Added SilcConnAuth connection auth protocol API.
[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   SilcFSMStruct 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
195 /******************************* Protocol API *******************************/
196
197 /* Allocate connection authentication context */
198
199 SilcConnAuth silc_connauth_alloc(SilcSchedule schedule,
200                                  SilcSKE ske,
201                                  SilcUInt32 timeout_secs)
202 {
203   SilcConnAuth connauth;
204
205   if (!schedule || !ske)
206     return NULL;
207
208   connauth = silc_calloc(1, sizeof(*connauth));
209   if (!connauth)
210     return NULL;
211
212   if (!silc_fsm_init(&connauth->fsm, connauth, NULL, NULL, schedule)) {
213     silc_connauth_free(connauth);
214     return NULL;
215   }
216
217   connauth->timeout_secs = timeout_secs;
218   connauth->ske = ske;
219
220   return connauth;
221 }
222
223 /* Free connection authentication context */
224
225 void silc_connauth_free(SilcConnAuth connauth)
226 {
227   if (connauth->public_keys)
228     silc_dlist_uninit(connauth->public_keys);
229   silc_free(connauth);
230 }
231
232 /* Return associated SKE context */
233
234 SilcSKE silc_connauth_get_ske(SilcConnAuth connauth)
235 {
236   return connauth->ske;
237 }
238
239
240 /******************************** Initiator *********************************/
241
242 SILC_FSM_STATE(silc_connauth_st_initiator_start);
243 SILC_FSM_STATE(silc_connauth_st_initiator_result);
244 SILC_FSM_STATE(silc_connauth_st_initiator_failure);
245
246 SILC_FSM_STATE(silc_connauth_st_initiator_start)
247 {
248   SilcConnAuth connauth = fsm_context;
249   SilcBuffer packet;
250   int payload_len = 0;
251   unsigned char *auth_data = NULL;
252   SilcUInt32 auth_data_len = 0;
253
254   SILC_LOG_DEBUG(("Start"));
255
256   if (connauth->aborted) {
257     /** Aborted */
258     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
259     return SILC_FSM_CONTINUE;
260   }
261
262   /* Start timeout */
263   if (connauth->timeout_secs)
264     silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
265                                    silc_connauth_timeout, connauth,
266                                    connauth->timeout_secs, 0);
267
268   switch (connauth->auth_method) {
269   case SILC_AUTH_NONE:
270     /* No authentication required */
271     break;
272
273   case SILC_AUTH_PASSWORD:
274     auth_data = silc_memdup(connauth->auth_data, connauth->auth_data_len);
275     if (!auth_data) {
276       /** Out of memory */
277       silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
278       return SILC_FSM_CONTINUE;
279     }
280     auth_data_len = connauth->auth_data_len;
281     break;
282
283   case SILC_AUTH_PUBLIC_KEY:
284     if (!silc_connauth_get_signature(connauth, &auth_data, &auth_data_len)) {
285       /** Error computing signature */
286       silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
287       return SILC_FSM_CONTINUE;
288     }
289     break;
290   }
291
292   payload_len = 4 + auth_data_len;
293   packet = silc_buffer_alloc_size(payload_len);
294   if (!packet) {
295     /** Out of memory */
296     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
297     return SILC_FSM_CONTINUE;
298   }
299
300   silc_buffer_format(packet,
301                      SILC_STR_UI_SHORT(payload_len),
302                      SILC_STR_UI_SHORT(connauth->conn_type),
303                      SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
304                      SILC_STR_END);
305
306   /* Send the packet */
307   if (!silc_packet_send(connauth->ske->stream, SILC_PACKET_CONNECTION_AUTH, 0,
308                         packet->data, silc_buffer_len(packet))) {
309     /** Error sending packet */
310     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
311     return SILC_FSM_CONTINUE;
312   }
313
314   if (auth_data) {
315     memset(auth_data, 0, auth_data_len);
316     silc_free(auth_data);
317   }
318   silc_buffer_free(packet);
319
320   /** Wait for responder */
321   silc_fsm_next(fsm, silc_connauth_st_initiator_result);
322   return SILC_FSM_WAIT;
323 }
324
325 SILC_FSM_STATE(silc_connauth_st_initiator_result)
326 {
327   SilcConnAuth connauth = fsm_context;
328
329   SILC_LOG_DEBUG(("Start"));
330
331   if (connauth->aborted) {
332     /** Aborted */
333     silc_fsm_next(fsm, silc_connauth_st_initiator_failure);
334     return SILC_FSM_CONTINUE;
335   }
336
337   /* Check the status of authentication */
338   if (connauth->packet->type == SILC_PACKET_SUCCESS) {
339     SILC_LOG_DEBUG(("Authentication successful"));
340     connauth->success = TRUE;
341   } else {
342     SILC_LOG_DEBUG(("Authentication failed"));
343     connauth->success = FALSE;
344   }
345   silc_packet_free(connauth->packet);
346
347   /* Call completion callback */
348   connauth->completion(connauth, connauth->success, connauth->context);
349
350   silc_packet_stream_unlink(connauth->ske->stream,
351                             &silc_connauth_stream_cbs, connauth);
352   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
353
354   return SILC_FSM_FINISH;
355 }
356
357 SILC_FSM_STATE(silc_connauth_st_initiator_failure)
358 {
359   SilcConnAuth connauth = fsm_context;
360   unsigned char error[4];
361
362   SILC_LOG_DEBUG(("Start"));
363
364   /* Send FAILURE packet */
365   SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
366   silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
367
368   /* Call completion callback */
369   connauth->completion(connauth, FALSE, connauth->context);
370
371   silc_packet_stream_unlink(connauth->ske->stream,
372                             &silc_connauth_stream_cbs, connauth);
373   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
374
375   return SILC_FSM_FINISH;
376 }
377
378 SilcAsyncOperation
379 silc_connauth_initiator(SilcConnAuth connauth,
380                         SilcConnectionType conn_type,
381                         SilcAuthMethod auth_method, void *auth_data,
382                         SilcUInt32 auth_data_len,
383                         SilcConnAuthCompletion completion,
384                         void *context)
385 {
386   SilcAsyncOperation op;
387
388   SILC_LOG_DEBUG(("Connection authentication as initiator"));
389
390   if (auth_method == SILC_AUTH_PASSWORD && !auth_data) {
391     completion(connauth, FALSE, context);
392     return NULL;
393   }
394
395   if (auth_method == SILC_AUTH_PUBLIC_KEY && !auth_data) {
396     completion(connauth, FALSE, context);
397     return NULL;
398   }
399
400   connauth->conn_type = conn_type;
401   connauth->auth_method = auth_method;
402   connauth->auth_data = auth_data;
403   connauth->auth_data_len = auth_data_len;
404   connauth->completion = completion;
405   connauth->context = context;
406
407   /* Link to packet stream to get packets */
408   silc_packet_stream_link(connauth->ske->stream,
409                           &silc_connauth_stream_cbs, connauth, 1000000,
410                           SILC_PACKET_SUCCESS,
411                           SILC_PACKET_FAILURE, -1);
412
413   /* Start the protocol */
414   op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
415   silc_fsm_start(&connauth->fsm, silc_connauth_st_initiator_start);
416
417   return op;
418 }
419
420
421 /******************************** Responder *********************************/
422
423 SILC_FSM_STATE(silc_connauth_st_responder_start);
424 SILC_FSM_STATE(silc_connauth_st_responder_authenticate);
425 SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk);
426 SILC_FSM_STATE(silc_connauth_st_responder_success);
427 SILC_FSM_STATE(silc_connauth_st_responder_failure);
428
429 SILC_FSM_STATE(silc_connauth_st_responder_start)
430 {
431   SilcConnAuth connauth = fsm_context;
432
433   SILC_LOG_DEBUG(("Start"));
434
435   if (connauth->aborted) {
436     /** Aborted */
437     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
438     return SILC_FSM_CONTINUE;
439   }
440
441   /* Start timeout */
442   if (connauth->timeout_secs)
443     silc_schedule_task_add_timeout(silc_fsm_get_schedule(fsm),
444                                    silc_connauth_timeout, connauth,
445                                    connauth->timeout_secs, 0);
446
447   /** Wait for initiator */
448   silc_fsm_next(fsm, silc_connauth_st_responder_authenticate);
449   return SILC_FSM_WAIT;
450 }
451
452 SILC_FSM_STATE(silc_connauth_st_responder_authenticate)
453 {
454   SilcConnAuth connauth = fsm_context;
455   SilcUInt16 payload_len;
456   SilcUInt16 conn_type;
457   unsigned char *auth_data = NULL, *passphrase = NULL;
458   SilcUInt32 passphrase_len;
459   SilcSKR repository = NULL;
460   int ret;
461
462   SILC_LOG_DEBUG(("Start"));
463
464   if (connauth->aborted) {
465     /** Aborted */
466     silc_packet_free(connauth->packet);
467     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
468     return SILC_FSM_CONTINUE;
469   }
470
471   if (connauth->packet->type != SILC_PACKET_CONNECTION_AUTH) {
472     /** Protocol failure */
473     silc_packet_free(connauth->packet);
474     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
475     return SILC_FSM_CONTINUE;
476   }
477
478   /* Parse the received authentication data packet. The received
479      payload is Connection Auth Payload. */
480   ret = silc_buffer_unformat(&connauth->packet->buffer,
481                              SILC_STR_UI_SHORT(&payload_len),
482                              SILC_STR_UI_SHORT(&conn_type),
483                              SILC_STR_END);
484   if (ret == -1) {
485     /** Bad payload */
486     SILC_LOG_ERROR(("Bad payload in authentication packet"));
487     silc_packet_free(connauth->packet);
488     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
489     return SILC_FSM_CONTINUE;
490   }
491
492   if (payload_len != silc_buffer_len(&connauth->packet->buffer)) {
493     /** Bad payload length */
494     SILC_LOG_ERROR(("Bad payload length in authentication packet"));
495     silc_packet_free(connauth->packet);
496     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
497     return SILC_FSM_CONTINUE;
498   }
499
500   payload_len -= 4;
501
502   if (conn_type < SILC_CONN_CLIENT || conn_type > SILC_CONN_ROUTER) {
503     /** Bad connection type */
504     SILC_LOG_ERROR(("Bad connection type (%d) in authentication packet",
505                     conn_type));
506     silc_packet_free(connauth->packet);
507     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
508     return SILC_FSM_CONTINUE;
509   }
510
511   if (payload_len > 0) {
512     /* Get authentication data */
513     ret = silc_buffer_unformat(&connauth->packet->buffer,
514                                SILC_STR_OFFSET(4),
515                                SILC_STR_UI_XNSTRING(&auth_data,
516                                                     payload_len),
517                                SILC_STR_END);
518     if (ret == -1) {
519       /** Bad payload */
520       SILC_LOG_DEBUG(("Bad payload in authentication payload"));
521       silc_packet_free(connauth->packet);
522       silc_fsm_next(fsm, silc_connauth_st_responder_failure);
523       return SILC_FSM_CONTINUE;
524     }
525   }
526   silc_packet_free(connauth->packet);
527
528   SILC_LOG_DEBUG(("Remote connection type %d", conn_type));
529
530   /* Get authentication data */
531   if (!connauth->get_auth_data(connauth, conn_type, &passphrase,
532                                &passphrase_len, &repository,
533                                connauth->context)) {
534     /** Connection not configured */
535     SILC_LOG_ERROR(("Remote connection not configured"));
536     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
537     return SILC_FSM_CONTINUE;
538   }
539
540   /* Verify */
541
542   /* Passphrase authentication */
543   if (passphrase && passphrase_len) {
544     SILC_LOG_DEBUG(("Passphrase authentication"));
545     if (!memcmp(auth_data, passphrase, passphrase_len)) {
546       /** Authentication failed */
547       silc_fsm_next(fsm, silc_connauth_st_responder_failure);
548       return SILC_FSM_CONTINUE;
549     }
550   } else if (repository) {
551     /* Digital signature */
552     SilcSKRFind find;
553
554     SILC_LOG_DEBUG(("Digital signature authentication"));
555
556     connauth->auth_data = silc_memdup(auth_data, payload_len);
557     connauth->auth_data_len = payload_len;
558
559     /* Allocate search constraints for finding the key */
560     find = silc_skr_find_alloc();
561
562     if (!find || !connauth->auth_data) {
563       /** Out of memory */
564       silc_fsm_next(fsm, silc_connauth_st_responder_failure);
565       return SILC_FSM_CONTINUE;
566     }
567
568     silc_skr_find_set_pkcs_type(find, connauth->ske->pk_type);
569     silc_skr_find_set_public_key(find, connauth->ske->public_key);
570     silc_skr_find_set_usage(find, (SILC_SKR_USAGE_AUTH |
571                                    SILC_SKR_USAGE_KEY_AGREEMENT));
572
573     /** Find public key */
574     silc_fsm_next(fsm, silc_connauth_st_responder_authenticate_pk);
575     SILC_FSM_CALL(silc_skr_find(repository, find, silc_connauth_skr_callback,
576                                 connauth));
577     /* NOT REACHED */
578   }
579
580   /* Passphrase auth Ok, or no authentication required */
581
582   /** Authentication successful */
583   silc_fsm_next(fsm, silc_connauth_st_responder_success);
584   return SILC_FSM_CONTINUE;
585 }
586
587 SILC_FSM_STATE(silc_connauth_st_responder_authenticate_pk)
588 {
589   SilcConnAuth connauth = fsm_context;
590   SilcSKRKey key;
591
592   if (connauth->aborted) {
593     /** Aborted */
594     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
595     return SILC_FSM_CONTINUE;
596   }
597
598   if (connauth->skr_status != SILC_SKR_OK) {
599     /** Public key not found */
600     SILC_LOG_DEBUG(("Public key not found, error %d", connauth->skr_status));
601     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
602     return SILC_FSM_CONTINUE;
603   }
604
605   SILC_LOG_DEBUG(("Found %d public keys",
606                   silc_dlist_count(connauth->public_keys)));
607
608   /* Verify signature */
609   key = silc_dlist_get(connauth->public_keys);
610   if (!silc_connauth_verify_signature(connauth, key->key,
611                                       connauth->auth_data,
612                                       connauth->auth_data_len)) {
613     /** Invalid signature */
614     SILC_LOG_DEBUG(("Invalid signature"));
615     silc_free(connauth->auth_data);
616     silc_fsm_next(fsm, silc_connauth_st_responder_failure);
617     return SILC_FSM_CONTINUE;
618   }
619
620   silc_free(connauth->auth_data);
621
622   /** Authentication successful */
623   silc_fsm_next(fsm, silc_connauth_st_responder_success);
624   return SILC_FSM_CONTINUE;
625 }
626
627 SILC_FSM_STATE(silc_connauth_st_responder_success)
628 {
629   SilcConnAuth connauth = fsm_context;
630   unsigned char tmp[4];
631
632   SILC_LOG_DEBUG(("Authentication successful"));
633
634   /* Send FAILURE packet */
635   SILC_PUT32_MSB(SILC_AUTH_OK, tmp);
636   silc_packet_send(connauth->ske->stream, SILC_PACKET_SUCCESS, 0, tmp, 4);
637
638   /* Call completion callback */
639   connauth->completion(connauth, TRUE, connauth->context);
640
641   silc_packet_stream_unlink(connauth->ske->stream,
642                             &silc_connauth_stream_cbs, connauth);
643   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
644
645   return SILC_FSM_FINISH;
646 }
647
648 SILC_FSM_STATE(silc_connauth_st_responder_failure)
649 {
650   SilcConnAuth connauth = fsm_context;
651   unsigned char error[4];
652
653   SILC_LOG_ERROR(("Authentication failed"));
654
655   /* Send FAILURE packet */
656   SILC_PUT32_MSB(SILC_AUTH_FAILED, error);
657   silc_packet_send(connauth->ske->stream, SILC_PACKET_FAILURE, 0, error, 4);
658
659   /* Call completion callback */
660   connauth->completion(connauth, FALSE, connauth->context);
661
662   silc_packet_stream_unlink(connauth->ske->stream,
663                             &silc_connauth_stream_cbs, connauth);
664   silc_schedule_task_del_by_context(silc_fsm_get_schedule(fsm), connauth);
665
666   return SILC_FSM_FINISH;
667 }
668
669 SilcAsyncOperation
670 silc_connauth_responder(SilcConnAuth connauth,
671                         SilcConnAuthGetAuthData get_auth_data,
672                         SilcConnAuthCompletion completion,
673                         void *context)
674 {
675   SilcAsyncOperation op;
676
677   SILC_LOG_DEBUG(("Connection authentication as responder"));
678
679   connauth->get_auth_data = get_auth_data;
680   connauth->completion = completion;
681   connauth->context = context;
682
683   /* Link to packet stream to get packets */
684   silc_packet_stream_link(connauth->ske->stream,
685                           &silc_connauth_stream_cbs, connauth, 1000000,
686                           SILC_PACKET_CONNECTION_AUTH,
687                           SILC_PACKET_FAILURE, -1);
688
689   /* Start the protocol */
690   op = silc_async_alloc(silc_connauth_abort, NULL, connauth);
691   silc_fsm_start(&connauth->fsm, silc_connauth_st_responder_start);
692
693   return op;
694 }