5772786 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$ cat -n keys.c
  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 }
5772787 [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: 2005-03-04 19:54:59