Added support for server public key verification.
[silc.git] / apps / silc / protocol.c
1 /*
2
3   protocol.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * Client side of the protocols.
22  */
23 /*
24  * $Id$
25  * $Log$
26  * Revision 1.4  2000/07/07 06:53:45  priikone
27  *      Added support for server public key verification.
28  *
29  * Revision 1.3  2000/07/06 07:14:16  priikone
30  *      Deprecated old `channel_auth' protocol.
31  *
32  * Revision 1.2  2000/07/05 06:12:05  priikone
33  *      Global cosmetic changes.
34  *
35  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
36  *      Imported from internal CVS/Added Log headers.
37  *
38  *
39  */
40
41 #include "clientincludes.h"
42
43 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth);
44 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange);
45
46 /* SILC client protocol list */
47 const SilcProtocolObject silc_protocol_list[] =
48 {
49   { SILC_PROTOCOL_CLIENT_CONNECTION_AUTH, 
50     silc_client_protocol_connection_auth },
51   { SILC_PROTOCOL_CLIENT_KEY_EXCHANGE, 
52     silc_client_protocol_key_exchange },
53
54   { SILC_PROTOCOL_CLIENT_NONE, NULL },
55 };
56
57 /*
58  * Key Exhange protocol functions
59  */
60
61 /* Function that is called when SKE protocol sends packets to network. */
62
63 static void silc_client_protocol_ke_send_packet(SilcSKE ske,
64                                                 SilcBuffer packet,
65                                                 SilcPacketType type,
66                                                 void *context)
67 {
68   SilcProtocol protocol = (SilcProtocol)context;
69   SilcClientKEInternalContext *ctx = 
70     (SilcClientKEInternalContext *)protocol->context;
71   SilcClient client = (SilcClient)ctx->client;
72
73   /* Send the packet immediately */
74   silc_client_packet_send(client, ske->sock, type, NULL, 0, NULL, NULL,
75                           packet->data, packet->len, TRUE);
76
77 }
78
79 /* Callback that is called when we have received KE2 payload from
80    responder. We try to verify the public key now. */
81
82 static SilcSKEStatus 
83 silc_client_protocol_ke_verify_key(SilcSKE ske,
84                                    unsigned char *pk_data,
85                                    unsigned int pk_len,
86                                    SilcSKEPKType pk_type,
87                                    void *context)
88 {
89   SilcProtocol protocol = (SilcProtocol)context;
90   SilcClientKEInternalContext *ctx = 
91     (SilcClientKEInternalContext *)protocol->context;
92   SilcClient client = (SilcClient)ctx->client;
93
94   SILC_LOG_DEBUG(("Start"));
95
96   if (!silc_client_verify_server_key(client, ctx->sock, 
97                                      pk_data, pk_len, pk_type))
98     return SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
99
100   return SILC_SKE_STATUS_OK;
101 }
102
103 /* Sets the negotiated key material into use for particular connection. */
104
105 static void silc_client_protocol_ke_set_keys(SilcSKE ske,
106                                              SilcSocketConnection sock,
107                                              SilcSKEKeyMaterial *keymat,
108                                              SilcCipher cipher,
109                                              SilcPKCS pkcs,
110                                              SilcHash hash)
111 {
112   SilcClientWindow win = (SilcClientWindow)sock->user_data;
113   SilcHash nhash;
114
115   SILC_LOG_DEBUG(("Setting new keys into use"));
116
117   /* Allocate cipher to be used in the communication */
118   silc_cipher_alloc(cipher->cipher->name, &win->send_key);
119   silc_cipher_alloc(cipher->cipher->name, &win->receive_key);
120
121   win->send_key->cipher->set_key(win->send_key->context, 
122                                  keymat->send_enc_key, 
123                                  keymat->enc_key_len);
124   win->send_key->set_iv(win->send_key, keymat->send_iv);
125   win->receive_key->cipher->set_key(win->receive_key->context, 
126                                     keymat->receive_enc_key, 
127                                     keymat->enc_key_len);
128   win->receive_key->set_iv(win->receive_key, keymat->receive_iv);
129
130   /* Allocate PKCS to be used */
131 #if 0
132   /* XXX Do we ever need to allocate PKCS for the connection??
133      If yes, we need to change KE protocol to get the initiators
134      public key. */
135   silc_pkcs_alloc(pkcs->pkcs->name, &win->public_Key);
136   silc_pkcs_set_public_key(win->public_key, ske->ke2_payload->pk_data, 
137                            ske->ke2_payload->pk_len);
138 #endif
139
140   /* Save HMAC key to be used in the communication. */
141   silc_hash_alloc(hash->hash->name, &nhash);
142   silc_hmac_alloc(nhash, &win->hmac);
143   win->hmac_key_len = keymat->hmac_key_len;
144   win->hmac_key = silc_calloc(win->hmac_key_len,
145                                     sizeof(unsigned char));
146   memcpy(win->hmac_key, keymat->hmac_key, keymat->hmac_key_len);
147
148 }
149
150 /* Performs key exchange protocol. This is used for both initiator
151    and responder key exchange. This may be called recursively. */
152
153 SILC_TASK_CALLBACK(silc_client_protocol_key_exchange)
154 {
155   SilcProtocol protocol = (SilcProtocol)context;
156   SilcClientKEInternalContext *ctx = 
157     (SilcClientKEInternalContext *)protocol->context;
158   SilcClient client = (SilcClient)ctx->client;
159   SilcSKEStatus status;
160
161   SILC_LOG_DEBUG(("Start"));
162
163   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
164     protocol->state = SILC_PROTOCOL_STATE_START;
165
166   switch(protocol->state) {
167   case SILC_PROTOCOL_STATE_START:
168     {
169       /*
170        * Start Protocol
171        */
172       SilcSKE ske;
173
174       /* Allocate Key Exchange object */
175       ske = silc_ske_alloc();
176       ctx->ske = ske;
177       
178       if (ctx->responder == TRUE) {
179 #if 0
180         SilcBuffer start_payload;
181
182
183         /* Start the key exchange by processing the received security
184            properties packet from initiator. */
185         status = silc_ske_responder_start(ske, ctx->rng, ctx->sock,
186                                           start_payload,
187                                           silc_client_protocol_ke_send_packet,
188                                           context);
189 #endif
190       } else {
191         SilcSKEStartPayload *start_payload;
192
193         /* Assemble security properties. */
194         silc_ske_assemble_security_properties(ske, &start_payload);
195
196         /* Start the key exchange by sending our security properties
197            to the remote end. */
198         status = silc_ske_initiator_start(ske, ctx->rng, ctx->sock,
199                                           start_payload,
200                                           silc_client_protocol_ke_send_packet,
201                                           context);
202       }
203
204       if (status != SILC_SKE_STATUS_OK) {
205         switch(status) {
206           
207         default:
208           break;
209         }
210       }
211
212       /* Advance the state of the protocol. */
213       protocol->state++;
214     }
215     break;
216   case 2:
217     {
218       /* 
219        * Phase 1 
220        */
221       if (ctx->responder == TRUE) {
222 #if 0
223         status = 
224           silc_ske_responder_phase_1(ctx->ske, 
225                                      ctx->ske->start_payload,
226                                      silc_server_protocol_ke_send_packet,
227                                      context);
228 #endif
229       } else {
230         /* Call Phase-1 function. This processes the Key Exchange Start
231            paylaod reply we just got from the responder. The callback
232            function will receive the processed payload where we will
233            save it. */
234         status = silc_ske_initiator_phase_1(ctx->ske, ctx->packet, NULL, NULL);
235       }
236
237       switch(status) {
238       default:
239         break;
240       }
241
242       /* Advance the state of the protocol and call the next state. */
243       protocol->state++;
244       protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
245     }
246     break;
247   case 3:
248     {
249       /* 
250        * Phase 2 
251        */
252       if (ctx->responder == TRUE) {
253 #if 0
254         status = 
255           silc_ske_responder_phase_2(ctx->ske, 
256                                      ctx->ske->start_payload,
257                                      silc_server_protocol_ke_send_packet,
258                                      context);
259 #endif
260       } else {
261         /* Call the Phase-2 function. This creates Diffie Hellman
262            key exchange parameters and sends our public part inside
263            Key Exhange 1 Payload to the responder. */
264         status = 
265           silc_ske_initiator_phase_2(ctx->ske,
266                                      silc_client_protocol_ke_send_packet,
267                                      context);
268       }
269
270       switch(status) {
271       default:
272         break;
273       }
274
275       /* Advance the state of the protocol. */
276       protocol->state++;
277     }
278     break;
279   case 4:
280     {
281       /* 
282        * Finish protocol
283        */
284       if (ctx->responder == TRUE) {
285         status = 0;
286 #if 0
287         status = 
288           silc_ske_responder_phase_2(ctx->ske, 
289                                      ctx->ske->start_payload,
290                                      silc_server_protocol_ke_send_packet,
291                                      context);
292 #endif
293       } else {
294         /* Finish the protocol. This verifies the Key Exchange 2 payload
295            sent by responder. */
296         status = silc_ske_initiator_finish(ctx->ske, ctx->packet,
297                                            silc_client_protocol_ke_verify_key,
298                                            context, NULL, NULL);
299       }
300
301       if (status != SILC_SKE_STATUS_OK) {
302         protocol->state = SILC_PROTOCOL_STATE_ERROR;
303         protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
304         return;
305       }
306       
307       /* Send Ok to the other end. We will end the protocol as server
308          sends Ok to us when we will take the new keys into use. */
309       silc_ske_end(ctx->ske, silc_client_protocol_ke_send_packet, context);
310       
311       /* End the protocol on the next round */
312       protocol->state = SILC_PROTOCOL_STATE_END;
313     }
314     break;
315   case SILC_PROTOCOL_STATE_END:
316     {
317       /* 
318        * End protocol
319        */
320       SilcSKEKeyMaterial *keymat;
321
322       /* Process the key material */
323       keymat = silc_calloc(1, sizeof(*keymat));
324       silc_ske_process_key_material(ctx->ske, 16, (16 * 8), 16, keymat);
325
326       /* Take the negotiated keys into use. */
327       silc_client_protocol_ke_set_keys(ctx->ske, ctx->sock, keymat,
328                                        ctx->ske->prop->cipher,
329                                        ctx->ske->prop->pkcs,
330                                        ctx->ske->prop->hash);
331
332       /* Protocol has ended, call the final callback */
333       if (protocol->final_callback)
334         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
335       else
336         silc_protocol_free(protocol);
337     }
338     break;
339   case SILC_PROTOCOL_STATE_ERROR:
340     
341     /* On error the final callback is always called. */
342     if (protocol->final_callback)
343       protocol->execute_final(client->timeout_queue, 0, protocol, fd);
344     else
345       silc_protocol_free(protocol);
346     break;
347   case SILC_PROTOCOL_STATE_UNKNOWN:
348     break;
349   }
350 }
351
352 /*
353  * Connection Authentication protocol functions
354  */
355
356 SILC_TASK_CALLBACK(silc_client_protocol_connection_auth)
357 {
358   SilcProtocol protocol = (SilcProtocol)context;
359   SilcClientConnAuthInternalContext *ctx = 
360     (SilcClientConnAuthInternalContext *)protocol->context;
361   SilcClient client = (SilcClient)ctx->client;
362
363   SILC_LOG_DEBUG(("Start"));
364
365   if (protocol->state == SILC_PROTOCOL_STATE_UNKNOWN)
366     protocol->state = SILC_PROTOCOL_STATE_START;
367
368   switch(protocol->state) {
369   case SILC_PROTOCOL_STATE_START:
370     {
371       /* 
372        * Start protocol. We send authentication data to the server
373        * to be authenticated.
374        */
375       SilcBuffer packet;
376       int payload_len = 0;
377       unsigned char *auth_data = NULL;
378       unsigned int auth_data_len = 0;
379
380       switch(ctx->auth_meth) {
381       case SILC_PROTOCOL_CONN_AUTH_NONE:
382         /* No authentication required */
383         break;
384
385       case SILC_PROTOCOL_CONN_AUTH_PASSWORD:
386         /* Password authentication */
387         if (ctx->auth_data && ctx->auth_data_len) {
388           auth_data = ctx->auth_data;
389           auth_data_len = ctx->auth_data_len;
390           break;
391         }
392
393         silc_say(client, "Password authentication required by server %s",
394                  ctx->sock->hostname);
395         auth_data = silc_client_ask_passphrase(client);
396         auth_data_len = strlen(auth_data);
397         break;
398
399       case SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY:
400         /* XXX */
401         break;
402       }
403
404       payload_len = 4 + auth_data_len;
405       packet = silc_buffer_alloc(payload_len);
406       silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
407       silc_buffer_format(packet,
408                          SILC_STR_UI_SHORT(payload_len),
409                          SILC_STR_UI_SHORT(SILC_SOCKET_TYPE_CLIENT),
410                          SILC_STR_UI_XNSTRING(auth_data, auth_data_len),
411                          SILC_STR_END);
412
413       /* Send the packet to server */
414       silc_client_packet_send(client, ctx->sock,
415                               SILC_PACKET_CONNECTION_AUTH,
416                               NULL, 0, NULL, NULL,
417                               packet->data, packet->len, TRUE);
418
419       if (auth_data) {
420         memset(auth_data, 0, auth_data_len);
421         silc_free(auth_data);
422       }
423       silc_buffer_free(packet);
424       
425       /* Next state is end of protocol */
426       protocol->state = SILC_PROTOCOL_STATE_END;
427     }
428     break;
429
430   case SILC_PROTOCOL_STATE_END:
431     {
432       /* 
433        * End protocol. Nothing special to be done here.
434        */
435
436       /* Protocol has ended, call the final callback */
437       if (protocol->final_callback)
438         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
439       else
440         silc_protocol_free(protocol);
441     }
442     break;
443
444   case SILC_PROTOCOL_STATE_ERROR:
445     {
446       /* 
447        * Error
448        */
449
450       /* Error in protocol. Send FAILURE packet. Although I don't think
451          this could ever happen on client side. */
452       silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
453                               NULL, 0, NULL, NULL, NULL, 0, TRUE);
454
455       /* On error the final callback is always called. */
456       if (protocol->final_callback)
457         protocol->execute_final(client->timeout_queue, 0, protocol, fd);
458       else
459         silc_protocol_free(protocol);
460     }
461     break;
462   case SILC_PROTOCOL_STATE_UNKNOWN:
463     break;
464   }
465 }
466