5772785 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$ cat -n dh.c
  1 /* dh.c */
  2 /* this file contains usefull stuff for Diffie helman algorithm against SSH 2 */
  3 /*
  4 Copyright 2003 Aris Adamantiadis
  5 
  6 This file is part of the SSH Library
  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 /* Let us resume the dh protocol. */
 24 /* Each side computes a private prime number, x at client side, y at server side. */
 25 /* g and n are two numbers common to every ssh software. */
 26 /* client's public key (e) is calculated by doing */
 27 /* e = g^x mod p */
 28 /* client sents e to the server . */
 29 /* the server computes his own public key, f */
 30 /* f = g^y mod p */
 31 /* it sents it to the client */
 32 /* the common key K is calculated by the client by doing */
 33 /* k = f^x mod p */
 34 /* the server does the same with the client public key e */
 35 /* k' = e^y mod p */
 36 /* if everything went correctly, k and k' are equal */
 37 
 38 #include "libssh/priv.h"
 39 
 40 #include <stdio.h>
 41 #include <stdlib.h>
 42 #include <unistd.h>
 43 #include <fcntl.h>
 44 #ifdef HAVE_NETDB_H
 45 #include <netdb.h>
 46 #endif
 47 #ifdef HAVE_WINDOWS_H
 48 #include <windows.h>
 49 #endif
 50 
 51 #include <openssl/rand.h>
 52 #include <openssl/evp.h>
 53 #include <openssl/err.h>
 54 #include <string.h>
 55 #include "libssh/crypto.h"    
 56 static unsigned char p_value[] = {
 57         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
 58         0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
 59         0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
 60         0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
 61         0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
 62         0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
 63         0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
 64         0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
 65         0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
 66         0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
 67         0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 68 #define P_LEN 128   /* Size in bytes of the p number */
 69 
 70 static unsigned long g_int = 2 ;    /* G is defined as 2 by the ssh2 standards */
 71 static bignum g;
 72 static bignum p;
 73 
 74 /* maybe it might be enhanced .... */
 75 /* XXX Do it. */        
 76 void ssh_get_random(void *where, int len){
 77     static int rndfd = -1;
 78     unsigned char *data = where;
 79     int i;
 80 
 81     if(rndfd < 0) {
 82         rndfd=open("/dev/urandom",O_RDONLY);
 83     }
 84 
 85     if(rndfd >= 0){
 86         read(rndfd,where,len);
 87         return;
 88     }
 89 
 90     for (i = 0; i < len; i++) {
 91         srand(getpid() + time(NULL) + rand() + len + i);
 92         data[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
 93     }
 94 }
 95 
 96 /* it inits the values g and p which are used for DH key agreement */
 97 void ssh_crypto_init(){
 98     static int init=0;
 99     if(!init){
100         g=bignum_new();
101         bignum_set_word(g,g_int);
102         p=bignum_new();
103         bignum_bin2bn(p_value,P_LEN,p);
104         init++;
105     }
106 }
107 
108 /* prints the bignum on stderr */
109 void ssh_print_bignum(char *which,bignum num){
110     char *hex;
111     fprintf(stderr,"%s value: ",which);
112     hex=bignum_bn2hex(num);
113     fprintf(stderr,"%s\n",hex);
114     free(hex);  
115 }
116 
117 void ssh_print_hexa(char *descr,unsigned char *what, int len){
118     int i;
119     printf("%s : ",descr);
120     for(i=0;i<len-1;i++)
121         printf("%.2hhx:",what[i]);
122     printf("%.2hhx\n",what[i]);
123 }
124 
125 void dh_generate_x(SSH_SESSION *session){
126     session->next_crypto->x=bignum_new();
127     bignum_rand(session->next_crypto->x,128,0,-1);
128     /* not harder than this */
129 #ifdef DEBUG_CRYPTO
130     ssh_print_bignum("x",session->next_crypto->x);
131 #endif
132 }
133 
134 void dh_generate_e(SSH_SESSION *session){
135     bignum_CTX ctx=bignum_ctx_new();
136     session->next_crypto->e=bignum_new();
137     bignum_mod_exp(session->next_crypto->e,g,session->next_crypto->x,p,ctx);
138 #ifdef DEBUG_CRYPTO
139     ssh_print_bignum("e",session->next_crypto->e);
140 #endif
141     bignum_ctx_free(ctx);
142 }
143 
144 
145 STRING *make_bignum_string(bignum num){
146     STRING *ptr;
147     int pad=0;
148     int len=bignum_num_bytes(num);
149     int bits=bignum_num_bits(num);
150     int finallen;
151     /* remember if the fist bit is set, it is considered as a negative number. so 0's must be appended */
152     if(!(bits%8) && bignum_is_bit_set(num,bits-1))
153         pad++;
154     ssh_say(3,"%d bits, %d bytes, %d padding\n",bits,len,pad);
155     ptr=malloc(4 + len + pad);
156     ptr->size=htonl(len+pad);
157     if(pad)
158         ptr->string[0]=0;
159     finallen=bignum_bn2bin(num,ptr->string+pad);
160     return ptr;
161 }
162 
163 bignum make_string_bn(STRING *string){
164     int len=ntohl(string->size);
165     ssh_say(3,"Importing a %d bits,%d bytes object ...\n",len*8,len);
166     return bignum_bin2bn(string->string,len,NULL);
167 }
168 
169 STRING *dh_get_e(SSH_SESSION *session){
170     return make_bignum_string(session->next_crypto->e);
171 }
172 
173 void dh_import_pubkey(SSH_SESSION *session,STRING *pubkey_string){
174     session->next_crypto->server_pubkey=pubkey_string;
175 }
176 
177 void dh_import_f(SSH_SESSION *session,STRING *f_string){
178     session->next_crypto->f=make_string_bn(f_string);
179 #ifdef DEBUG_CRYPTO
180     ssh_print_bignum("f",session->next_crypto->f);
181 #endif
182 }
183 
184 void dh_build_k(SSH_SESSION *session){
185     bignum_CTX ctx=bignum_ctx_new();
186     session->next_crypto->k=bignum_new();
187     bignum_mod_exp(session->next_crypto->k,session->next_crypto->f,session->next_crypto->x,p,ctx);
188 #ifdef DEBUG_CRYPTO
189     ssh_print_bignum("shared secret key",session->next_crypto->k);
190 #endif
191     bignum_ctx_free(ctx);
192 }
193 
194 static void sha_add(STRING *str,SHACTX *ctx){
195     sha1_update(ctx,str,string_len(str)+4);
196 }
197 
198 void make_sessionid(SSH_SESSION *session){
199     SHACTX *ctx;
200     STRING *num,*str;
201     int len;
202     ctx=sha1_init();
203 
204     str=string_from_char(session->clientbanner);
205     sha_add(str,ctx);
206     free(str);
207 
208     str=string_from_char(session->serverbanner);
209     sha_add(str,ctx);
210     free(str);
211 
212     buffer_add_u32(session->in_hashbuf,0);
213     buffer_add_u8(session->in_hashbuf,0);
214     buffer_add_u32(session->out_hashbuf,0);
215     buffer_add_u8(session->out_hashbuf,0);
216 
217     len=ntohl(buffer_get_len(session->out_hashbuf));
218     sha1_update(ctx,&len,4);
219 
220     sha1_update(ctx,buffer_get(session->out_hashbuf),buffer_get_len(session->out_hashbuf));
221     buffer_free(session->out_hashbuf);
222     session->out_hashbuf=NULL;
223 
224     len=ntohl(buffer_get_len(session->in_hashbuf));
225     sha1_update(ctx,&len,4);
226 
227     sha1_update(ctx,buffer_get(session->in_hashbuf),buffer_get_len(session->in_hashbuf));
228     buffer_free(session->in_hashbuf);
229     session->in_hashbuf=NULL;
230     sha1_update(ctx,session->next_crypto->server_pubkey,len=(string_len(session->next_crypto->server_pubkey)+4));
231     num=make_bignum_string(session->next_crypto->e);
232     sha1_update(ctx,num,len=(string_len(num)+4));
233     free(num);
234     num=make_bignum_string(session->next_crypto->f);
235     sha1_update(ctx,num,len=(string_len(num)+4));
236     free(num);
237     num=make_bignum_string(session->next_crypto->k);
238     sha1_update(ctx,num,len=(string_len(num)+4));
239     free(num);
240     sha1_final(session->next_crypto->session_id,ctx);
241 
242 #ifdef DEBUG_CRYPTO
243         printf("Session hash : ");
244         ssh_print_hexa("session id",session->next_crypto->session_id,SHA_DIGEST_LENGTH);
245 #endif
246 }
247 
248 void hashbufout_add_cookie(SSH_SESSION *session){
249     session->out_hashbuf=buffer_new();
250     buffer_add_u8(session->out_hashbuf,20);
251     buffer_add_data(session->out_hashbuf,session->client_kex.cookie,16);
252 }
253 
254 
255 void hashbufin_add_cookie(SSH_SESSION *session,unsigned char *cookie){
256     session->in_hashbuf=buffer_new();
257     buffer_add_u8(session->in_hashbuf,20);
258     buffer_add_data(session->in_hashbuf,cookie,16);
259 }
260 
261 static void generate_one_key(STRING *k,char session_id[SHA_DIGEST_LENGTH],char output[SHA_DIGEST_LENGTH],char letter){
262     SHACTX *ctx=sha1_init();
263     sha1_update(ctx,k,string_len(k)+4);
264     sha1_update(ctx,session_id,SHA_DIGEST_LENGTH);
265     sha1_update(ctx,&letter,1);
266     sha1_update(ctx,session_id,SHA_DIGEST_LENGTH);
267     sha1_final(output,ctx);
268 }
269 
270 void generate_session_keys(SSH_SESSION *session){
271     STRING *k_string;
272     SHACTX *ctx;
273     k_string=make_bignum_string(session->next_crypto->k);
274 
275     /* IV */
276     generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptIV,'A');
277     generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptIV,'B');
278 
279     generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptkey,'C');
280 
281     /* some ciphers need more than 20 bytes of input key */
282     if(session->next_crypto->out_cipher->keylen > SHA_DIGEST_LENGTH*8){
283         ctx=sha1_init();
284         sha1_update(ctx,k_string,string_len(k_string)+4);
285         sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH);
286         sha1_update(ctx,session->next_crypto->encryptkey,SHA_DIGEST_LENGTH);
287         sha1_final(session->next_crypto->encryptkey+SHA_DIGEST_LEN,ctx);
288     }
289 
290     generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptkey,'D');
291 
292     if(session->next_crypto->in_cipher->keylen > SHA_DIGEST_LENGTH*8){
293         ctx=sha1_init();
294         sha1_update(ctx,k_string,string_len(k_string)+4);
295         sha1_update(ctx,session->next_crypto->session_id,SHA_DIGEST_LENGTH);
296         sha1_update(ctx,session->next_crypto->decryptkey,SHA_DIGEST_LENGTH);
297         sha1_final(session->next_crypto->decryptkey+SHA_DIGEST_LEN,ctx);
298     }
299 
300     generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->encryptMAC,'E');
301     generate_one_key(k_string,session->next_crypto->session_id,session->next_crypto->decryptMAC,'F');
302 
303 #ifdef DEBUG_CRYPTO
304     ssh_print_hexa("client->server IV",session->next_crypto->encryptIV,SHA_DIGEST_LENGTH);
305     ssh_print_hexa("server->client IV",session->next_crypto->decryptIV,SHA_DIGEST_LENGTH);
306     ssh_print_hexa("encryption key",session->next_crypto->encryptkey,16);
307     ssh_print_hexa("decryption key",session->next_crypto->decryptkey,16);
308     ssh_print_hexa("Encryption MAC",session->next_crypto->encryptMAC,SHA_DIGEST_LENGTH);
309     ssh_print_hexa("Decryption MAC",session->next_crypto->decryptMAC,20);
310 #endif
311     free(k_string);
312 }
313 
314 int ssh_get_pubkey_hash(SSH_SESSION *session,char hash[MD5_DIGEST_LEN]){
315     STRING *pubkey=session->current_crypto->server_pubkey;
316     MD5CTX *ctx;
317     int len=string_len(pubkey);
318 
319     ctx=md5_init();
320     md5_update(ctx,pubkey->string,len);
321     md5_final(hash,ctx);
322     return MD5_DIGEST_LEN;
323 }
324 
325 int pubkey_get_hash(SSH_SESSION *session, char hash[MD5_DIGEST_LEN]){
326     return ssh_get_pubkey_hash(session,hash);
327 }
328 
329 STRING *ssh_get_pubkey(SSH_SESSION *session){
330     return string_copy(session->current_crypto->server_pubkey);
331 }
332 
333 /* XXX i doubt it is still needed, or may need some fix */
334 static int match(char *group,char *object){
335     char *ptr,*saved;
336     char *end;
337     ptr=strdup(group);
338     saved=ptr;
339     while(1){
340         end=strchr(ptr,',');
341         if(end)
342             *end=0;
343         if(!strcmp(ptr,object)){
344             free(saved);
345             return 0;
346         }
347         if(end)
348             ptr=end+1;
349         else{
350             free(saved);
351             return -1;
352         }
353     }
354     /* not reached */
355     return 1;
356 }
357 
358 int sig_verify(PUBLIC_KEY *pubkey, SIGNATURE *signature, char *digest){
359     int valid=0;
360     char hash[SHA_DIGEST_LENGTH];
361     sha1(digest,SHA_DIGEST_LENGTH,hash);
362     switch(pubkey->type){
363         case TYPE_DSS:
364             valid=DSA_do_verify(hash,SHA_DIGEST_LENGTH,signature->dsa_sign,
365                 pubkey->dsa_pub);
366             if(valid==1)
367                 return 0;
368             if(valid==-1){
369                 ssh_set_error(NULL,SSH_INVALID_DATA,"DSA error : %s",ERR_error_string(ERR_get_error(),NULL));
370                 return -1;
371             }
372             ssh_set_error(NULL,SSH_NO_ERROR,"Invalid DSA signature");
373             return -1;
374         case TYPE_RSA:
375         case TYPE_RSA1:
376         valid=RSA_verify(NID_sha1,hash,SHA_DIGEST_LENGTH,
377             signature->rsa_sign->string,string_len(signature->rsa_sign),pubkey->rsa_pub);
378             if(valid==1)
379                 return 0;
380             if(valid==-1){
381                 ssh_set_error(NULL,SSH_INVALID_DATA,"RSA error : %s",ERR_error_string(ERR_get_error(),NULL));
382                 return -1;
383             }
384             ssh_set_error(NULL,SSH_NO_ERROR,"Invalid RSA signature");
385             return -1;
386        default:
387             ssh_set_error(NULL,SSH_INVALID_DATA,"Unknown public key type");
388             return -1;
389    }
390 return -1;
391 }
392 
393     
394 int signature_verify(SSH_SESSION *session,STRING *signature){
395     PUBLIC_KEY *pubkey;
396     SIGNATURE *sign;
397     int err;
398     if(session->options->dont_verify_hostkey){
399         ssh_say(1,"Host key wasn't verified\n");
400         return 0;
401     }
402     pubkey=publickey_from_string(session->next_crypto->server_pubkey);
403     if(!pubkey)
404         return -1;
405     if(session->options->wanted_methods[KEX_HOSTKEY]){
406          if(match(session->options->wanted_methods[KEX_HOSTKEY],pubkey->type_c)){
407              ssh_set_error((session->connected?session:NULL),SSH_FATAL,"Public key from server (%s) doesn't match user
	preference (%s)",
408              pubkey->type,session->options->wanted_methods[KEX_HOSTKEY]);
409              publickey_free(pubkey);
410              return -1;
411          }
412     }
413     sign=signature_from_string(signature,pubkey,pubkey->type);
414     if(!sign){
415         ssh_set_error((session->connected?session:NULL),SSH_INVALID_DATA,"Invalid signature blob");
416         publickey_free(pubkey);
417         return -1;
418     }
419     ssh_say(1,"Going to verify a %s type signature\n",pubkey->type_c);
420     err=sig_verify(pubkey,sign,session->next_crypto->session_id);
421     signature_free(sign);
422     session->next_crypto->server_pubkey_type=pubkey->type_c;
423     publickey_free(pubkey);
424     return err;
425 }
5772786 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2007-02-17 17:46:50