Merged from silc_1_0_branch.
[silc.git] / lib / silcske / silcske.c
1 /*
2
3   silcske.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2000 - 2002 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 /* $Id$ */
20
21 #include "silcincludes.h"
22 #include "silcske.h"
23 #include "groups_internal.h"
24
25 /* Static functions */
26 static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, 
27                                          SilcUInt32 len, 
28                                          SilcMPInt *rnd);
29 static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
30                                         unsigned char *return_hash,
31                                         SilcUInt32 *return_hash_len,
32                                         int initiator);
33
34 /* Structure to hold all SKE callbacks. */
35 struct SilcSKECallbacksStruct {
36   SilcSKESendPacketCb send_packet;
37   SilcSKECb payload_receive;
38   SilcSKEVerifyCb verify_key;
39   SilcSKECb proto_continue;
40   SilcSKECheckVersion check_version;
41   void *context;
42 };
43
44 /* Allocates new SKE object. */
45
46 SilcSKE silc_ske_alloc(SilcRng rng, void *context)
47 {
48   SilcSKE ske;
49
50   SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
51
52   ske = silc_calloc(1, sizeof(*ske));
53   if (!ske)
54     return NULL;
55   ske->status = SILC_SKE_STATUS_OK;
56   ske->rng = rng;
57   ske->user_data = context;
58   ske->users = 1;
59
60   return ske;
61 }
62
63 /* Free's SKE object. */
64
65 void silc_ske_free(SilcSKE ske)
66 {
67   ske->users--;
68   if (ske->users > 0) {
69     SILC_LOG_DEBUG(("Key Exchange set to FREED status"));
70     ske->status = SILC_SKE_STATUS_FREED;
71     return;
72   }
73
74   SILC_LOG_DEBUG(("Freeing Key Exchange object"));
75
76   if (ske) {
77     /* Free start payload */
78     if (ske->start_payload)
79       silc_ske_payload_start_free(ske->start_payload);
80
81     /* Free KE payload */
82     if (ske->ke1_payload)
83       silc_ske_payload_ke_free(ske->ke1_payload);
84     if (ske->ke2_payload)
85       silc_ske_payload_ke_free(ske->ke2_payload);
86     silc_free(ske->remote_version);
87
88     /* Free rest */
89     if (ske->prop) {
90       if (ske->prop->group)
91         silc_ske_group_free(ske->prop->group);
92       if (ske->prop->pkcs)
93         silc_pkcs_free(ske->prop->pkcs);
94       if (ske->prop->cipher)
95         silc_cipher_free(ske->prop->cipher);
96       if (ske->prop->hash)
97         silc_hash_free(ske->prop->hash);
98       if (ske->prop->hmac)
99         silc_hmac_free(ske->prop->hmac);
100       silc_free(ske->prop);
101     }
102     if (ske->start_payload_copy)
103       silc_buffer_free(ske->start_payload_copy);
104     if (ske->x) {
105       silc_mp_uninit(ske->x);
106       silc_free(ske->x);
107     }
108     if (ske->KEY) {
109       silc_mp_uninit(ske->KEY);
110       silc_free(ske->KEY);
111     }
112     silc_free(ske->hash);
113     silc_free(ske->callbacks);
114
115     memset(ske, 'F', sizeof(*ske));
116     silc_free(ske);
117   }
118 }
119
120 /* Sets the callback functions for the SKE session. 
121
122    The `send_packet' callback is a function that sends the packet to
123    network. The SKE library will call it at any time packet needs to
124    be sent to the remote host. 
125
126    The `payload_receive' callback is called when the remote host's Key
127    Exchange Start Payload has been processed.  The payload is saved
128    to ske->start_payload if the application would need it.  The application
129    must also provide the payload to the next state of the SKE.
130
131    The `verify_key' callback is called to verify the received public key
132    or certificate.  The verification process is most likely asynchronous.
133    That is why the application must call the completion callback when the
134    verification process has been completed. The library then calls the user
135    callback (`proto_continue'), if it is provided to indicate that the SKE
136    protocol may continue. 
137    
138    The `proto_continue' callback is called to indicate that it is
139    safe to continue the execution of the SKE protocol after executing
140    an asynchronous operation, such as calling the `verify_key' callback
141    function, which is asynchronous. The application should check the
142    ske->status in this function to check whether it is Ok to continue
143    the execution of the protocol.
144
145    The `check_version' callback is called to verify the remote host's
146    version. The application may check its own version against the remote
147    host's version and determine whether supporting the remote host
148    is possible. 
149
150    The `context' is passed as argument to all of the above callback
151    functions. */
152
153 void silc_ske_set_callbacks(SilcSKE ske,
154                             SilcSKESendPacketCb send_packet,
155                             SilcSKECb payload_receive,
156                             SilcSKEVerifyCb verify_key,
157                             SilcSKECb proto_continue,
158                             SilcSKECheckVersion check_version,
159                             void *context)
160 {
161   if (ske->callbacks)
162     silc_free(ske->callbacks);
163   ske->callbacks = silc_calloc(1, sizeof(*ske->callbacks));
164   if (!ske->callbacks)
165     return;
166   ske->callbacks->send_packet = send_packet;
167   ske->callbacks->payload_receive = payload_receive;
168   ske->callbacks->verify_key = verify_key;
169   ske->callbacks->proto_continue = proto_continue;
170   ske->callbacks->check_version = check_version;
171   ske->callbacks->context = context;
172 }
173
174 /* Starts the SILC Key Exchange protocol for initiator. The connection
175    to the remote end must be established before calling this function
176    and the connecting socket must be sent as argument. This function
177    creates the Key Exchange Start Payload which includes all our
178    configured security properties. This payload is then sent to the
179    remote end for further processing. This payload must be sent as
180    argument to the function, however, it must not be encoded
181    already, it is done by this function. The caller must not free
182    the `start_payload' since the SKE library will save it.
183
184    The packet sending is done by calling a callback function. Caller
185    must provide a routine to send the packet. */
186
187 SilcSKEStatus silc_ske_initiator_start(SilcSKE ske, SilcRng rng,
188                                        SilcSocketConnection sock,
189                                        SilcSKEStartPayload *start_payload)
190 {
191   SilcSKEStatus status = SILC_SKE_STATUS_OK;
192   SilcBuffer payload_buf;
193
194   SILC_LOG_DEBUG(("Start"));
195
196   ske->sock = sock;
197   ske->rng = rng;
198
199   /* Encode the payload */
200   status = silc_ske_payload_start_encode(ske, start_payload, &payload_buf);
201   if (status != SILC_SKE_STATUS_OK)
202     return status;
203
204   /* Take a copy of the payload buffer for future use. It is used to
205      compute the HASH value. */
206   ske->start_payload_copy = silc_buffer_copy(payload_buf);
207   ske->start_payload = start_payload;
208
209   /* Send the packet. */
210   if (ske->callbacks->send_packet)
211     (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
212                                    ske->callbacks->context);
213
214   silc_buffer_free(payload_buf);
215
216   return status;
217 }
218
219 /* Function called after ske_initiator_start fuction. This receives
220    the remote ends Key Exchange Start payload which includes the
221    security properties selected by the responder from our payload
222    sent in the silc_ske_initiator_start function. */
223
224 SilcSKEStatus silc_ske_initiator_phase_1(SilcSKE ske, 
225                                          SilcBuffer start_payload)
226 {
227   SilcSKEStatus status = SILC_SKE_STATUS_OK;
228   SilcSKEStartPayload *payload;
229   SilcSKESecurityProperties prop;
230   SilcSKEDiffieHellmanGroup group;
231
232   SILC_LOG_DEBUG(("Start"));
233
234   /* Decode the payload */
235   status = silc_ske_payload_start_decode(ske, start_payload, &payload);
236   if (status != SILC_SKE_STATUS_OK) {
237     ske->status = status;
238     silc_ske_payload_start_free(ske->start_payload);
239     return status;
240   }
241
242   /* Check that the cookie is returned unmodified */
243   if (memcmp(ske->start_payload->cookie, payload->cookie,
244              ske->start_payload->cookie_len)) {
245     SILC_LOG_ERROR(("Responder modified our cookie and it must not do it"));
246     ske->status = SILC_SKE_STATUS_INVALID_COOKIE;
247     silc_ske_payload_start_free(ske->start_payload);
248     return status;
249   }
250
251   /* Check version string */
252   if (ske->callbacks->check_version) {
253     status = ske->callbacks->check_version(ske, payload->version, 
254                                            payload->version_len,
255                                            ske->callbacks->context);
256     if (status != SILC_SKE_STATUS_OK) {
257       ske->status = status;
258       silc_ske_payload_start_free(ske->start_payload);
259       return status;
260     }
261   }
262
263   /* Free our KE Start Payload context, we don't need it anymore. */
264   silc_ske_payload_start_free(ske->start_payload);
265
266   /* Take the selected security properties into use while doing
267      the key exchange. This is used only while doing the key 
268      exchange. The same data is returned to upper levels by calling
269      the callback function. */
270   ske->prop = prop = silc_calloc(1, sizeof(*prop));
271   if (!ske->prop)
272     goto err;
273   prop->flags = payload->flags;
274   status = silc_ske_group_get_by_name(payload->ke_grp_list, &group);
275   if (status != SILC_SKE_STATUS_OK)
276     goto err;
277
278   prop->group = group;
279
280   if (silc_pkcs_alloc(payload->pkcs_alg_list, &prop->pkcs) == FALSE) {
281     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
282     goto err;
283   }
284
285   if (silc_cipher_alloc(payload->enc_alg_list, &prop->cipher) == FALSE) {
286     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
287     goto err;
288   }
289
290   if (silc_hash_alloc(payload->hash_alg_list, &prop->hash) == FALSE) {
291     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
292     goto err;
293   }
294
295   if (silc_hmac_alloc(payload->hmac_alg_list, NULL, &prop->hmac) == FALSE) {
296     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
297     goto err;
298   }
299
300   /* Save remote's KE Start Payload */
301   ske->start_payload = payload;
302
303   /* Return the received payload by calling the callback function. */
304   if (ske->callbacks->payload_receive)
305     (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
306
307   return status;
308
309  err:
310   if (payload)
311     silc_ske_payload_start_free(payload);
312
313   silc_ske_group_free(group);
314
315   if (prop->pkcs)
316     silc_pkcs_free(prop->pkcs);
317   if (prop->cipher)
318     silc_cipher_free(prop->cipher);
319   if (prop->hash)
320     silc_hash_free(prop->hash);
321   if (prop->hmac)
322     silc_hmac_free(prop->hmac);
323   silc_free(prop);
324   ske->prop = NULL;
325
326   if (status == SILC_SKE_STATUS_OK)
327     return SILC_SKE_STATUS_ERROR;
328
329   ske->status = status;
330   return status;
331 }
332
333 /* This function creates random number x, such that 1 < x < q and 
334    computes e = g ^ x mod p and sends the result to the remote end in 
335    Key Exchange Payload. */
336
337 SilcSKEStatus silc_ske_initiator_phase_2(SilcSKE ske,
338                                          SilcPublicKey public_key,
339                                          SilcPrivateKey private_key,
340                                          SilcSKEPKType pk_type)
341 {
342   SilcSKEStatus status = SILC_SKE_STATUS_OK;
343   SilcBuffer payload_buf;
344   SilcMPInt *x;
345   SilcSKEKEPayload *payload;
346   SilcUInt32 pk_len;
347
348   SILC_LOG_DEBUG(("Start"));
349
350   /* Create the random number x, 1 < x < q. */
351   x = silc_calloc(1, sizeof(*x));
352   if (!x){
353     ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
354     return ske->status;
355   }
356   silc_mp_init(x);
357   status = 
358     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
359                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
360                         x);
361   if (status != SILC_SKE_STATUS_OK) {
362     silc_mp_uninit(x);
363     silc_free(x);
364     ske->status = status;
365     return status;
366   }
367
368   /* Encode the result to Key Exchange Payload. */
369
370   payload = silc_calloc(1, sizeof(*payload));
371   if (!payload) {
372     silc_mp_uninit(x);
373     silc_free(x);
374     ske->status = SILC_SKE_STATUS_OUT_OF_MEMORY;
375     return ske->status;
376   }
377   ske->ke1_payload = payload;
378
379   SILC_LOG_DEBUG(("Computing e = g ^ x mod p"));
380
381   /* Do the Diffie Hellman computation, e = g ^ x mod p */
382   silc_mp_init(&payload->x);
383   silc_mp_pow_mod(&payload->x, &ske->prop->group->generator, x, 
384                   &ske->prop->group->group);
385
386   /* Get public key */
387   if (public_key) {
388     payload->pk_data = silc_pkcs_public_key_encode(public_key, &pk_len);
389     if (!payload->pk_data) {
390       silc_mp_uninit(x);
391       silc_free(x);
392       silc_mp_uninit(&payload->x);
393       silc_free(payload);
394       ske->ke1_payload = NULL;
395       ske->status = SILC_SKE_STATUS_OK;
396       return ske->status;
397     }
398     payload->pk_len = pk_len;
399   }
400   payload->pk_type = pk_type;
401
402   /* Compute signature data if we are doing mutual authentication */
403   if (private_key && ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
404     unsigned char hash[32], sign[2048 + 1];
405     SilcUInt32 hash_len, sign_len;
406
407     SILC_LOG_DEBUG(("We are doing mutual authentication"));
408     SILC_LOG_DEBUG(("Computing HASH_i value"));
409
410     /* Compute the hash value */
411     memset(hash, 0, sizeof(hash));
412     silc_ske_make_hash(ske, hash, &hash_len, TRUE);
413
414     SILC_LOG_DEBUG(("Signing HASH_i value"));
415     
416     /* Sign the hash value */
417     silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
418                                    private_key->prv_len);
419     if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
420         !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
421       silc_mp_uninit(x);
422       silc_free(x);
423       silc_mp_uninit(&payload->x);
424       silc_free(payload->pk_data);
425       silc_free(payload);
426       ske->ke1_payload = NULL;
427       ske->status = SILC_SKE_STATUS_SIGNATURE_ERROR;
428       return ske->status;
429     }
430     payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
431     memcpy(payload->sign_data, sign, sign_len);
432     memset(sign, 0, sizeof(sign));
433     payload->sign_len = sign_len;
434   }
435
436   status = silc_ske_payload_ke_encode(ske, payload, &payload_buf);
437   if (status != SILC_SKE_STATUS_OK) {
438     silc_mp_uninit(x);
439     silc_free(x);
440     silc_mp_uninit(&payload->x);
441     silc_free(payload->pk_data);
442     silc_free(payload->sign_data);
443     silc_free(payload);
444     ske->ke1_payload = NULL;
445     ske->status = status;
446     return status;
447   }
448
449   ske->x = x;
450
451   /* Send the packet. */
452   if (ske->callbacks->send_packet)
453     (*ske->callbacks->send_packet)(ske, payload_buf, 
454                                    SILC_PACKET_KEY_EXCHANGE_1, 
455                                    ske->callbacks->context);
456
457   silc_buffer_free(payload_buf);
458
459   return status;
460 }
461
462 /* An initiator finish final callback that is called to indicate that
463    the SKE protocol may continue. */
464
465 static void silc_ske_initiator_finish_final(SilcSKE ske,
466                                             SilcSKEStatus status,
467                                             void *context)
468 {
469   SilcSKEKEPayload *payload;
470   unsigned char hash[32];
471   SilcUInt32 hash_len;
472   SilcPublicKey public_key = NULL;
473
474   /* If the SKE was freed during the async call then free it really now,
475      otherwise just decrement the reference counter. */
476   if (ske->status == SILC_SKE_STATUS_FREED) {
477     silc_ske_free(ske);
478     return;
479   }
480
481   /* If the caller returns PENDING status SKE library will assume that
482      the caller will re-call this callback when it is not anymore in
483      PENDING status. */
484   if (status == SILC_SKE_STATUS_PENDING)
485     return;
486
487   ske->users--;
488   payload = ske->ke2_payload;
489
490   /* If the status is an error then the public key that was verified
491      by the caller is not authentic. */
492   if (status != SILC_SKE_STATUS_OK) {
493     ske->status = status;
494     if (ske->callbacks->proto_continue)
495       ske->callbacks->proto_continue(ske, ske->callbacks->context);
496     return;
497   }
498
499   if (payload->pk_data) {
500     /* Decode the public key */
501     if (!silc_pkcs_public_key_decode(payload->pk_data, payload->pk_len, 
502                                      &public_key)) {
503       status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
504       SILC_LOG_ERROR(("Unsupported/malformed public key received"));
505       if (ske->callbacks->proto_continue)
506         ske->callbacks->proto_continue(ske, ske->callbacks->context);
507       return;
508     }
509
510     SILC_LOG_DEBUG(("Public key is authentic"));
511
512     /* Compute the hash value */
513     status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
514     if (status != SILC_SKE_STATUS_OK)
515       goto err;
516
517     ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
518     memcpy(ske->hash, hash, hash_len);
519     ske->hash_len = hash_len;
520
521     SILC_LOG_DEBUG(("Verifying signature (HASH)"));
522
523     /* Verify signature */
524     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
525     if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data, 
526                          payload->sign_len, hash, hash_len) == FALSE) {
527       SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
528       status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
529       goto err;
530     }
531
532     SILC_LOG_DEBUG(("Signature is Ok"));
533     
534     silc_pkcs_public_key_free(public_key);
535     memset(hash, 'F', hash_len);
536   }
537
538   ske->status = SILC_SKE_STATUS_OK;
539
540   /* Call the callback. The caller may now continue the SKE protocol. */
541   if (ske->callbacks->proto_continue)
542     ske->callbacks->proto_continue(ske, ske->callbacks->context);
543
544   return;
545
546  err:
547   memset(hash, 'F', sizeof(hash));
548   silc_ske_payload_ke_free(payload);
549   ske->ke2_payload = NULL;
550
551   silc_mp_uninit(ske->KEY);
552   silc_free(ske->KEY);
553   ske->KEY = NULL;
554
555   if (public_key)
556     silc_pkcs_public_key_free(public_key);
557
558   if (ske->hash) {
559     memset(ske->hash, 'F', hash_len);
560     silc_free(ske->hash);
561     ske->hash = NULL;
562   }
563
564   if (status == SILC_SKE_STATUS_OK)
565     ske->status = SILC_SKE_STATUS_ERROR;
566
567   ske->status = status;
568
569   /* Call the callback. */
570   if (ske->callbacks->proto_continue)
571     ske->callbacks->proto_continue(ske, ske->callbacks->context);
572 }
573
574 /* Receives Key Exchange Payload from responder consisting responders
575    public key, f, and signature. This function verifies the public key,
576    computes the secret shared key and verifies the signature. 
577
578    The `proto_continue' will be called to indicate that the caller may
579    continue with the SKE protocol.  The caller must not continue
580    before the SKE libary has called that callback.  If this function
581    returns an error the callback will not be called.  It is called
582    if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
583    However, note that when the library calls the callback the ske->status
584    may be error.
585
586    This calls the `verify_key' callback to verify the received public
587    key or certificate. If the `verify_key' is provided then the remote
588    must send public key and it is considered to be an error if remote 
589    does not send its public key. If caller is performing a re-key with
590    SKE then the `verify_key' is usually not provided when it is not also
591    required for the remote to send its public key. */
592
593 SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske,
594                                         SilcBuffer ke_payload)
595 {
596   SilcSKEStatus status = SILC_SKE_STATUS_OK;
597   SilcSKEKEPayload *payload;
598   SilcMPInt *KEY;
599
600   SILC_LOG_DEBUG(("Start"));
601
602   /* Decode the payload */
603   status = silc_ske_payload_ke_decode(ske, ke_payload, &payload);
604   if (status != SILC_SKE_STATUS_OK) {
605     ske->status = status;
606     return status;
607   }
608   ske->ke2_payload = payload;
609
610   if (!payload->pk_data && ske->callbacks->verify_key) {
611     SILC_LOG_DEBUG(("Remote end did not send its public key (or certificate), "
612                     "even though we require it"));
613     ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
614     goto err;
615   }
616
617   SILC_LOG_DEBUG(("Computing KEY = f ^ x mod p"));
618
619   /* Compute the shared secret key */
620   KEY = silc_calloc(1, sizeof(*KEY));
621   silc_mp_init(KEY);
622   silc_mp_pow_mod(KEY, &payload->x, ske->x, &ske->prop->group->group);
623   ske->KEY = KEY;
624
625   if (payload->pk_data && ske->callbacks->verify_key) {
626     SILC_LOG_DEBUG(("Verifying public key"));
627     
628     ske->users++;
629     (*ske->callbacks->verify_key)(ske, payload->pk_data, payload->pk_len,
630                                  payload->pk_type, ske->callbacks->context,
631                                  silc_ske_initiator_finish_final, NULL);
632     
633     /* We will continue to the final state after the public key has
634        been verified by the caller. */
635     return SILC_SKE_STATUS_PENDING;
636   }
637
638   /* Continue to final state */
639   ske->users++;
640   silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
641
642   return SILC_SKE_STATUS_OK;
643
644  err:
645   silc_ske_payload_ke_free(payload);
646   ske->ke2_payload = NULL;
647
648   silc_mp_uninit(ske->KEY);
649   silc_free(ske->KEY);
650   ske->KEY = NULL;
651
652   if (status == SILC_SKE_STATUS_OK)
653     return SILC_SKE_STATUS_ERROR;
654
655   ske->status = status;
656   return status;
657 }
658
659 /* Starts Key Exchange protocol for responder. Responder receives
660    Key Exchange Start Payload from initiator consisting of all the
661    security properties the initiator supports. This function decodes
662    the payload and parses the payload further and selects the right 
663    security properties. */
664
665 SilcSKEStatus silc_ske_responder_start(SilcSKE ske, SilcRng rng,
666                                        SilcSocketConnection sock,
667                                        const char *version,
668                                        SilcBuffer start_payload,
669                                        SilcSKESecurityPropertyFlag flags)
670 {
671   SilcSKEStatus status = SILC_SKE_STATUS_OK;
672   SilcSKEStartPayload *remote_payload = NULL, *payload = NULL;
673
674   SILC_LOG_DEBUG(("Start"));
675
676   ske->sock = sock;
677   ske->rng = rng;
678
679   /* Decode the payload */
680   status = silc_ske_payload_start_decode(ske, start_payload, &remote_payload);
681   if (status != SILC_SKE_STATUS_OK) {
682     ske->status = status;
683     return status;
684   }
685
686   /* Take a copy of the payload buffer for future use. It is used to
687      compute the HASH value. */
688   ske->start_payload_copy = silc_buffer_copy(start_payload);
689
690   /* Force the mutual authentication flag if we want to do it. */
691   if (flags & SILC_SKE_SP_FLAG_MUTUAL) {
692     SILC_LOG_DEBUG(("Force mutual authentication"));
693     remote_payload->flags |= SILC_SKE_SP_FLAG_MUTUAL;
694   }
695
696   /* Force PFS flag if we require it */
697   if (flags & SILC_SKE_SP_FLAG_PFS) {
698     SILC_LOG_DEBUG(("Force PFS"));
699     remote_payload->flags |= SILC_SKE_SP_FLAG_PFS;
700   }
701
702   /* Disable IV Included flag if requested */
703   if (remote_payload->flags & SILC_SKE_SP_FLAG_IV_INCLUDED &&
704       !(flags & SILC_SKE_SP_FLAG_IV_INCLUDED)) {
705     SILC_LOG_DEBUG(("We do not support IV Included flag"));
706     remote_payload->flags &= ~SILC_SKE_SP_FLAG_IV_INCLUDED;
707   }
708
709   /* Parse and select the security properties from the payload */
710   payload = silc_calloc(1, sizeof(*payload));
711   status = silc_ske_select_security_properties(ske, version,
712                                                payload, remote_payload);
713   if (status != SILC_SKE_STATUS_OK)
714     goto err;
715
716   ske->start_payload = payload;
717
718   /* Call the callback function. */
719   if (ske->callbacks->payload_receive)
720     (*ske->callbacks->payload_receive)(ske, ske->callbacks->context);
721
722   silc_ske_payload_start_free(remote_payload);
723
724   return status;
725
726  err:
727   if (remote_payload)
728     silc_ske_payload_start_free(remote_payload);
729   if (payload)
730     silc_free(payload);
731
732   if (status == SILC_SKE_STATUS_OK)
733     return SILC_SKE_STATUS_ERROR;
734
735   ske->status = status;
736   return status;
737 }
738
739 /* The selected security properties from the initiator payload is now 
740    encoded into Key Exchange Start Payload and sent to the initiator. */
741
742 SilcSKEStatus silc_ske_responder_phase_1(SilcSKE ske)
743 {
744   SilcSKEStatus status = SILC_SKE_STATUS_OK;
745   SilcBuffer payload_buf;
746   SilcSKESecurityProperties prop;
747   SilcSKEDiffieHellmanGroup group = NULL;
748
749   SILC_LOG_DEBUG(("Start"));
750
751   /* Allocate security properties from the payload. These are allocated
752      only for this negotiation and will be free'd after KE is over. */
753   ske->prop = prop = silc_calloc(1, sizeof(*prop));
754   prop->flags = ske->start_payload->flags;
755   status = silc_ske_group_get_by_name(ske->start_payload->ke_grp_list, &group);
756   if (status != SILC_SKE_STATUS_OK)
757     goto err;
758
759   prop->group = group;
760
761   if (silc_pkcs_alloc(ske->start_payload->pkcs_alg_list, 
762                       &prop->pkcs) == FALSE) {
763     status = SILC_SKE_STATUS_UNKNOWN_PKCS;
764     goto err;
765   }
766
767   if (silc_cipher_alloc(ske->start_payload->enc_alg_list, 
768                         &prop->cipher) == FALSE) {
769     status = SILC_SKE_STATUS_UNKNOWN_CIPHER;
770     goto err;
771   }
772
773   if (silc_hash_alloc(ske->start_payload->hash_alg_list,
774                       &prop->hash) == FALSE) {
775     status = SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
776     goto err;
777   }
778
779   if (silc_hmac_alloc(ske->start_payload->hmac_alg_list, NULL,
780                       &prop->hmac) == FALSE) {
781     status = SILC_SKE_STATUS_UNKNOWN_HMAC;
782     goto err;
783   }
784
785   /* Encode the payload */
786   status = silc_ske_payload_start_encode(ske, ske->start_payload, 
787                                          &payload_buf);
788   if (status != SILC_SKE_STATUS_OK)
789     goto err;
790
791   /* Send the packet. */
792   if (ske->callbacks->send_packet)
793     (*ske->callbacks->send_packet)(ske, payload_buf, SILC_PACKET_KEY_EXCHANGE, 
794                                    ske->callbacks->context);
795
796   silc_buffer_free(payload_buf);
797
798   return status;
799
800  err:
801   if (group)
802     silc_ske_group_free(group);
803
804   if (prop->pkcs)
805     silc_pkcs_free(prop->pkcs);
806   if (prop->cipher)
807     silc_cipher_free(prop->cipher);
808   if (prop->hash)
809     silc_hash_free(prop->hash);
810   if (prop->hmac)
811     silc_hmac_free(prop->hmac);
812   silc_free(prop);
813   ske->prop = NULL;
814
815   if (status == SILC_SKE_STATUS_OK)
816     return SILC_SKE_STATUS_ERROR;
817
818   ske->status = status;
819   return status;
820 }
821
822 /* An responder phase 2 final callback that is called to indicate that
823    the SKE protocol may continue. */
824
825 static void silc_ske_responder_phase2_final(SilcSKE ske,
826                                             SilcSKEStatus status,
827                                             void *context)
828 {
829   SilcSKEKEPayload *recv_payload, *send_payload;
830   SilcMPInt *x;
831
832   /* If the SKE was freed during the async call then free it really now,
833      otherwise just decrement the reference counter. */
834   if (ske->status == SILC_SKE_STATUS_FREED) {
835     silc_ske_free(ske);
836     return;
837   }
838
839   /* If the caller returns PENDING status SKE library will assume that
840      the caller will re-call this callback when it is not anymore in
841      PENDING status. */
842   if (status == SILC_SKE_STATUS_PENDING)
843     return;
844
845   ske->users--;
846   recv_payload = ske->ke1_payload;
847
848   /* If the status is an error then the public key that was verified
849      by the caller is not authentic. */
850   if (status != SILC_SKE_STATUS_OK) {
851     ske->status = status;
852     if (ske->callbacks->proto_continue)
853       ske->callbacks->proto_continue(ske, ske->callbacks->context);
854     return;
855   }
856
857   /* The public key verification was performed only if the Mutual
858      Authentication flag is set. */
859   if (ske->start_payload && 
860       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
861     SilcPublicKey public_key = NULL;
862     unsigned char hash[32];
863     SilcUInt32 hash_len;
864
865     /* Decode the public key */
866     if (!silc_pkcs_public_key_decode(recv_payload->pk_data, 
867                                      recv_payload->pk_len, 
868                                      &public_key)) {
869       ske->status = SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY;
870       SILC_LOG_ERROR(("Unsupported/malformed public key received"));
871       if (ske->callbacks->proto_continue)
872         ske->callbacks->proto_continue(ske, ske->callbacks->context);
873       return;
874     }
875
876     SILC_LOG_DEBUG(("Public key is authentic"));
877
878     /* Compute the hash value */
879     status = silc_ske_make_hash(ske, hash, &hash_len, TRUE);
880     if (status != SILC_SKE_STATUS_OK) {
881       ske->status = status;
882       if (ske->callbacks->proto_continue)
883         ske->callbacks->proto_continue(ske, ske->callbacks->context);
884       return;
885     }
886
887     SILC_LOG_DEBUG(("Verifying signature (HASH_i)"));
888     
889     /* Verify signature */
890     silc_pkcs_public_key_set(ske->prop->pkcs, public_key);
891     if (silc_pkcs_verify(ske->prop->pkcs, recv_payload->sign_data, 
892                          recv_payload->sign_len, hash, hash_len) == FALSE) {
893       SILC_LOG_ERROR(("Signature verification failed, incorrect signature"));
894       ske->status = SILC_SKE_STATUS_INCORRECT_SIGNATURE;
895       if (ske->callbacks->proto_continue)
896         ske->callbacks->proto_continue(ske, ske->callbacks->context);
897       return;
898     }
899     
900     SILC_LOG_DEBUG(("Signature is Ok"));
901     
902     silc_pkcs_public_key_free(public_key);
903     memset(hash, 'F', hash_len);
904   }
905
906   /* Create the random number x, 1 < x < q. */
907   x = silc_calloc(1, sizeof(*x));
908   silc_mp_init(x);
909   status = 
910     silc_ske_create_rnd(ske, &ske->prop->group->group_order,
911                         silc_mp_sizeinbase(&ske->prop->group->group_order, 2),
912                         x);
913   if (status != SILC_SKE_STATUS_OK) {
914     silc_mp_uninit(x);
915     silc_free(x);
916     ske->status = status;
917     if (ske->callbacks->proto_continue)
918       ske->callbacks->proto_continue(ske, ske->callbacks->context);
919     return;
920   }
921
922   /* Save the results for later processing */
923   send_payload = silc_calloc(1, sizeof(*send_payload));
924   ske->x = x;
925   ske->ke2_payload = send_payload;
926
927   SILC_LOG_DEBUG(("Computing f = g ^ x mod p"));
928
929   /* Do the Diffie Hellman computation, f = g ^ x mod p */
930   silc_mp_init(&send_payload->x);
931   silc_mp_pow_mod(&send_payload->x, &ske->prop->group->generator, x, 
932                   &ske->prop->group->group);
933   
934   /* Call the callback. The caller may now continue with the SKE protocol. */
935   ske->status = SILC_SKE_STATUS_OK;
936   if (ske->callbacks->proto_continue)
937     ske->callbacks->proto_continue(ske, ske->callbacks->context);
938 }
939
940 /* This function receives the Key Exchange Payload from the initiator.
941    This also performs the mutual authentication if required. Then, this 
942    function first generated a random number x, such that 1 < x < q
943    and computes f = g ^ x mod p. This then puts the result f to a Key
944    Exchange Payload. 
945
946    The `proto_continue' will be called to indicate that the caller may
947    continue with the SKE protocol.  The caller must not continue
948    before the SKE libary has called that callback.  If this function
949    returns an error the callback will not be called.  It is called
950    if this function return SILC_SKE_STATUS_OK or SILC_SKE_STATUS_PENDING.
951    However, note that when the library calls the callback the ske->status
952    may be error.
953
954    This calls the `verify_key' callback to verify the received public
955    key or certificate if the Mutual Authentication flag is set. If the
956    `verify_key' is provided then the remote must send public key and it
957    is considered to be an error if remote does not send its public key. */
958
959 SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske,
960                                          SilcBuffer ke_payload)
961 {
962   SilcSKEStatus status = SILC_SKE_STATUS_OK;
963   SilcSKEKEPayload *recv_payload;
964
965   SILC_LOG_DEBUG(("Start"));
966
967   /* Decode Key Exchange Payload */
968   status = silc_ske_payload_ke_decode(ske, ke_payload, &recv_payload);
969   if (status != SILC_SKE_STATUS_OK) {
970     ske->status = status;
971     return status;
972   }
973
974   ske->ke1_payload = recv_payload;
975
976   /* Verify the received public key and verify the signature if we are
977      doing mutual authentication. */
978   if (ske->start_payload && 
979       ske->start_payload->flags & SILC_SKE_SP_FLAG_MUTUAL) {
980
981     SILC_LOG_DEBUG(("We are doing mutual authentication"));
982     
983     if (!recv_payload->pk_data && ske->callbacks->verify_key) {
984       SILC_LOG_ERROR(("Remote end did not send its public key (or "
985                       "certificate), even though we require it"));
986       ske->status = SILC_SKE_STATUS_PUBLIC_KEY_NOT_PROVIDED;
987       return status;
988     }
989
990     if (recv_payload->pk_data && ske->callbacks->verify_key) {
991       SILC_LOG_DEBUG(("Verifying public key"));
992
993       ske->users++;
994       (*ske->callbacks->verify_key)(ske, recv_payload->pk_data, 
995                                     recv_payload->pk_len,
996                                     recv_payload->pk_type, 
997                                     ske->callbacks->context,
998                                     silc_ske_responder_phase2_final, NULL);
999
1000       /* We will continue to the final state after the public key has
1001          been verified by the caller. */
1002       return SILC_SKE_STATUS_PENDING;
1003     }
1004   }
1005
1006   /* Continue to final state */
1007   ske->users++;
1008   silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
1009
1010   return SILC_SKE_STATUS_OK;
1011 }
1012
1013 /* This functions generates the secret key KEY = e ^ x mod p, and, a hash
1014    value to be signed and sent to the other end. This then encodes Key
1015    Exchange Payload and sends it to the other end. */
1016
1017 SilcSKEStatus silc_ske_responder_finish(SilcSKE ske,
1018                                         SilcPublicKey public_key,
1019                                         SilcPrivateKey private_key,
1020                                         SilcSKEPKType pk_type)
1021 {
1022   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1023   SilcBuffer payload_buf;
1024   SilcMPInt *KEY;
1025   unsigned char hash[32], sign[2048 + 1], *pk;
1026   SilcUInt32 hash_len, sign_len, pk_len;
1027
1028   SILC_LOG_DEBUG(("Start"));
1029
1030   SILC_LOG_DEBUG(("Computing KEY = e ^ x mod p"));
1031
1032   /* Compute the shared secret key */
1033   KEY = silc_calloc(1, sizeof(*KEY));
1034   silc_mp_init(KEY);
1035   silc_mp_pow_mod(KEY, &ske->ke1_payload->x, ske->x, 
1036                   &ske->prop->group->group);
1037   ske->KEY = KEY;
1038
1039   if (public_key && private_key) {
1040     SILC_LOG_DEBUG(("Getting public key"));
1041     
1042     /* Get the public key */
1043     pk = silc_pkcs_public_key_encode(public_key, &pk_len);
1044     if (!pk) {
1045       status = SILC_SKE_STATUS_OUT_OF_MEMORY;
1046       goto err;
1047     }
1048     ske->ke2_payload->pk_data = pk;
1049     ske->ke2_payload->pk_len = pk_len;
1050     
1051     SILC_LOG_DEBUG(("Computing HASH value"));
1052     
1053     /* Compute the hash value */
1054     memset(hash, 0, sizeof(hash));
1055     status = silc_ske_make_hash(ske, hash, &hash_len, FALSE);
1056     if (status != SILC_SKE_STATUS_OK)
1057       goto err;
1058
1059     ske->hash = silc_calloc(hash_len, sizeof(unsigned char));
1060     memcpy(ske->hash, hash, hash_len);
1061     ske->hash_len = hash_len;
1062     
1063     SILC_LOG_DEBUG(("Signing HASH value"));
1064     
1065     /* Sign the hash value */
1066     silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv, 
1067                                    private_key->prv_len);
1068     if (silc_pkcs_get_key_len(ske->prop->pkcs) / 8 > sizeof(sign) - 1 ||
1069         !silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len)) {
1070       status = SILC_SKE_STATUS_SIGNATURE_ERROR;
1071       goto err;
1072     }
1073     ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
1074     memcpy(ske->ke2_payload->sign_data, sign, sign_len);
1075     memset(sign, 0, sizeof(sign));
1076     ske->ke2_payload->sign_len = sign_len;
1077   }
1078   ske->ke2_payload->pk_type = pk_type;
1079
1080   /* Encode the Key Exchange Payload */
1081   status = silc_ske_payload_ke_encode(ske, ske->ke2_payload,
1082                                       &payload_buf);
1083   if (status != SILC_SKE_STATUS_OK)
1084     goto err;
1085
1086   /* Send the packet. */
1087   if (ske->callbacks->send_packet)
1088     (*ske->callbacks->send_packet)(ske, payload_buf, 
1089                                    SILC_PACKET_KEY_EXCHANGE_2,
1090                                    ske->callbacks->context);
1091
1092   silc_buffer_free(payload_buf);
1093
1094   return status;
1095
1096  err:
1097   silc_mp_uninit(ske->KEY);
1098   silc_free(ske->KEY);
1099   ske->KEY = NULL;
1100   silc_ske_payload_ke_free(ske->ke2_payload);
1101
1102   if (status == SILC_SKE_STATUS_OK)
1103     return SILC_SKE_STATUS_ERROR;
1104
1105   ske->status = status;
1106   return status;
1107 }
1108
1109 /* The Key Exchange protocol is ended by calling this function. This
1110    must not be called until the keys are processed like the protocol
1111    defines. This function is for both initiator and responder. */
1112
1113 SilcSKEStatus silc_ske_end(SilcSKE ske)
1114 {
1115   SilcBuffer packet;
1116
1117   SILC_LOG_DEBUG(("Start"));
1118
1119   packet = silc_buffer_alloc_size(4);
1120   if (!packet)
1121     return SILC_SKE_STATUS_OUT_OF_MEMORY;
1122   silc_buffer_format(packet,
1123                      SILC_STR_UI_INT((SilcUInt32)SILC_SKE_STATUS_OK),
1124                      SILC_STR_END);
1125
1126   if (ske->callbacks->send_packet)
1127     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_SUCCESS, 
1128                                    ske->callbacks->context);
1129
1130   silc_buffer_free(packet);
1131
1132   return SILC_SKE_STATUS_OK;
1133 }
1134
1135 /* Aborts the Key Exchange protocol. This is called if error occurs
1136    while performing the protocol. The status argument is the error
1137    status and it is sent to the remote end. */
1138
1139 SilcSKEStatus silc_ske_abort(SilcSKE ske, SilcSKEStatus status)
1140 {
1141   SilcBuffer packet;
1142
1143   SILC_LOG_DEBUG(("Start"));
1144
1145   if (status > SILC_SKE_STATUS_INVALID_COOKIE)
1146     status = SILC_SKE_STATUS_BAD_PAYLOAD;
1147
1148   packet = silc_buffer_alloc_size(4);
1149   if (!packet)
1150     return SILC_SKE_STATUS_OUT_OF_MEMORY;
1151   silc_buffer_format(packet,
1152                      SILC_STR_UI_INT((SilcUInt32)status),
1153                      SILC_STR_END);
1154
1155   if (ske->callbacks->send_packet)
1156     (*ske->callbacks->send_packet)(ske, packet, SILC_PACKET_FAILURE, 
1157                                    ske->callbacks->context);
1158
1159   silc_buffer_free(packet);
1160
1161   return SILC_SKE_STATUS_OK;
1162 }
1163
1164 /* Assembles security properties to Key Exchange Start Payload to be
1165    sent to the remote end. This checks system wide (SILC system, that is)
1166    settings and chooses from those. However, if other properties
1167    should be used this function is easy to replace by another function,
1168    as, this function is called by the caller of the protocol and not
1169    by the protocol itself. */
1170
1171 SilcSKEStatus 
1172 silc_ske_assemble_security_properties(SilcSKE ske,
1173                                       SilcSKESecurityPropertyFlag flags,
1174                                       const char *version,
1175                                       SilcSKEStartPayload **return_payload)
1176 {
1177   SilcSKEStartPayload *rp;
1178   int i;
1179
1180   SILC_LOG_DEBUG(("Assembling KE Start Payload"));
1181
1182   rp = silc_calloc(1, sizeof(*rp));
1183
1184   /* Set flags */
1185   rp->flags = (unsigned char)flags;
1186
1187   /* Set random cookie */
1188   rp->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(*rp->cookie));
1189   for (i = 0; i < SILC_SKE_COOKIE_LEN; i++)
1190     rp->cookie[i] = silc_rng_get_byte_fast(ske->rng);
1191   rp->cookie_len = SILC_SKE_COOKIE_LEN;
1192
1193   /* Put version */
1194   rp->version = strdup(version);
1195   rp->version_len = strlen(version);
1196
1197   /* Get supported Key Exhange groups */
1198   rp->ke_grp_list = silc_ske_get_supported_groups();
1199   rp->ke_grp_len = strlen(rp->ke_grp_list);
1200
1201   /* Get supported PKCS algorithms */
1202   rp->pkcs_alg_list = silc_pkcs_get_supported();
1203   rp->pkcs_alg_len = strlen(rp->pkcs_alg_list);
1204
1205   /* Get supported encryption algorithms */
1206   rp->enc_alg_list = silc_cipher_get_supported();
1207   rp->enc_alg_len = strlen(rp->enc_alg_list);
1208
1209   /* Get supported hash algorithms */
1210   rp->hash_alg_list = silc_hash_get_supported();
1211   rp->hash_alg_len = strlen(rp->hash_alg_list);
1212
1213   /* Get supported HMACs */
1214   rp->hmac_alg_list = silc_hmac_get_supported();
1215   rp->hmac_alg_len = strlen(rp->hmac_alg_list);
1216
1217   /* XXX */
1218   /* Get supported compression algorithms */
1219   rp->comp_alg_list = strdup("none");
1220   rp->comp_alg_len = strlen("none");
1221
1222   rp->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1223     2 + rp->version_len +
1224     2 + rp->ke_grp_len + 2 + rp->pkcs_alg_len + 
1225     2 + rp->enc_alg_len + 2 + rp->hash_alg_len + 
1226     2 + rp->hmac_alg_len + 2 + rp->comp_alg_len;
1227
1228   *return_payload = rp;
1229
1230   return SILC_SKE_STATUS_OK;
1231 }
1232
1233 /* Selects the supported security properties from the remote end's Key 
1234    Exchange Start Payload. */
1235
1236 SilcSKEStatus 
1237 silc_ske_select_security_properties(SilcSKE ske,
1238                                     const char *version,
1239                                     SilcSKEStartPayload *payload,
1240                                     SilcSKEStartPayload *remote_payload)
1241 {
1242   SilcSKEStatus status;
1243   SilcSKEStartPayload *rp;
1244   char *cp;
1245   int len;
1246
1247   SILC_LOG_DEBUG(("Parsing KE Start Payload"));
1248
1249   rp = remote_payload;
1250
1251   /* Check version string */
1252   if (ske->callbacks->check_version) {
1253     status = ske->callbacks->check_version(ske, rp->version, 
1254                                            rp->version_len,
1255                                            ske->callbacks->context);
1256     if (status != SILC_SKE_STATUS_OK) {
1257       ske->status = status;
1258       return status;
1259     }
1260   }
1261
1262   ske->remote_version = silc_memdup(rp->version, rp->version_len);
1263
1264   /* Flags are returned unchanged. */
1265   payload->flags = rp->flags;
1266
1267   /* Take cookie, we must return it to sender unmodified. */
1268   payload->cookie = silc_calloc(SILC_SKE_COOKIE_LEN, sizeof(unsigned char));
1269   payload->cookie_len = SILC_SKE_COOKIE_LEN;
1270   memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
1271
1272   /* Put our version to our reply */
1273   payload->version = strdup(version);
1274   payload->version_len = strlen(version);
1275
1276   /* Get supported Key Exchange groups */
1277   cp = rp->ke_grp_list;
1278   if (cp && strchr(cp, ',')) {
1279     while(cp) {
1280       char *item;
1281
1282       len = strcspn(cp, ",");
1283       item = silc_calloc(len + 1, sizeof(char));
1284       memcpy(item, cp, len);
1285
1286       SILC_LOG_DEBUG(("Proposed KE group `%s'", item));
1287
1288       if (silc_ske_group_get_by_name(item, NULL) == SILC_SKE_STATUS_OK) {
1289         SILC_LOG_DEBUG(("Found KE group `%s'", item));
1290
1291         payload->ke_grp_len = len;
1292         payload->ke_grp_list = item;
1293         break;
1294       }
1295
1296       cp += len;
1297       if (strlen(cp) == 0)
1298         cp = NULL;
1299       else
1300         cp++;
1301
1302       if (item)
1303         silc_free(item);
1304     }
1305
1306     if (!payload->ke_grp_len && !payload->ke_grp_list) {
1307       SILC_LOG_DEBUG(("Could not find supported KE group"));
1308       silc_free(payload);
1309       return SILC_SKE_STATUS_UNKNOWN_GROUP;
1310     }
1311   } else {
1312
1313     if (!rp->ke_grp_len) {
1314       SILC_LOG_DEBUG(("KE group not defined in payload"));
1315       silc_free(payload);
1316       return SILC_SKE_STATUS_BAD_PAYLOAD;
1317     }
1318
1319     SILC_LOG_DEBUG(("Proposed KE group `%s'", rp->ke_grp_list));
1320     SILC_LOG_DEBUG(("Found KE group `%s'", rp->ke_grp_list));
1321
1322     payload->ke_grp_len = rp->ke_grp_len;
1323     payload->ke_grp_list = strdup(rp->ke_grp_list);
1324   }
1325
1326   /* Get supported PKCS algorithms */
1327   cp = rp->pkcs_alg_list;
1328   if (cp && strchr(cp, ',')) {
1329     while(cp) {
1330       char *item;
1331
1332       len = strcspn(cp, ",");
1333       item = silc_calloc(len + 1, sizeof(char));
1334       memcpy(item, cp, len);
1335
1336       SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", item));
1337
1338       if (silc_pkcs_is_supported(item) == TRUE) {
1339         SILC_LOG_DEBUG(("Found PKCS alg `%s'", item));
1340
1341         payload->pkcs_alg_len = len;
1342         payload->pkcs_alg_list = item;
1343         break;
1344       }
1345
1346       cp += len;
1347       if (strlen(cp) == 0)
1348         cp = NULL;
1349       else
1350         cp++;
1351
1352       if (item)
1353         silc_free(item);
1354     }
1355
1356     if (!payload->pkcs_alg_len && !payload->pkcs_alg_list) {
1357       SILC_LOG_DEBUG(("Could not find supported PKCS alg"));
1358       silc_free(payload->ke_grp_list);
1359       silc_free(payload);
1360       return SILC_SKE_STATUS_UNKNOWN_PKCS;
1361     }
1362   } else {
1363
1364     if (!rp->pkcs_alg_len) {
1365       SILC_LOG_DEBUG(("PKCS alg not defined in payload"));
1366       silc_free(payload->ke_grp_list);
1367       silc_free(payload);
1368       return SILC_SKE_STATUS_BAD_PAYLOAD;
1369     }
1370
1371     SILC_LOG_DEBUG(("Proposed PKCS alg `%s'", rp->pkcs_alg_list));
1372     SILC_LOG_DEBUG(("Found PKCS alg `%s'", rp->pkcs_alg_list));
1373
1374     payload->pkcs_alg_len = rp->pkcs_alg_len;
1375     payload->pkcs_alg_list = strdup(rp->pkcs_alg_list);
1376   }
1377
1378   /* Get supported encryption algorithms */
1379   cp = rp->enc_alg_list;
1380   if (cp && strchr(cp, ',')) {
1381     while(cp) {
1382       char *item;
1383
1384       len = strcspn(cp, ",");
1385       item = silc_calloc(len + 1, sizeof(char));
1386       memcpy(item, cp, len);
1387
1388       SILC_LOG_DEBUG(("Proposed encryption alg `%s'", item));
1389
1390       if (silc_cipher_is_supported(item) == TRUE) {
1391         SILC_LOG_DEBUG(("Found encryption alg `%s'", item));
1392
1393         payload->enc_alg_len = len;
1394         payload->enc_alg_list = item;
1395         break;
1396       }
1397
1398       cp += len;
1399       if (strlen(cp) == 0)
1400         cp = NULL;
1401       else
1402         cp++;
1403
1404       if (item)
1405         silc_free(item);
1406     }
1407
1408     if (!payload->enc_alg_len && !payload->enc_alg_list) {
1409       SILC_LOG_DEBUG(("Could not find supported encryption alg"));
1410       silc_free(payload->ke_grp_list);
1411       silc_free(payload->pkcs_alg_list);
1412       silc_free(payload);
1413       return SILC_SKE_STATUS_UNKNOWN_CIPHER;
1414     }
1415   } else {
1416
1417     if (!rp->enc_alg_len) {
1418       SILC_LOG_DEBUG(("Encryption alg not defined in payload"));
1419       silc_free(payload->ke_grp_list);
1420       silc_free(payload->pkcs_alg_list);
1421       silc_free(payload);
1422       return SILC_SKE_STATUS_BAD_PAYLOAD;
1423     }
1424
1425     SILC_LOG_DEBUG(("Proposed encryption alg `%s' and selected it",
1426                     rp->enc_alg_list));
1427
1428     payload->enc_alg_len = rp->enc_alg_len;
1429     payload->enc_alg_list = strdup(rp->enc_alg_list);
1430   }
1431
1432   /* Get supported hash algorithms */
1433   cp = rp->hash_alg_list;
1434   if (cp && strchr(cp, ',')) {
1435     while(cp) {
1436       char *item;
1437
1438       len = strcspn(cp, ",");
1439       item = silc_calloc(len + 1, sizeof(char));
1440       memcpy(item, cp, len);
1441
1442       SILC_LOG_DEBUG(("Proposed hash alg `%s'", item));
1443
1444       if (silc_hash_is_supported(item) == TRUE) {
1445         SILC_LOG_DEBUG(("Found hash alg `%s'", item));
1446
1447         payload->hash_alg_len = len;
1448         payload->hash_alg_list = item;
1449         break;
1450       }
1451
1452       cp += len;
1453       if (strlen(cp) == 0)
1454         cp = NULL;
1455       else
1456         cp++;
1457
1458       if (item)
1459         silc_free(item);
1460     }
1461
1462     if (!payload->hash_alg_len && !payload->hash_alg_list) {
1463       SILC_LOG_DEBUG(("Could not find supported hash alg"));
1464       silc_free(payload->ke_grp_list);
1465       silc_free(payload->pkcs_alg_list);
1466       silc_free(payload->enc_alg_list);
1467       silc_free(payload);
1468       return SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION;
1469     }
1470   } else {
1471
1472     if (!rp->hash_alg_len) {
1473       SILC_LOG_DEBUG(("Hash alg not defined in payload"));
1474       silc_free(payload->ke_grp_list);
1475       silc_free(payload->pkcs_alg_list);
1476       silc_free(payload->enc_alg_list);
1477       silc_free(payload);
1478       return SILC_SKE_STATUS_BAD_PAYLOAD;
1479     }
1480
1481     SILC_LOG_DEBUG(("Proposed hash alg `%s' and selected it",
1482                     rp->hash_alg_list));
1483
1484     payload->hash_alg_len = rp->hash_alg_len;
1485     payload->hash_alg_list = strdup(rp->hash_alg_list);
1486   }
1487
1488   /* Get supported HMACs */
1489   cp = rp->hmac_alg_list;
1490   if (cp && strchr(cp, ',')) {
1491     while(cp) {
1492       char *item;
1493
1494       len = strcspn(cp, ",");
1495       item = silc_calloc(len + 1, sizeof(char));
1496       memcpy(item, cp, len);
1497
1498       SILC_LOG_DEBUG(("Proposed HMAC `%s'", item));
1499
1500       if (silc_hmac_is_supported(item) == TRUE) {
1501         SILC_LOG_DEBUG(("Found HMAC `%s'", item));
1502
1503         payload->hmac_alg_len = len;
1504         payload->hmac_alg_list = item;
1505         break;
1506       }
1507
1508       cp += len;
1509       if (strlen(cp) == 0)
1510         cp = NULL;
1511       else
1512         cp++;
1513
1514       if (item)
1515         silc_free(item);
1516     }
1517
1518     if (!payload->hmac_alg_len && !payload->hmac_alg_list) {
1519       SILC_LOG_DEBUG(("Could not find supported HMAC"));
1520       silc_free(payload->ke_grp_list);
1521       silc_free(payload->pkcs_alg_list);
1522       silc_free(payload->enc_alg_list);
1523       silc_free(payload->hash_alg_list);
1524       silc_free(payload);
1525       return SILC_SKE_STATUS_UNKNOWN_HMAC;
1526     }
1527   } else {
1528
1529     if (!rp->hmac_alg_len) {
1530       SILC_LOG_DEBUG(("HMAC not defined in payload"));
1531       silc_free(payload->ke_grp_list);
1532       silc_free(payload->pkcs_alg_list);
1533       silc_free(payload->enc_alg_list);
1534       silc_free(payload->hash_alg_list);
1535       silc_free(payload);
1536       return SILC_SKE_STATUS_BAD_PAYLOAD;
1537     }
1538
1539     SILC_LOG_DEBUG(("Proposed HMAC `%s' and selected it",
1540                     rp->hmac_alg_list));
1541
1542     payload->hmac_alg_len = rp->hmac_alg_len;
1543     payload->hmac_alg_list = strdup(rp->hmac_alg_list);
1544   }
1545
1546   /* Get supported compression algorithms */
1547   cp = rp->comp_alg_list;
1548   if (cp && strchr(cp, ',')) {
1549     while(cp) {
1550       char *item;
1551
1552       len = strcspn(cp, ",");
1553       item = silc_calloc(len + 1, sizeof(char));
1554       memcpy(item, cp, len);
1555
1556       SILC_LOG_DEBUG(("Proposed Compression `%s'", item));
1557
1558 #if 1
1559       if (!strcmp(item, "none")) {
1560         SILC_LOG_DEBUG(("Found Compression `%s'", item));
1561         payload->comp_alg_len = len;
1562         payload->comp_alg_list = item;
1563         break;
1564       }
1565 #else
1566       if (silc_hmac_is_supported(item) == TRUE) {
1567         SILC_LOG_DEBUG(("Found Compression `%s'", item));
1568         payload->comp_alg_len = len;
1569         payload->comp_alg_list = item;
1570         break;
1571       }
1572 #endif
1573
1574       cp += len;
1575       if (strlen(cp) == 0)
1576         cp = NULL;
1577       else
1578         cp++;
1579
1580       if (item)
1581         silc_free(item);
1582     }
1583   }
1584
1585   payload->len = 1 + 1 + 2 + SILC_SKE_COOKIE_LEN + 
1586     2 + payload->version_len + 
1587     2 + payload->ke_grp_len + 2 + payload->pkcs_alg_len + 
1588     2 + payload->enc_alg_len + 2 + payload->hash_alg_len + 
1589     2 + payload->hmac_alg_len + 2 + payload->comp_alg_len;
1590
1591   return SILC_SKE_STATUS_OK;
1592 }
1593
1594 /* Creates random number such that 1 < rnd < n and at most length
1595    of len bits. The rnd sent as argument must be initialized. */
1596
1597 static SilcSKEStatus silc_ske_create_rnd(SilcSKE ske, SilcMPInt *n, 
1598                                          SilcUInt32 len, 
1599                                          SilcMPInt *rnd)
1600 {
1601   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1602   unsigned char *string;
1603   SilcUInt32 l;
1604
1605   if (!len)
1606     return SILC_SKE_STATUS_ERROR;
1607
1608   SILC_LOG_DEBUG(("Creating random number"));
1609
1610   l = ((len - 1) / 8);
1611
1612   /* Get the random number as string */
1613   string = silc_rng_get_rn_data(ske->rng, l);
1614   if (!string)
1615     return SILC_SKE_STATUS_OUT_OF_MEMORY;
1616
1617   /* Decode the string into a MP integer */
1618   silc_mp_bin2mp(string, l, rnd);
1619   silc_mp_mod_2exp(rnd, rnd, len);
1620
1621   /* Checks */
1622   if (silc_mp_cmp_ui(rnd, 1) < 0)
1623     status = SILC_SKE_STATUS_ERROR;
1624   if (silc_mp_cmp(rnd, n) >= 0)
1625     status = SILC_SKE_STATUS_ERROR;
1626
1627   memset(string, 'F', l);
1628   silc_free(string);
1629
1630   return status;
1631 }
1632
1633 /* Creates a hash value HASH as defined in the SKE protocol. If the
1634    `initiator' is TRUE then this function is used to create the HASH_i
1635    hash value defined in the protocol. If it is FALSE then this is used
1636    to create the HASH value defined by the protocol. */
1637
1638 static SilcSKEStatus silc_ske_make_hash(SilcSKE ske, 
1639                                         unsigned char *return_hash,
1640                                         SilcUInt32 *return_hash_len,
1641                                         int initiator)
1642 {
1643   SilcSKEStatus status = SILC_SKE_STATUS_OK;
1644   SilcBuffer buf;
1645   unsigned char *e, *f, *KEY;
1646   SilcUInt32 e_len, f_len, KEY_len;
1647   int ret;
1648
1649   SILC_LOG_DEBUG(("Start"));
1650
1651   if (initiator == FALSE) {
1652     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1653     f = silc_mp_mp2bin(&ske->ke2_payload->x, 0, &f_len);
1654     KEY = silc_mp_mp2bin(ske->KEY, 0, &KEY_len);
1655     
1656     /* Format the buffer used to compute the hash value */
1657     buf = silc_buffer_alloc_size(ske->start_payload_copy->len + 
1658                                  ske->ke2_payload->pk_len + 
1659                                  ske->ke1_payload->pk_len + 
1660                                  e_len + f_len + KEY_len);
1661     if (!buf)
1662       return SILC_SKE_STATUS_OUT_OF_MEMORY;
1663
1664     /* Initiator is not required to send its public key */
1665     if (!ske->ke1_payload->pk_data) {
1666       ret = 
1667         silc_buffer_format(buf,
1668                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1669                                                 data,
1670                                                 ske->start_payload_copy->
1671                                                 len),
1672                            SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1673                                                 ske->ke2_payload->pk_len),
1674                            SILC_STR_UI_XNSTRING(e, e_len),
1675                            SILC_STR_UI_XNSTRING(f, f_len),
1676                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
1677                            SILC_STR_END);
1678     } else {
1679       ret = 
1680         silc_buffer_format(buf,
1681                            SILC_STR_UI_XNSTRING(ske->start_payload_copy->
1682                                                 data,
1683                                                 ske->start_payload_copy->
1684                                                 len),
1685                            SILC_STR_UI_XNSTRING(ske->ke2_payload->pk_data, 
1686                                                 ske->ke2_payload->pk_len),
1687                            SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
1688                                                 ske->ke1_payload->pk_len),
1689                            SILC_STR_UI_XNSTRING(e, e_len),
1690                            SILC_STR_UI_XNSTRING(f, f_len),
1691                            SILC_STR_UI_XNSTRING(KEY, KEY_len),
1692                            SILC_STR_END);
1693     }
1694     if (ret == -1) {
1695       silc_buffer_free(buf);
1696       memset(e, 0, e_len);
1697       memset(f, 0, f_len);
1698       memset(KEY, 0, KEY_len);
1699       silc_free(e);
1700       silc_free(f);
1701       silc_free(KEY);
1702       return SILC_SKE_STATUS_ERROR;
1703     }
1704
1705     memset(e, 0, e_len);
1706     memset(f, 0, f_len);
1707     memset(KEY, 0, KEY_len);
1708     silc_free(e);
1709     silc_free(f);
1710     silc_free(KEY);
1711   } else {
1712     e = silc_mp_mp2bin(&ske->ke1_payload->x, 0, &e_len);
1713
1714     buf = silc_buffer_alloc_size(ske->start_payload_copy->len + 
1715                                   ske->ke1_payload->pk_len + e_len);
1716     if (!buf)
1717       return SILC_SKE_STATUS_OUT_OF_MEMORY;
1718     
1719     /* Format the buffer used to compute the hash value */
1720     ret = 
1721       silc_buffer_format(buf,
1722                          SILC_STR_UI_XNSTRING(ske->start_payload_copy->data,
1723                                               ske->start_payload_copy->len),
1724                          SILC_STR_UI_XNSTRING(ske->ke1_payload->pk_data, 
1725                                               ske->ke1_payload->pk_len),
1726                          SILC_STR_UI_XNSTRING(e, e_len),
1727                          SILC_STR_END);
1728     if (ret == -1) {
1729       silc_buffer_free(buf);
1730       memset(e, 0, e_len);
1731       silc_free(e);
1732       return SILC_SKE_STATUS_ERROR;
1733     }
1734
1735     memset(e, 0, e_len);
1736     silc_free(e);
1737   }
1738
1739   /* Make the hash */
1740   silc_hash_make(ske->prop->hash, buf->data, buf->len, return_hash);
1741   *return_hash_len = silc_hash_len(ske->prop->hash);
1742
1743   if (initiator == FALSE) {
1744     SILC_LOG_HEXDUMP(("HASH"), return_hash, *return_hash_len);
1745   } else {
1746     SILC_LOG_HEXDUMP(("HASH_i"), return_hash, *return_hash_len);
1747   }
1748
1749   silc_buffer_free(buf);
1750
1751   return status;
1752 }
1753
1754 /* Processes the provided key material `data' as the SILC protocol 
1755    specification defines. */
1756
1757 SilcSKEStatus 
1758 silc_ske_process_key_material_data(unsigned char *data,
1759                                    SilcUInt32 data_len,
1760                                    SilcUInt32 req_iv_len,
1761                                    SilcUInt32 req_enc_key_len,
1762                                    SilcUInt32 req_hmac_key_len,
1763                                    SilcHash hash,
1764                                    SilcSKEKeyMaterial *key)
1765 {
1766   SilcBuffer buf;
1767   unsigned char hashd[32];
1768   SilcUInt32 hash_len = req_hmac_key_len;
1769   SilcUInt32 enc_key_len = req_enc_key_len / 8;
1770
1771   SILC_LOG_DEBUG(("Start"));
1772
1773   if (!req_iv_len || !req_enc_key_len || !req_hmac_key_len)
1774     return SILC_SKE_STATUS_ERROR;
1775
1776   buf = silc_buffer_alloc_size(1 + data_len);
1777   if (!buf)
1778     return SILC_SKE_STATUS_OUT_OF_MEMORY;
1779   silc_buffer_format(buf,
1780                      SILC_STR_UI_CHAR(0),
1781                      SILC_STR_UI_XNSTRING(data, data_len),
1782                      SILC_STR_END);
1783
1784   /* Take IVs */
1785   memset(hashd, 0, sizeof(hashd));
1786   buf->data[0] = 0;
1787   silc_hash_make(hash, buf->data, buf->len, hashd);
1788   key->send_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1789   memcpy(key->send_iv, hashd, req_iv_len);
1790   memset(hashd, 0, sizeof(hashd));
1791   buf->data[0] = 1;
1792   silc_hash_make(hash, buf->data, buf->len, hashd);
1793   key->receive_iv = silc_calloc(req_iv_len, sizeof(unsigned char));
1794   memcpy(key->receive_iv, hashd, req_iv_len);
1795   key->iv_len = req_iv_len;
1796
1797   /* Take the encryption keys. If requested key size is more than
1798      the size of hash length we will distribute more key material
1799      as protocol defines. */
1800   buf->data[0] = 2;
1801   if (enc_key_len > hash_len) {
1802     SilcBuffer dist;
1803     unsigned char k1[32], k2[32], k3[32];
1804     unsigned char *dtmp;
1805     
1806     /* XXX */
1807     if (enc_key_len > (3 * hash_len))
1808       return SILC_SKE_STATUS_ERROR;
1809     
1810     /* Take first round */
1811     memset(k1, 0, sizeof(k1));
1812     silc_hash_make(hash, buf->data, buf->len, k1);
1813     
1814     /* Take second round */
1815     dist = silc_buffer_alloc_size(data_len + hash_len);
1816     if (!dist)
1817       return SILC_SKE_STATUS_OUT_OF_MEMORY;
1818     silc_buffer_format(dist,
1819                        SILC_STR_UI_XNSTRING(data, data_len),
1820                        SILC_STR_UI_XNSTRING(k1, hash_len),
1821                        SILC_STR_END);
1822     memset(k2, 0, sizeof(k2));
1823     silc_hash_make(hash, dist->data, dist->len, k2);
1824
1825     /* Take third round */
1826     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1827     silc_buffer_pull_tail(dist, hash_len);
1828     silc_buffer_pull(dist, data_len + hash_len);
1829     silc_buffer_format(dist,
1830                        SILC_STR_UI_XNSTRING(k2, hash_len),
1831                        SILC_STR_END);
1832     silc_buffer_push(dist, data_len + hash_len);
1833     memset(k3, 0, sizeof(k3));
1834     silc_hash_make(hash, dist->data, dist->len, k3);
1835
1836     /* Then, save the keys */
1837     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1838     memcpy(dtmp, k1, hash_len);
1839     memcpy(dtmp + hash_len, k2, hash_len);
1840     memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1841
1842     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1843     memcpy(key->send_enc_key, dtmp, enc_key_len);
1844     key->enc_key_len = req_enc_key_len;
1845
1846     memset(dtmp, 0, (3 * hash_len));
1847     memset(k1, 0, sizeof(k1));
1848     memset(k2, 0, sizeof(k2));
1849     memset(k3, 0, sizeof(k3));
1850     silc_free(dtmp);
1851     silc_buffer_clear(dist);
1852     silc_buffer_free(dist);
1853   } else {
1854     /* Take normal hash as key */
1855     memset(hashd, 0, sizeof(hashd));
1856     silc_hash_make(hash, buf->data, buf->len, hashd);
1857     key->send_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1858     memcpy(key->send_enc_key, hashd, enc_key_len);
1859     key->enc_key_len = req_enc_key_len;
1860   }
1861
1862   buf->data[0] = 3;
1863   if (enc_key_len > hash_len) {
1864     SilcBuffer dist;
1865     unsigned char k1[32], k2[32], k3[32];
1866     unsigned char *dtmp;
1867     
1868     /* XXX */
1869     if (enc_key_len > (3 * hash_len))
1870       return SILC_SKE_STATUS_ERROR;
1871     
1872     /* Take first round */
1873     memset(k1, 0, sizeof(k1));
1874     silc_hash_make(hash, buf->data, buf->len, k1);
1875     
1876     /* Take second round */
1877     dist = silc_buffer_alloc_size(data_len + hash_len);
1878     if (!dist)
1879       return SILC_SKE_STATUS_OUT_OF_MEMORY;
1880     silc_buffer_format(dist,
1881                        SILC_STR_UI_XNSTRING(data, data_len),
1882                        SILC_STR_UI_XNSTRING(k1, hash_len),
1883                        SILC_STR_END);
1884     memset(k2, 0, sizeof(k2));
1885     silc_hash_make(hash, dist->data, dist->len, k2);
1886     
1887     /* Take third round */
1888     dist = silc_buffer_realloc(dist, data_len + hash_len + hash_len);
1889     silc_buffer_pull_tail(dist, hash_len);
1890     silc_buffer_pull(dist, data_len + hash_len);
1891     silc_buffer_format(dist,
1892                        SILC_STR_UI_XNSTRING(k2, hash_len),
1893                        SILC_STR_END);
1894     silc_buffer_push(dist, data_len + hash_len);
1895     memset(k3, 0, sizeof(k3));
1896     silc_hash_make(hash, dist->data, dist->len, k3);
1897
1898     /* Then, save the keys */
1899     dtmp = silc_calloc((3 * hash_len), sizeof(unsigned char));
1900     memcpy(dtmp, k1, hash_len);
1901     memcpy(dtmp + hash_len, k2, hash_len);
1902     memcpy(dtmp + hash_len + hash_len, k3, hash_len);
1903
1904     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1905     memcpy(key->receive_enc_key, dtmp, enc_key_len);
1906     key->enc_key_len = req_enc_key_len;
1907
1908     memset(dtmp, 0, (3 * hash_len));
1909     memset(k1, 0, sizeof(k1));
1910     memset(k2, 0, sizeof(k2));
1911     memset(k3, 0, sizeof(k3));
1912     silc_free(dtmp);
1913     silc_buffer_clear(dist);
1914     silc_buffer_free(dist);
1915   } else {
1916     /* Take normal hash as key */
1917     memset(hashd, 0, sizeof(hashd));
1918     silc_hash_make(hash, buf->data, buf->len, hashd);
1919     key->receive_enc_key = silc_calloc(enc_key_len, sizeof(unsigned char));
1920     memcpy(key->receive_enc_key, hashd, enc_key_len);
1921     key->enc_key_len = req_enc_key_len;
1922   }
1923
1924   /* Take HMAC keys */
1925   memset(hashd, 0, sizeof(hashd));
1926   buf->data[0] = 4;
1927   silc_hash_make(hash, buf->data, buf->len, hashd);
1928   key->send_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1929   memcpy(key->send_hmac_key, hashd, req_hmac_key_len);
1930   memset(hashd, 0, sizeof(hashd));
1931   buf->data[0] = 5;
1932   silc_hash_make(hash, buf->data, buf->len, hashd);
1933   key->receive_hmac_key = silc_calloc(req_hmac_key_len, sizeof(unsigned char));
1934   memcpy(key->receive_hmac_key, hashd, req_hmac_key_len);
1935   key->hmac_key_len = req_hmac_key_len;
1936   memset(hashd, 0, sizeof(hashd));
1937
1938   silc_buffer_clear(buf);
1939   silc_buffer_free(buf);
1940
1941   return SILC_SKE_STATUS_OK;
1942 }
1943
1944 /* Processes negotiated key material as protocol specifies. This returns
1945    the actual keys to be used in the SILC. */
1946
1947 SilcSKEStatus silc_ske_process_key_material(SilcSKE ske, 
1948                                             SilcUInt32 req_iv_len,
1949                                             SilcUInt32 req_enc_key_len,
1950                                             SilcUInt32 req_hmac_key_len,
1951                                             SilcSKEKeyMaterial *key)
1952 {
1953   SilcSKEStatus status;
1954   SilcBuffer buf;
1955   unsigned char *tmpbuf;
1956   SilcUInt32 klen;
1957
1958   /* Encode KEY to binary data */
1959   tmpbuf = silc_mp_mp2bin(ske->KEY, 0, &klen);
1960
1961   buf = silc_buffer_alloc_size(klen + ske->hash_len);
1962   if (!buf)
1963     return SILC_SKE_STATUS_OUT_OF_MEMORY;
1964   silc_buffer_format(buf,
1965                      SILC_STR_UI_XNSTRING(tmpbuf, klen),
1966                      SILC_STR_UI_XNSTRING(ske->hash, ske->hash_len),
1967                      SILC_STR_END);
1968
1969   /* Process the key material */
1970   status = silc_ske_process_key_material_data(buf->data, buf->len,
1971                                               req_iv_len, req_enc_key_len,
1972                                               req_hmac_key_len, 
1973                                               ske->prop->hash, key);
1974
1975   memset(tmpbuf, 0, klen);
1976   silc_free(tmpbuf);
1977   silc_buffer_clear(buf);
1978   silc_buffer_free(buf);
1979
1980   return status;
1981 }
1982
1983 /* Free key material structure */
1984
1985 void silc_ske_free_key_material(SilcSKEKeyMaterial *key)
1986 {
1987   if (!key)
1988     return;
1989
1990   if (key->send_iv)
1991     silc_free(key->send_iv);
1992   if (key->receive_iv)
1993     silc_free(key->receive_iv);
1994   if (key->send_enc_key) {
1995     memset(key->send_enc_key, 0, key->enc_key_len / 8);
1996     silc_free(key->send_enc_key);
1997   }
1998   if (key->receive_enc_key) {
1999     memset(key->receive_enc_key, 0, key->enc_key_len / 8);
2000     silc_free(key->receive_enc_key);
2001   }
2002   if (key->send_hmac_key) {
2003     memset(key->send_hmac_key, 0, key->hmac_key_len);
2004     silc_free(key->send_hmac_key);
2005   }
2006   if (key->receive_hmac_key) {
2007     memset(key->receive_hmac_key, 0, key->hmac_key_len);
2008     silc_free(key->receive_hmac_key);
2009   }
2010   silc_free(key);
2011 }
2012
2013 const char *silc_ske_status_string[] = 
2014 {
2015   /* Official */
2016   "Ok",
2017   "Unkown error occurred",
2018   "Bad payload in packet",
2019   "Unsupported group",
2020   "Unsupported cipher",
2021   "Unsupported PKCS",
2022   "Unsupported hash function",
2023   "Unsupported HMAC",
2024   "Unsupported public key (or certificate)",
2025   "Incorrect signature",
2026   "Bad or unsupported version",
2027   "Invalid cookie",
2028
2029   /* Other errors */
2030   "Pending",
2031   "Remote did not provide public key",
2032   "Key exchange protocol is not active",
2033   "Bad reserved field in packet",
2034   "Bad payload length in packet",
2035   "Error computing signature",
2036   "System out of memory",
2037
2038   NULL
2039 };
2040
2041 /* Maps status to readable string and returns the string. If string is not
2042    found and empty character string ("") is returned. */
2043
2044 const char *silc_ske_map_status(SilcSKEStatus status)
2045 {
2046   int i;
2047
2048   for (i = 0; silc_ske_status_string[i]; i++)
2049     if (status == i)
2050       return silc_ske_status_string[i];
2051
2052   return "";
2053 }
2054
2055 /* Parses remote host's version string. */
2056
2057 bool silc_ske_parse_version(SilcSKE ske, 
2058                             SilcUInt32 *protocol_version,
2059                             char **protocol_version_string,
2060                             SilcUInt32 *software_version, 
2061                             char **software_version_string,
2062                             char **vendor_version)
2063 {
2064   return silc_parse_version_string(ske->remote_version,
2065                                    protocol_version, 
2066                                    protocol_version_string, 
2067                                    software_version,
2068                                    software_version_string,
2069                                    vendor_version);
2070 }