1 /*
2  * kex.c - key exchange
3  *
4  * This file is part of the SSH Library
5  *
6  * Copyright (c) 2003-2008 by Aris Adamantiadis
7  *
8  * The SSH Library is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or (at your
11  * option) any later version.
12  *
13  * The SSH Library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16  * License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with the SSH Library; see the file COPYING.  If not, write to
20  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21  * MA 02111-1307, USA.
22  */
23 
24 #include "config.h"
25 
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 
30 #include "libssh/priv.h"
31 #include "libssh/buffer.h"
32 #include "libssh/dh.h"
33 #include "libssh/kex.h"
34 #include "libssh/session.h"
35 #include "libssh/ssh2.h"
36 #include "libssh/string.h"
37 
38 #ifdef HAVE_LIBGCRYPT
39 #define BLOWFISH "blowfish-cbc,"
40 #define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
41 #define DES "3des-cbc"
42 #elif defined HAVE_LIBCRYPTO
43 #ifdef HAVE_OPENSSL_BLOWFISH_H
44 #define BLOWFISH "blowfish-cbc,"
45 #else
46 #define BLOWFISH ""
47 #endif
48 #ifdef HAVE_OPENSSL_AES_H
49 #ifdef BROKEN_AES_CTR
50 #define AES "aes256-cbc,aes192-cbc,aes128-cbc,"
51 #else
52 #define AES "aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,"
53 #endif /* BROKEN_AES_CTR */
54 #else
55 #define AES ""
56 #endif
57 
58 #define DES "3des-cbc"
59 #endif
60 
61 #ifdef WITH_ZLIB
62 #define ZLIB "none,zlib,zlib@openssh.com"
63 #else
64 #define ZLIB "none"
65 #endif
66 
67 #ifdef HAVE_ECDH
68 #define KEY_EXCHANGE "ecdh-sha2-nistp256,diffie-hellman-group1-sha1"
69 #else
70 #define KEY_EXCHANGE "diffie-hellman-group1-sha1"
71 #endif
72 
73 static const char *default_methods[] = {
74   KEY_EXCHANGE,
75   "ssh-rsa,ssh-dss",
76   AES BLOWFISH DES,
77   AES BLOWFISH DES,
78   "hmac-sha1",
79   "hmac-sha1",
80   "none",
81   "none",
82   "",
83   "",
84   NULL
85 };
86 
87 const char *supported_methods[] = {
88   KEY_EXCHANGE,
89   "ssh-rsa,ssh-dss",
90   AES BLOWFISH DES,
91   AES BLOWFISH DES,
92   "hmac-sha1",
93   "hmac-sha1",
94   ZLIB,
95   ZLIB,
96   "",
97   "",
98   NULL
99 };
100 
101 /* descriptions of the key exchange packet */
102 const char *ssh_kex_nums[] = {
103   "kex algos",
104   "server host key algo",
105   "encryption client->server",
106   "encryption server->client",
107   "mac algo client->server",
108   "mac algo server->client",
109   "compression algo client->server",
110   "compression algo server->client",
111   "languages client->server",
112   "languages server->client",
113   NULL
114 };
115 
116 /* tokenize will return a token of strings delimited by ",". the first element has to be freed */
tokenize(const char * chain)117 static char **tokenize(const char *chain){
118     char **tokens;
119     int n=1;
120     int i=0;
121     char *tmp;
122     char *ptr;
123 
124     tmp = strdup(chain);
125     if (tmp == NULL) {
126       return NULL;
127     }
128     ptr = tmp;
129     while(*ptr){
130         if(*ptr==','){
131             n++;
132             *ptr=0;
133         }
134         ptr++;
135     }
136     /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
137     tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
138     if (tokens == NULL) {
139       SAFE_FREE(tmp);
140       return NULL;
141     }
142     ptr=tmp;
143     for(i=0;i<n;i++){
144         tokens[i]=ptr;
145         while(*ptr)
146             ptr++; // find a zero
147         ptr++; // then go one step further
148     }
149     tokens[i]=NULL;
150     return tokens;
151 }
152 
153 /* same as tokenize(), but with spaces instead of ',' */
154 /* TODO FIXME rewrite me! */
space_tokenize(const char * chain)155 char **space_tokenize(const char *chain){
156     char **tokens;
157     int n=1;
158     int i=0;
159     char *tmp;
160     char *ptr;
161 
162     tmp = strdup(chain);
163     if (tmp == NULL) {
164       return NULL;
165     }
166     ptr = tmp;
167 
168     while(*ptr==' ')
169         ++ptr; /* skip initial spaces */
170     while(*ptr){
171         if(*ptr==' '){
172             n++; /* count one token per word */
173             *ptr=0;
174             while(*(ptr+1)==' '){ /* don't count if the tokens have more than 2 spaces */
175                 *(ptr++)=0;
176             }
177         }
178         ptr++;
179     }
180     /* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
181     tokens = malloc(sizeof(char *) * (n + 1)); /* +1 for the null */
182     if (tokens == NULL) {
183       SAFE_FREE(tmp);
184       return NULL;
185     }
186     ptr=tmp; /* we don't pass the initial spaces because the "tmp" pointer is needed by the caller */
187                     /* function to free the tokens. */
188     for(i=0;i<n;i++){
189         tokens[i]=ptr;
190         if(i!=n-1){
191             while(*ptr)
192                 ptr++; // find a zero
193             while(!*(ptr+1))
194                 ++ptr; /* if the zero is followed by other zeros, go through them */
195             ptr++; // then go one step further
196         }
197     }
198     tokens[i]=NULL;
199     return tokens;
200 }
201 
202 /* find_matching gets 2 parameters : a list of available objects (available_d), separated by colons,*/
203 /* and a list of preferred objects (preferred_d) */
204 /* it will return a strduped pointer on the first preferred object found in the available objects list */
205 
ssh_find_matching(const char * available_d,const char * preferred_d)206 char *ssh_find_matching(const char *available_d, const char *preferred_d){
207     char ** tok_available, **tok_preferred;
208     int i_avail, i_pref;
209     char *ret;
210 
211     if ((available_d == NULL) || (preferred_d == NULL)) {
212       return NULL; /* don't deal with null args */
213     }
214 
215     tok_available = tokenize(available_d);
216     if (tok_available == NULL) {
217       return NULL;
218     }
219 
220     tok_preferred = tokenize(preferred_d);
221     if (tok_preferred == NULL) {
222       SAFE_FREE(tok_available[0]);
223       SAFE_FREE(tok_available);
224       return NULL;
225     }
226 
227     for(i_pref=0; tok_preferred[i_pref] ; ++i_pref){
228       for(i_avail=0; tok_available[i_avail]; ++i_avail){
229         if(!strcmp(tok_available[i_avail],tok_preferred[i_pref])){
230           /* match */
231           ret=strdup(tok_available[i_avail]);
232           /* free the tokens */
233           SAFE_FREE(tok_available[0]);
234           SAFE_FREE(tok_preferred[0]);
235           SAFE_FREE(tok_available);
236           SAFE_FREE(tok_preferred);
237           return ret;
238         }
239       }
240     }
241     SAFE_FREE(tok_available[0]);
242     SAFE_FREE(tok_preferred[0]);
243     SAFE_FREE(tok_available);
244     SAFE_FREE(tok_preferred);
245     return NULL;
246 }
247 
SSH_PACKET_CALLBACK(ssh_packet_kexinit)248 SSH_PACKET_CALLBACK(ssh_packet_kexinit){
249 	int server_kex=session->server;
250   ssh_string str = NULL;
251   char *strings[10];
252   int i;
253 
254   enter_function();
255   (void)type;
256   (void)user;
257   memset(strings, 0, sizeof(strings));
258   if(session->session_state != SSH_SESSION_STATE_INITIAL_KEX){
259   	ssh_set_error(session,SSH_FATAL,"SSH_KEXINIT received in wrong state");
260   	goto error;
261   }
262   if (server_kex) {
263       if (buffer_get_data(packet,session->next_crypto->client_kex.cookie,16) != 16) {
264         ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
265         goto error;
266       }
267 
268       if (hashbufin_add_cookie(session, session->next_crypto->client_kex.cookie) < 0) {
269         ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
270         goto error;
271       }
272   } else {
273       if (buffer_get_data(packet,session->next_crypto->server_kex.cookie,16) != 16) {
274         ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: no cookie in packet");
275         goto error;
276       }
277 
278       if (hashbufin_add_cookie(session, session->next_crypto->server_kex.cookie) < 0) {
279         ssh_set_error(session, SSH_FATAL, "ssh_packet_kexinit: adding cookie failed");
280         goto error;
281       }
282   }
283 
284   for (i = 0; i < 10; i++) {
285     str = buffer_get_ssh_string(packet);
286     if (str == NULL) {
287       break;
288     }
289 
290     if (buffer_add_ssh_string(session->in_hashbuf, str) < 0) {
291     	ssh_set_error(session, SSH_FATAL, "Error adding string in hash buffer");
292       goto error;
293     }
294 
295     strings[i] = ssh_string_to_char(str);
296     if (strings[i] == NULL) {
297     	ssh_set_error_oom(session);
298       goto error;
299     }
300     ssh_string_free(str);
301     str = NULL;
302   }
303 
304   /* copy the server kex info into an array of strings */
305   if (server_kex) {
306     for (i = 0; i < SSH_KEX_METHODS; i++) {
307       session->next_crypto->client_kex.methods[i] = strings[i];
308     }
309   } else { /* client */
310     for (i = 0; i < SSH_KEX_METHODS; i++) {
311       session->next_crypto->server_kex.methods[i] = strings[i];
312     }
313   }
314 
315   leave_function();
316   session->session_state=SSH_SESSION_STATE_KEXINIT_RECEIVED;
317   session->ssh_connection_callback(session);
318   return SSH_PACKET_USED;
319 error:
320   ssh_string_free(str);
321   for (i = 0; i < 10; i++) {
322     SAFE_FREE(strings[i]);
323   }
324 
325   session->session_state = SSH_SESSION_STATE_ERROR;
326   leave_function();
327   return SSH_PACKET_USED;
328 }
329 
ssh_list_kex(ssh_session session,struct ssh_kex_struct * kex)330 void ssh_list_kex(ssh_session session, struct ssh_kex_struct *kex) {
331   int i = 0;
332 
333 #ifdef DEBUG_CRYPTO
334   ssh_print_hexa("session cookie", kex->cookie, 16);
335 #endif
336   if(kex->methods==NULL){
337     ssh_log(session, SSH_LOG_RARE,"kex->methods is NULL");
338     return;
339   }
340   for(i = 0; i < 10; i++) {
341     ssh_log(session, SSH_LOG_FUNCTIONS, "%s: %s",
342         ssh_kex_nums[i], kex->methods[i]);
343   }
344 }
345 
346 /**
347  * @brief sets the key exchange parameters to be sent to the server,
348  *        in function of the options and available methods.
349  */
set_client_kex(ssh_session session)350 int set_client_kex(ssh_session session){
351     struct ssh_kex_struct *client= &session->next_crypto->client_kex;
352     int i;
353     const char *wanted;
354     enter_function();
355     ssh_get_random(client->cookie,16,0);
356     memset(client->methods,0,10*sizeof(char **));
357     for (i=0;i<10;i++){
358         wanted=session->wanted_methods[i];
359         if(wanted == NULL)
360             wanted=default_methods[i];
361         client->methods[i]=strdup(wanted);
362     }
363     leave_function();
364     return SSH_OK;
365 }
366 
367 /** @brief Select the different methods on basis of client's and
368  * server's kex messages, and watches out if a match is possible.
369  */
ssh_kex_select_methods(ssh_session session)370 int ssh_kex_select_methods (ssh_session session){
371     struct ssh_kex_struct *server = &session->next_crypto->server_kex;
372     struct ssh_kex_struct *client = &session->next_crypto->client_kex;
373     int rc = SSH_ERROR;
374     int i;
375 
376     enter_function();
377 
378     for (i=0;i<10;i++){
379         session->next_crypto->kex_methods[i]=ssh_find_matching(server->methods[i],client->methods[i]);
380         if(session->next_crypto->kex_methods[i] == NULL && i < SSH_LANG_C_S){
381             ssh_set_error(session,SSH_FATAL,"kex error : no match for method %s: server [%s], client [%s]",
382                     ssh_kex_nums[i],server->methods[i],client->methods[i]);
383             goto error;
384         } else if ((i >= SSH_LANG_C_S) && (session->next_crypto->kex_methods[i] == NULL)) {
385             /* we can safely do that for languages */
386             session->next_crypto->kex_methods[i] = strdup("");
387         }
388     }
389     if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "diffie-hellman-group1-sha1") == 0){
390       session->next_crypto->kex_type=SSH_KEX_DH_GROUP1_SHA1;
391     } else if(strcmp(session->next_crypto->kex_methods[SSH_KEX], "ecdh-sha2-nistp256") == 0){
392       session->next_crypto->kex_type=SSH_KEX_ECDH_SHA2_NISTP256;
393     }
394     rc = SSH_OK;
395 error:
396     leave_function();
397     return rc;
398 }
399 
400 
401 /* this function only sends the predefined set of kex methods */
ssh_send_kex(ssh_session session,int server_kex)402 int ssh_send_kex(ssh_session session, int server_kex) {
403   struct ssh_kex_struct *kex = (server_kex ? &session->next_crypto->server_kex :
404       &session->next_crypto->client_kex);
405   ssh_string str = NULL;
406   int i;
407 
408   enter_function();
409 
410   if (buffer_add_u8(session->out_buffer, SSH2_MSG_KEXINIT) < 0) {
411     goto error;
412   }
413   if (buffer_add_data(session->out_buffer, kex->cookie, 16) < 0) {
414     goto error;
415   }
416 
417   if (hashbufout_add_cookie(session) < 0) {
418     goto error;
419   }
420 
421   ssh_list_kex(session, kex);
422 
423   for (i = 0; i < 10; i++) {
424     str = ssh_string_from_char(kex->methods[i]);
425     if (str == NULL) {
426       goto error;
427     }
428 
429     if (buffer_add_ssh_string(session->out_hashbuf, str) < 0) {
430       goto error;
431     }
432     if (buffer_add_ssh_string(session->out_buffer, str) < 0) {
433       goto error;
434     }
435     ssh_string_free(str);
436   }
437 
438   if (buffer_add_u8(session->out_buffer, 0) < 0) {
439     goto error;
440   }
441   if (buffer_add_u32(session->out_buffer, 0) < 0) {
442     goto error;
443   }
444 
445   if (packet_send(session) == SSH_ERROR) {
446     leave_function();
447     return -1;
448   }
449 
450   leave_function();
451   return 0;
452 error:
453   buffer_reinit(session->out_buffer);
454   buffer_reinit(session->out_hashbuf);
455   ssh_string_free(str);
456 
457   leave_function();
458   return -1;
459 }
460 
461 /* returns 1 if at least one of the name algos is in the default algorithms table */
verify_existing_algo(int algo,const char * name)462 int verify_existing_algo(int algo, const char *name){
463     char *ptr;
464     if(algo>9 || algo <0)
465         return -1;
466     ptr=ssh_find_matching(supported_methods[algo],name);
467     if(ptr){
468         free(ptr);
469         return 1;
470     }
471     return 0;
472 }
473 
474 /* vim: set ts=2 sw=2 et cindent: */
475