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 } |