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