1 /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
2  * Copyright (c) 2009-2014 by Daniel Stenberg
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms,
6  * with or without modification, are permitted provided
7  * that the following conditions are met:
8  *
9  *   Redistributions of source code must retain the above
10  *   copyright notice, this list of conditions and the
11  *   following disclaimer.
12  *
13  *   Redistributions in binary form must reproduce the above
14  *   copyright notice, this list of conditions and the following
15  *   disclaimer in the documentation and/or other materials
16  *   provided with the distribution.
17  *
18  *   Neither the name of the copyright holder nor the names
19  *   of any other contributors may be used to endorse or
20  *   promote products derived from this software without
21  *   specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
36  * OF SUCH DAMAGE.
37  */
38 
39 #include "libssh2_priv.h"
40 #include "misc.h"
41 
42 /* Needed for struct iovec on some platforms */
43 #ifdef HAVE_SYS_UIO_H
44 #include <sys/uio.h>
45 #endif
46 
47 #if LIBSSH2_RSA
48 /* ***********
49  * ssh-rsa *
50  *********** */
51 
52 static int hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,
53                                        void **abstract);
54 
55 /*
56  * hostkey_method_ssh_rsa_init
57  *
58  * Initialize the server hostkey working area with e/n pair
59  */
60 static int
hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,const unsigned char * hostkey_data,size_t hostkey_data_len,void ** abstract)61 hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
62                             const unsigned char *hostkey_data,
63                             size_t hostkey_data_len,
64                             void **abstract)
65 {
66     libssh2_rsa_ctx *rsactx;
67     const unsigned char *s, *e, *n;
68     unsigned long len, e_len, n_len;
69     int ret;
70 
71     (void) hostkey_data_len;
72 
73     if (*abstract) {
74         hostkey_method_ssh_rsa_dtor(session, abstract);
75         *abstract = NULL;
76     }
77 
78     s = hostkey_data;
79     len = _libssh2_ntohu32(s);
80     s += 4;
81 
82     if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
83         return -1;
84     }
85     s += 7;
86 
87     e_len = _libssh2_ntohu32(s);
88     s += 4;
89 
90     e = s;
91     s += e_len;
92     n_len = _libssh2_ntohu32(s);
93     s += 4;
94     n = s;
95 
96     ret = _libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
97                      NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0);
98     if (ret) {
99         return -1;
100     }
101 
102     *abstract = rsactx;
103 
104     return 0;
105 }
106 
107 /*
108  * hostkey_method_ssh_rsa_initPEM
109  *
110  * Load a Private Key from a PEM file
111  */
112 static int
hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,const char * privkeyfile,unsigned const char * passphrase,void ** abstract)113 hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
114                                const char *privkeyfile,
115                                unsigned const char *passphrase,
116                                void **abstract)
117 {
118     libssh2_rsa_ctx *rsactx;
119     int ret;
120 
121     if (*abstract) {
122         hostkey_method_ssh_rsa_dtor(session, abstract);
123         *abstract = NULL;
124     }
125 
126     ret = _libssh2_rsa_new_private(&rsactx, session, privkeyfile, passphrase);
127     if (ret) {
128         return -1;
129     }
130 
131     *abstract = rsactx;
132 
133     return 0;
134 }
135 
136 /*
137  * hostkey_method_ssh_rsa_initPEMFromMemory
138  *
139  * Load a Private Key from a memory
140  */
141 static int
hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,const char * privkeyfiledata,size_t privkeyfiledata_len,unsigned const char * passphrase,void ** abstract)142 hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,
143                                          const char *privkeyfiledata,
144                                          size_t privkeyfiledata_len,
145                                          unsigned const char *passphrase,
146                                          void **abstract)
147 {
148     libssh2_rsa_ctx *rsactx;
149     int ret;
150 
151     if (*abstract) {
152         hostkey_method_ssh_rsa_dtor(session, abstract);
153         *abstract = NULL;
154     }
155 
156     ret = _libssh2_rsa_new_private_frommemory(&rsactx, session,
157                                               privkeyfiledata,
158                                               privkeyfiledata_len, passphrase);
159     if (ret) {
160         return -1;
161     }
162 
163     *abstract = rsactx;
164 
165     return 0;
166 }
167 
168 /*
169  * hostkey_method_ssh_rsa_sign
170  *
171  * Verify signature created by remote
172  */
173 static int
hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,const unsigned char * sig,size_t sig_len,const unsigned char * m,size_t m_len,void ** abstract)174 hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
175                                   const unsigned char *sig,
176                                   size_t sig_len,
177                                   const unsigned char *m,
178                                   size_t m_len, void **abstract)
179 {
180     libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
181     (void) session;
182 
183     /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
184     sig += 15;
185     sig_len -= 15;
186     return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
187 }
188 
189 /*
190  * hostkey_method_ssh_rsa_signv
191  *
192  * Construct a signature from an array of vectors
193  */
194 static int
hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,unsigned char ** signature,size_t * signature_len,int veccount,const struct iovec datavec[],void ** abstract)195 hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
196                              unsigned char **signature,
197                              size_t *signature_len,
198                              int veccount,
199                              const struct iovec datavec[],
200                              void **abstract)
201 {
202     libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
203     int ret;
204     int i;
205     unsigned char hash[SHA_DIGEST_LENGTH];
206     libssh2_sha1_ctx ctx;
207 
208     libssh2_sha1_init(&ctx);
209     for(i = 0; i < veccount; i++) {
210         libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
211     }
212     libssh2_sha1_final(ctx, hash);
213 
214     ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
215                                  signature, signature_len);
216     if (ret) {
217         return -1;
218     }
219 
220     return 0;
221 }
222 
223 /*
224  * hostkey_method_ssh_rsa_dtor
225  *
226  * Shutdown the hostkey
227  */
228 static int
hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,void ** abstract)229 hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract)
230 {
231     libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
232     (void) session;
233 
234     _libssh2_rsa_free(rsactx);
235 
236     *abstract = NULL;
237 
238     return 0;
239 }
240 
241 #ifdef OPENSSL_NO_MD5
242 #define MD5_DIGEST_LENGTH 16
243 #endif
244 
245 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = {
246     "ssh-rsa",
247     MD5_DIGEST_LENGTH,
248     hostkey_method_ssh_rsa_init,
249     hostkey_method_ssh_rsa_initPEM,
250     hostkey_method_ssh_rsa_initPEMFromMemory,
251     hostkey_method_ssh_rsa_sig_verify,
252     hostkey_method_ssh_rsa_signv,
253     NULL,                       /* encrypt */
254     hostkey_method_ssh_rsa_dtor,
255 };
256 #endif /* LIBSSH2_RSA */
257 
258 #if LIBSSH2_DSA
259 /* ***********
260  * ssh-dss *
261  *********** */
262 
263 static int hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,
264                                        void **abstract);
265 
266 /*
267  * hostkey_method_ssh_dss_init
268  *
269  * Initialize the server hostkey working area with p/q/g/y set
270  */
271 static int
hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,const unsigned char * hostkey_data,size_t hostkey_data_len,void ** abstract)272 hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
273                             const unsigned char *hostkey_data,
274                             size_t hostkey_data_len,
275                             void **abstract)
276 {
277     libssh2_dsa_ctx *dsactx;
278     const unsigned char *p, *q, *g, *y, *s;
279     unsigned long p_len, q_len, g_len, y_len, len;
280 	int ret;
281     (void) hostkey_data_len;
282 
283     if (*abstract) {
284         hostkey_method_ssh_dss_dtor(session, abstract);
285         *abstract = NULL;
286     }
287 
288     s = hostkey_data;
289     len = _libssh2_ntohu32(s);
290     s += 4;
291     if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
292         return -1;
293     }
294     s += 7;
295 
296     p_len = _libssh2_ntohu32(s);
297     s += 4;
298     p = s;
299     s += p_len;
300     q_len = _libssh2_ntohu32(s);
301     s += 4;
302     q = s;
303     s += q_len;
304     g_len = _libssh2_ntohu32(s);
305     s += 4;
306     g = s;
307     s += g_len;
308     y_len = _libssh2_ntohu32(s);
309     s += 4;
310     y = s;
311     /* s += y_len; */
312 
313     ret = _libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
314                            g, g_len, y, y_len, NULL, 0);
315     if (ret) {
316         return -1;
317     }
318 
319     *abstract = dsactx;
320 
321     return 0;
322 }
323 
324 /*
325  * hostkey_method_ssh_dss_initPEM
326  *
327  * Load a Private Key from a PEM file
328  */
329 static int
hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,const char * privkeyfile,unsigned const char * passphrase,void ** abstract)330 hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
331                                const char *privkeyfile,
332                                unsigned const char *passphrase,
333                                void **abstract)
334 {
335     libssh2_dsa_ctx *dsactx;
336     int ret;
337 
338     if (*abstract) {
339         hostkey_method_ssh_dss_dtor(session, abstract);
340         *abstract = NULL;
341     }
342 
343     ret = _libssh2_dsa_new_private(&dsactx, session, privkeyfile, passphrase);
344     if (ret) {
345         return -1;
346     }
347 
348     *abstract = dsactx;
349 
350     return 0;
351 }
352 
353 /*
354  * hostkey_method_ssh_dss_initPEMFromMemory
355  *
356  * Load a Private Key from memory
357  */
358 static int
hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,const char * privkeyfiledata,size_t privkeyfiledata_len,unsigned const char * passphrase,void ** abstract)359 hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,
360                                          const char *privkeyfiledata,
361                                          size_t privkeyfiledata_len,
362                                          unsigned const char *passphrase,
363                                          void **abstract)
364 {
365     libssh2_dsa_ctx *dsactx;
366     int ret;
367 
368     if (*abstract) {
369         hostkey_method_ssh_dss_dtor(session, abstract);
370         *abstract = NULL;
371     }
372 
373     ret = _libssh2_dsa_new_private_frommemory(&dsactx, session,
374                                               privkeyfiledata,
375                                               privkeyfiledata_len, passphrase);
376     if (ret) {
377         return -1;
378     }
379 
380     *abstract = dsactx;
381 
382     return 0;
383 }
384 
385 /*
386  * libssh2_hostkey_method_ssh_dss_sign
387  *
388  * Verify signature created by remote
389  */
390 static int
hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,const unsigned char * sig,size_t sig_len,const unsigned char * m,size_t m_len,void ** abstract)391 hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
392                                   const unsigned char *sig,
393                                   size_t sig_len,
394                                   const unsigned char *m,
395                                   size_t m_len, void **abstract)
396 {
397     libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
398 
399     /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
400     sig += 15;
401     sig_len -= 15;
402     if (sig_len != 40) {
403         return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
404                               "Invalid DSS signature length");
405     }
406     return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
407 }
408 
409 /*
410  * hostkey_method_ssh_dss_signv
411  *
412  * Construct a signature from an array of vectors
413  */
414 static int
hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,unsigned char ** signature,size_t * signature_len,int veccount,const struct iovec datavec[],void ** abstract)415 hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
416                              unsigned char **signature,
417                              size_t *signature_len,
418                              int veccount,
419                              const struct iovec datavec[],
420                              void **abstract)
421 {
422     libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
423     unsigned char hash[SHA_DIGEST_LENGTH];
424     libssh2_sha1_ctx ctx;
425     int i;
426 
427     *signature = LIBSSH2_CALLOC(session, 2 * SHA_DIGEST_LENGTH);
428     if (!*signature) {
429         return -1;
430     }
431 
432     *signature_len = 2 * SHA_DIGEST_LENGTH;
433 
434     libssh2_sha1_init(&ctx);
435     for(i = 0; i < veccount; i++) {
436         libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
437     }
438     libssh2_sha1_final(ctx, hash);
439 
440     if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
441         LIBSSH2_FREE(session, *signature);
442         return -1;
443     }
444 
445     return 0;
446 }
447 
448 /*
449  * libssh2_hostkey_method_ssh_dss_dtor
450  *
451  * Shutdown the hostkey method
452  */
453 static int
hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,void ** abstract)454 hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract)
455 {
456     libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
457     (void) session;
458 
459     _libssh2_dsa_free(dsactx);
460 
461     *abstract = NULL;
462 
463     return 0;
464 }
465 
466 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = {
467     "ssh-dss",
468     MD5_DIGEST_LENGTH,
469     hostkey_method_ssh_dss_init,
470     hostkey_method_ssh_dss_initPEM,
471     hostkey_method_ssh_dss_initPEMFromMemory,
472     hostkey_method_ssh_dss_sig_verify,
473     hostkey_method_ssh_dss_signv,
474     NULL,                       /* encrypt */
475     hostkey_method_ssh_dss_dtor,
476 };
477 #endif /* LIBSSH2_DSA */
478 
479 static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = {
480 #if LIBSSH2_RSA
481     &hostkey_method_ssh_rsa,
482 #endif /* LIBSSH2_RSA */
483 #if LIBSSH2_DSA
484     &hostkey_method_ssh_dss,
485 #endif /* LIBSSH2_DSA */
486     NULL
487 };
488 
489 const LIBSSH2_HOSTKEY_METHOD **
libssh2_hostkey_methods(void)490 libssh2_hostkey_methods(void)
491 {
492     return hostkey_methods;
493 }
494 
495 /*
496  * libssh2_hostkey_hash
497  *
498  * Returns hash signature
499  * Returned buffer should NOT be freed
500  * Length of buffer is determined by hash type
501  * i.e. MD5 == 16, SHA1 == 20
502  */
503 LIBSSH2_API const char *
libssh2_hostkey_hash(LIBSSH2_SESSION * session,int hash_type)504 libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
505 {
506     switch (hash_type) {
507 #if LIBSSH2_MD5
508     case LIBSSH2_HOSTKEY_HASH_MD5:
509         return (session->server_hostkey_md5_valid)
510           ? (char *) session->server_hostkey_md5
511           : NULL;
512         break;
513 #endif /* LIBSSH2_MD5 */
514     case LIBSSH2_HOSTKEY_HASH_SHA1:
515         return (session->server_hostkey_sha1_valid)
516           ? (char *) session->server_hostkey_sha1
517           : NULL;
518         break;
519     default:
520         return NULL;
521     }
522 }
523 
hostkey_type(const unsigned char * hostkey,size_t len)524 static int hostkey_type(const unsigned char *hostkey, size_t len)
525 {
526     const unsigned char rsa[] = {
527         0, 0, 0, 0x07, 's', 's', 'h', '-', 'r', 's', 'a'
528     };
529     const unsigned char dss[] = {
530         0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's'
531     };
532 
533     if (len < 11)
534         return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
535 
536     if (!memcmp(rsa, hostkey, 11))
537         return LIBSSH2_HOSTKEY_TYPE_RSA;
538 
539     if (!memcmp(dss, hostkey, 11))
540         return LIBSSH2_HOSTKEY_TYPE_DSS;
541 
542     return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
543 }
544 
545 /*
546  * libssh2_session_hostkey()
547  *
548  * Returns the server key and length.
549  *
550  */
551 LIBSSH2_API const char *
libssh2_session_hostkey(LIBSSH2_SESSION * session,size_t * len,int * type)552 libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len, int *type)
553 {
554     if(session->server_hostkey_len) {
555         if(len)
556             *len = session->server_hostkey_len;
557         if (type)
558             *type = hostkey_type(session->server_hostkey,
559                                  session->server_hostkey_len);
560         return (char *) session->server_hostkey;
561     }
562     if(len)
563         *len = 0;
564     return NULL;
565 }
566 
567