1 /* keys handle the public key related functions */ 2 /* decoding a public key (both rsa and dsa), decoding a signature (rsa and dsa), veryfying them */ 3 4 /* 5 Copyright 2003,04 Aris Adamantiadis 6 7 This file is part of the SSH Library 8 9 The SSH Library is free software; you can redistribute it and/or modify 10 it under the terms of the GNU Lesser General Public License as published by 11 the Free Software Foundation; either version 2.1 of the License, or (at your 12 option) any later version. 13 14 The SSH Library is distributed in the hope that it will be useful, but 15 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 16 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17 License for more details. 18 19 You should have received a copy of the GNU Lesser General Public License 20 along with the SSH Library; see the file COPYING. If not, write to 21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 22 MA 02111-1307, USA. */ 23 #include <string.h> 24 #include <openssl/dsa.h> 25 #include <openssl/rsa.h> 26 #include "libssh/priv.h" 27 28 29 /* Public key decoding functions */ 30 31 char *ssh_type_to_char(int type){ 32 switch(type){ 33 case TYPE_DSS: 34 return "ssh-dss"; 35 case TYPE_RSA: 36 case TYPE_RSA1: 37 return "ssh-rsa"; 38 default: 39 return NULL; 40 } 41 } 42 43 PUBLIC_KEY *publickey_make_dss(BUFFER *buffer){ 44 STRING *p,*q,*g,*pubkey; 45 PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY)); 46 key->type=TYPE_DSS; 47 key->type_c="ssh-dss"; 48 p=buffer_get_ssh_string(buffer); 49 q=buffer_get_ssh_string(buffer); 50 g=buffer_get_ssh_string(buffer); 51 pubkey=buffer_get_ssh_string(buffer); 52 buffer_free(buffer); /* we don't need it anymore */ 53 if(!p || !q || !g || !pubkey){ 54 ssh_set_error(NULL,SSH_FATAL,"Invalid DSA public key"); 55 if(p) 56 free(p); 57 if(q) 58 free(q); 59 if(g) 60 free(g); 61 if(pubkey) 62 free(pubkey); 63 free(key); 64 return NULL; 65 } 66 key->dsa_pub=DSA_new(); 67 key->dsa_pub->p=make_string_bn(p); 68 key->dsa_pub->q=make_string_bn(q); 69 key->dsa_pub->g=make_string_bn(g); 70 key->dsa_pub->pub_key=make_string_bn(pubkey); 71 free(p); 72 free(q); 73 free(g); 74 free(pubkey); 75 return key; 76 } 77 78 PUBLIC_KEY *publickey_make_rsa(BUFFER *buffer){ 79 STRING *e,*n; 80 PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY)); 81 key->type=TYPE_RSA; 82 key->type_c="ssh-rsa"; 83 e=buffer_get_ssh_string(buffer); 84 n=buffer_get_ssh_string(buffer); 85 buffer_free(buffer); /* we don't need it anymore */ 86 if(!e || !n){ 87 ssh_set_error(NULL,SSH_FATAL,"Invalid RSA public key"); 88 if(e) 89 free(e); 90 if(n) 91 free(n); 92 free(key); 93 return NULL; 94 } 95 key->rsa_pub=RSA_new(); 96 key->rsa_pub->e=make_string_bn(e); 97 key->rsa_pub->n=make_string_bn(n); 98 #ifdef DEBUG_CRYPTO 99 ssh_print_bignum("e",key->rsa_pub->e); 100 ssh_print_bignum("n",key->rsa_pub->n); 101 #endif 102 free(e); 103 free(n); 104 return key; 105 } 106 107 void publickey_free(PUBLIC_KEY *key){ 108 if(!key) 109 return; 110 switch(key->type){ 111 case TYPE_DSS: 112 DSA_free(key->dsa_pub); 113 break; 114 case TYPE_RSA: 115 case TYPE_RSA1: 116 RSA_free(key->rsa_pub); 117 break; 118 default: 119 break; 120 } 121 free(key); 122 } 123 124 PUBLIC_KEY *publickey_from_string(STRING *pubkey_s){ 125 BUFFER *tmpbuf=buffer_new(); 126 STRING *type_s; 127 char *type; 128 129 buffer_add_data(tmpbuf,pubkey_s->string,string_len(pubkey_s)); 130 type_s=buffer_get_ssh_string(tmpbuf); 131 if(!type_s){ 132 buffer_free(tmpbuf); 133 ssh_set_error(NULL,SSH_FATAL,"Invalid public key format"); 134 return NULL; 135 } 136 type=string_to_char(type_s); 137 free(type_s); 138 if(!strcmp(type,"ssh-dss")){ 139 free(type); 140 return publickey_make_dss(tmpbuf); 141 } 142 if(!strcmp(type,"ssh-rsa")){ 143 free(type); 144 return publickey_make_rsa(tmpbuf); 145 } 146 ssh_set_error(NULL,SSH_FATAL,"unknown public key protocol %s",type); 147 buffer_free(tmpbuf); 148 free(type); 149 return NULL; 150 } 151 152 /* Signature decoding functions */ 153 154 STRING *signature_to_string(SIGNATURE *sign){ 155 STRING *str; 156 STRING *rs,*r,*s; 157 unsigned char buffer[40]; 158 BUFFER *tmpbuf=buffer_new(); 159 STRING *tmp; 160 tmp=string_from_char(ssh_type_to_char(sign->type)); 161 buffer_add_ssh_string(tmpbuf,tmp); 162 free(tmp); 163 switch(sign->type){ 164 case TYPE_DSS: 165 r=make_bignum_string(sign->dsa_sign->r); 166 s=make_bignum_string(sign->dsa_sign->s); 167 rs=string_new(40); 168 memset(buffer,0,40); 169 memcpy(buffer,r->string+string_len(r)-20,20); 170 memcpy(buffer+ 20, s->string + string_len(s) - 20, 20); 171 string_fill(rs,buffer,40); 172 free(r); 173 free(s); 174 buffer_add_ssh_string(tmpbuf,rs); 175 free(rs); 176 break; 177 case TYPE_RSA: 178 case TYPE_RSA1: 179 buffer_add_ssh_string(tmpbuf,sign->rsa_sign); 180 break; 181 } 182 str=string_new(buffer_get_len(tmpbuf)); 183 string_fill(str,buffer_get(tmpbuf),buffer_get_len(tmpbuf)); 184 buffer_free(tmpbuf); 185 return str; 186 } 187 188 /* TODO : split this function in two so it becomes smaller */ 189 SIGNATURE *signature_from_string(STRING *signature,PUBLIC_KEY *pubkey,int needed_type){ 190 DSA_SIG *sig; 191 SIGNATURE *sign=malloc(sizeof(SIGNATURE)); 192 BUFFER *tmpbuf=buffer_new(); 193 STRING *rs; 194 STRING *r,*s,*type_s,*e; 195 int len,rsalen; 196 char *type; 197 buffer_add_data(tmpbuf,signature->string,string_len(signature)); 198 type_s=buffer_get_ssh_string(tmpbuf); 199 if(!type_s){ 200 ssh_set_error(NULL,SSH_FATAL,"Invalid signature packet"); 201 buffer_free(tmpbuf); 202 return NULL; 203 } 204 type=string_to_char(type_s); 205 free(type_s); 206 switch(needed_type){ 207 case TYPE_DSS: 208 if(strcmp(type,"ssh-dss")){ 209 ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type); 210 buffer_free(tmpbuf); 211 free(type); 212 return NULL; 213 } 214 break; 215 case TYPE_RSA: 216 if(strcmp(type,"ssh-rsa")){ 217 ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type); 218 buffer_free(tmpbuf); 219 free(type); 220 return NULL; 221 } 222 break; 223 default: 224 ssh_set_error(NULL,SSH_FATAL,"Invalid signature type : %s",type); 225 free(type); 226 buffer_free(tmpbuf); 227 return NULL; 228 } 229 free(type); 230 switch(needed_type){ 231 case TYPE_DSS: 232 rs=buffer_get_ssh_string(tmpbuf); 233 buffer_free(tmpbuf); 234 if(!rs || string_len(rs)!=40){ /* 40 is the dual signature blob len. */ 235 if(rs) 236 free(rs); 237 return NULL; 238 } 239 /* we make use of strings because we have all-made functions to convert them to bignums */ 240 r=string_new(20); 241 s=string_new(20); 242 string_fill(r,rs->string,20); 243 string_fill(s,rs->string+20,20); 244 free(rs); 245 sig=DSA_SIG_new(); 246 sig->r=make_string_bn(r); /* is that really portable ? Openssh's hack isn't better */ 247 sig->s=make_string_bn(s); 248 #ifdef DEBUG_CRYPTO 249 ssh_print_bignum("r",sig->r); 250 ssh_print_bignum("s",sig->s); 251 #endif 252 free(r); 253 free(s); 254 sign->type=TYPE_DSS; 255 sign->dsa_sign=sig; 256 return sign; 257 case TYPE_RSA: 258 e=buffer_get_ssh_string(tmpbuf); 259 buffer_free(tmpbuf); 260 if(!e){ 261 free(e); 262 return NULL; 263 } 264 len=string_len(e); 265 rsalen=RSA_size(pubkey->rsa_pub); 266 if(len>rsalen){ 267 free(e); 268 free(sign); 269 ssh_set_error(NULL,SSH_FATAL,"signature too big ! %d instead of %d",len,rsalen); 270 return NULL; 271 } 272 if(len<rsalen) 273 ssh_say(0,"Len %d < %d\n",len,rsalen); 274 sign->type=TYPE_RSA; 275 sign->rsa_sign=e; 276 #ifdef DEBUG_CRYPTO 277 ssh_say(0,"Len : %d\n",len); 278 ssh_print_hexa("rsa signature",e->string,len); 279 #endif 280 return sign; 281 default: 282 return NULL; 283 } 284 } 285 286 void signature_free(SIGNATURE *sign){ 287 if(!sign) 288 return; 289 switch(sign->type){ 290 case TYPE_DSS: 291 DSA_SIG_free(sign->dsa_sign); 292 break; 293 case TYPE_RSA: 294 case TYPE_RSA1: 295 free(sign->rsa_sign); 296 break; 297 default: 298 ssh_say(1,"freeing a signature with no type !\n"); 299 } 300 free(sign); 301 } 302 303 /* maybe the missing function from libcrypto */ 304 /* i think now, maybe it's a bad idea to name it has it should have be named in libcrypto */ 305 static STRING *RSA_do_sign(void *payload,int len,RSA *privkey){ 306 STRING *sign; 307 void *buffer=malloc(RSA_size(privkey)); 308 unsigned int size; 309 int err; 310 err=RSA_sign(NID_sha1,payload,len,buffer,&size,privkey); 311 if(!err){ 312 free(buffer); 313 return NULL; 314 } 315 sign=string_new(size); 316 string_fill(sign,buffer,size); 317 free(buffer); 318 return sign; 319 } 320 321 STRING *ssh_do_sign(SSH_SESSION *session,BUFFER *sigbuf, PRIVATE_KEY *privatekey){ 322 SHACTX *ctx; 323 STRING *session_str=string_new(SHA_DIGEST_LEN); 324 char hash[SHA_DIGEST_LEN]; 325 SIGNATURE *sign; 326 STRING *signature; 327 string_fill(session_str,session->current_crypto->session_id,SHA_DIGEST_LENGTH); 328 ctx=sha1_init(); 329 sha1_update(ctx,session_str,string_len(session_str)+4); 330 sha1_update(ctx,buffer_get(sigbuf),buffer_get_len(sigbuf)); 331 sha1_final(hash,ctx); 332 free(session_str); 333 sign=malloc(sizeof(SIGNATURE)); 334 switch(privatekey->type){ 335 case TYPE_DSS: 336 sign->dsa_sign=DSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->dsa_priv); 337 sign->rsa_sign=NULL; 338 break; 339 case TYPE_RSA: 340 sign->rsa_sign=RSA_do_sign(hash,SHA_DIGEST_LENGTH,privatekey->rsa_priv); 341 sign->dsa_sign=NULL; 342 break; 343 } 344 sign->type=privatekey->type; 345 if(!sign->dsa_sign && !sign->rsa_sign){ 346 ssh_set_error(session,SSH_FATAL,"Signing : openssl error"); 347 signature_free(sign); 348 return NULL; 349 } 350 signature=signature_to_string(sign); 351 signature_free(sign); 352 return signature; 353 } |