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

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-03-04 19:54:59