1 /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
2  * Copyright (c) 2009-2019 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     unsigned char *e, *n;
68     size_t e_len, n_len;
69     struct string_buf buf;
70 
71     if(*abstract) {
72         hostkey_method_ssh_rsa_dtor(session, abstract);
73         *abstract = NULL;
74     }
75 
76     if(hostkey_data_len < 19) {
77         _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
78                        "host key length too short");
79         return -1;
80     }
81 
82     buf.data = (unsigned char *)hostkey_data;
83     buf.dataptr = buf.data;
84     buf.len = hostkey_data_len;
85 
86     if(_libssh2_match_string(&buf, "ssh-rsa"))
87         return -1;
88 
89     if(_libssh2_get_string(&buf, &e, &e_len))
90         return -1;
91 
92     if(_libssh2_get_string(&buf, &n, &n_len))
93         return -1;
94 
95     if(_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
96                         NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) {
97         return -1;
98     }
99 
100     *abstract = rsactx;
101 
102     return 0;
103 }
104 
105 /*
106  * hostkey_method_ssh_rsa_initPEM
107  *
108  * Load a Private Key from a PEM file
109  */
110 static int
hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,const char * privkeyfile,unsigned const char * passphrase,void ** abstract)111 hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
112                                const char *privkeyfile,
113                                unsigned const char *passphrase,
114                                void **abstract)
115 {
116     libssh2_rsa_ctx *rsactx;
117     int ret;
118 
119     if(*abstract) {
120         hostkey_method_ssh_rsa_dtor(session, abstract);
121         *abstract = NULL;
122     }
123 
124     ret = _libssh2_rsa_new_private(&rsactx, session, privkeyfile, passphrase);
125     if(ret) {
126         return -1;
127     }
128 
129     *abstract = rsactx;
130 
131     return 0;
132 }
133 
134 /*
135  * hostkey_method_ssh_rsa_initPEMFromMemory
136  *
137  * Load a Private Key from a memory
138  */
139 static int
hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,const char * privkeyfiledata,size_t privkeyfiledata_len,unsigned const char * passphrase,void ** abstract)140 hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,
141                                          const char *privkeyfiledata,
142                                          size_t privkeyfiledata_len,
143                                          unsigned const char *passphrase,
144                                          void **abstract)
145 {
146     libssh2_rsa_ctx *rsactx;
147     int ret;
148 
149     if(*abstract) {
150         hostkey_method_ssh_rsa_dtor(session, abstract);
151         *abstract = NULL;
152     }
153 
154     ret = _libssh2_rsa_new_private_frommemory(&rsactx, session,
155                                               privkeyfiledata,
156                                               privkeyfiledata_len, passphrase);
157     if(ret) {
158         return -1;
159     }
160 
161     *abstract = rsactx;
162 
163     return 0;
164 }
165 
166 /*
167  * hostkey_method_ssh_rsa_sign
168  *
169  * Verify signature created by remote
170  */
171 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)172 hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
173                                   const unsigned char *sig,
174                                   size_t sig_len,
175                                   const unsigned char *m,
176                                   size_t m_len, void **abstract)
177 {
178     libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
179     (void) session;
180 
181     /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
182     if(sig_len < 15)
183         return -1;
184 
185     sig += 15;
186     sig_len -= 15;
187     return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
188 }
189 
190 /*
191  * hostkey_method_ssh_rsa_signv
192  *
193  * Construct a signature from an array of vectors
194  */
195 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)196 hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
197                              unsigned char **signature,
198                              size_t *signature_len,
199                              int veccount,
200                              const struct iovec datavec[],
201                              void **abstract)
202 {
203     libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
204 
205 #ifdef _libssh2_rsa_sha1_signv
206     return _libssh2_rsa_sha1_signv(session, signature, signature_len,
207                                    veccount, datavec, rsactx);
208 #else
209     int ret;
210     int i;
211     unsigned char hash[SHA_DIGEST_LENGTH];
212     libssh2_sha1_ctx ctx;
213 
214     libssh2_sha1_init(&ctx);
215     for(i = 0; i < veccount; i++) {
216         libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
217     }
218     libssh2_sha1_final(ctx, hash);
219 
220     ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
221                                  signature, signature_len);
222     if(ret) {
223         return -1;
224     }
225 
226     return 0;
227 #endif
228 }
229 
230 /*
231  * hostkey_method_ssh_rsa_dtor
232  *
233  * Shutdown the hostkey
234  */
235 static int
hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,void ** abstract)236 hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract)
237 {
238     libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
239     (void) session;
240 
241     _libssh2_rsa_free(rsactx);
242 
243     *abstract = NULL;
244 
245     return 0;
246 }
247 
248 #ifdef OPENSSL_NO_MD5
249 #define MD5_DIGEST_LENGTH 16
250 #endif
251 
252 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = {
253     "ssh-rsa",
254     MD5_DIGEST_LENGTH,
255     hostkey_method_ssh_rsa_init,
256     hostkey_method_ssh_rsa_initPEM,
257     hostkey_method_ssh_rsa_initPEMFromMemory,
258     hostkey_method_ssh_rsa_sig_verify,
259     hostkey_method_ssh_rsa_signv,
260     NULL,                       /* encrypt */
261     hostkey_method_ssh_rsa_dtor,
262 };
263 #endif /* LIBSSH2_RSA */
264 
265 #if LIBSSH2_DSA
266 /* ***********
267  * ssh-dss *
268  *********** */
269 
270 static int hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,
271                                        void **abstract);
272 
273 /*
274  * hostkey_method_ssh_dss_init
275  *
276  * Initialize the server hostkey working area with p/q/g/y set
277  */
278 static int
hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,const unsigned char * hostkey_data,size_t hostkey_data_len,void ** abstract)279 hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
280                             const unsigned char *hostkey_data,
281                             size_t hostkey_data_len,
282                             void **abstract)
283 {
284     libssh2_dsa_ctx *dsactx;
285     unsigned char *p, *q, *g, *y;
286     size_t p_len, q_len, g_len, y_len;
287     struct string_buf buf;
288 
289     if(*abstract) {
290         hostkey_method_ssh_dss_dtor(session, abstract);
291         *abstract = NULL;
292     }
293 
294     if(hostkey_data_len < 27) {
295         _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
296                        "host key length too short");
297         return -1;
298     }
299 
300     buf.data = (unsigned char *)hostkey_data;
301     buf.dataptr = buf.data;
302     buf.len = hostkey_data_len;
303 
304     if(_libssh2_match_string(&buf, "ssh-dss"))
305         return -1;
306 
307     if(_libssh2_get_string(&buf, &p, &p_len))
308        return -1;
309 
310     if(_libssh2_get_string(&buf, &q, &q_len))
311         return -1;
312 
313     if(_libssh2_get_string(&buf, &g, &g_len))
314         return -1;
315 
316     if(_libssh2_get_string(&buf, &y, &y_len))
317         return -1;
318 
319     if(_libssh2_dsa_new(&dsactx, p, p_len, q, q_len,
320                         g, g_len, y, y_len, NULL, 0)) {
321         return -1;
322     }
323 
324     *abstract = dsactx;
325 
326     return 0;
327 }
328 
329 /*
330  * hostkey_method_ssh_dss_initPEM
331  *
332  * Load a Private Key from a PEM file
333  */
334 static int
hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,const char * privkeyfile,unsigned const char * passphrase,void ** abstract)335 hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
336                                const char *privkeyfile,
337                                unsigned const char *passphrase,
338                                void **abstract)
339 {
340     libssh2_dsa_ctx *dsactx;
341     int ret;
342 
343     if(*abstract) {
344         hostkey_method_ssh_dss_dtor(session, abstract);
345         *abstract = NULL;
346     }
347 
348     ret = _libssh2_dsa_new_private(&dsactx, session, privkeyfile, passphrase);
349     if(ret) {
350         return -1;
351     }
352 
353     *abstract = dsactx;
354 
355     return 0;
356 }
357 
358 /*
359  * hostkey_method_ssh_dss_initPEMFromMemory
360  *
361  * Load a Private Key from memory
362  */
363 static int
hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,const char * privkeyfiledata,size_t privkeyfiledata_len,unsigned const char * passphrase,void ** abstract)364 hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,
365                                          const char *privkeyfiledata,
366                                          size_t privkeyfiledata_len,
367                                          unsigned const char *passphrase,
368                                          void **abstract)
369 {
370     libssh2_dsa_ctx *dsactx;
371     int ret;
372 
373     if(*abstract) {
374         hostkey_method_ssh_dss_dtor(session, abstract);
375         *abstract = NULL;
376     }
377 
378     ret = _libssh2_dsa_new_private_frommemory(&dsactx, session,
379                                               privkeyfiledata,
380                                               privkeyfiledata_len, passphrase);
381     if(ret) {
382         return -1;
383     }
384 
385     *abstract = dsactx;
386 
387     return 0;
388 }
389 
390 /*
391  * libssh2_hostkey_method_ssh_dss_sign
392  *
393  * Verify signature created by remote
394  */
395 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)396 hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
397                                   const unsigned char *sig,
398                                   size_t sig_len,
399                                   const unsigned char *m,
400                                   size_t m_len, void **abstract)
401 {
402     libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
403 
404     /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
405     if(sig_len != 55) {
406         return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
407                               "Invalid DSS signature length");
408     }
409 
410     sig += 15;
411     sig_len -= 15;
412 
413     return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
414 }
415 
416 /*
417  * hostkey_method_ssh_dss_signv
418  *
419  * Construct a signature from an array of vectors
420  */
421 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)422 hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
423                              unsigned char **signature,
424                              size_t *signature_len,
425                              int veccount,
426                              const struct iovec datavec[],
427                              void **abstract)
428 {
429     libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
430     unsigned char hash[SHA_DIGEST_LENGTH];
431     libssh2_sha1_ctx ctx;
432     int i;
433 
434     *signature = LIBSSH2_CALLOC(session, 2 * SHA_DIGEST_LENGTH);
435     if(!*signature) {
436         return -1;
437     }
438 
439     *signature_len = 2 * SHA_DIGEST_LENGTH;
440 
441     libssh2_sha1_init(&ctx);
442     for(i = 0; i < veccount; i++) {
443         libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
444     }
445     libssh2_sha1_final(ctx, hash);
446 
447     if(_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
448         LIBSSH2_FREE(session, *signature);
449         return -1;
450     }
451 
452     return 0;
453 }
454 
455 /*
456  * libssh2_hostkey_method_ssh_dss_dtor
457  *
458  * Shutdown the hostkey method
459  */
460 static int
hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,void ** abstract)461 hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract)
462 {
463     libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
464     (void) session;
465 
466     _libssh2_dsa_free(dsactx);
467 
468     *abstract = NULL;
469 
470     return 0;
471 }
472 
473 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = {
474     "ssh-dss",
475     MD5_DIGEST_LENGTH,
476     hostkey_method_ssh_dss_init,
477     hostkey_method_ssh_dss_initPEM,
478     hostkey_method_ssh_dss_initPEMFromMemory,
479     hostkey_method_ssh_dss_sig_verify,
480     hostkey_method_ssh_dss_signv,
481     NULL,                       /* encrypt */
482     hostkey_method_ssh_dss_dtor,
483 };
484 #endif /* LIBSSH2_DSA */
485 
486 #if LIBSSH2_ECDSA
487 
488 /* ***********
489  * ecdsa-sha2-nistp256/384/521 *
490  *********** */
491 
492 static int
493 hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session,
494                               void **abstract);
495 
496 /*
497  * hostkey_method_ssh_ecdsa_init
498  *
499  * Initialize the server hostkey working area with e/n pair
500  */
501 static int
hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session,const unsigned char * hostkey_data,size_t hostkey_data_len,void ** abstract)502 hostkey_method_ssh_ecdsa_init(LIBSSH2_SESSION * session,
503                           const unsigned char *hostkey_data,
504                           size_t hostkey_data_len,
505                           void **abstract)
506 {
507     libssh2_ecdsa_ctx *ecdsactx = NULL;
508     unsigned char *type_str, *domain, *public_key;
509     size_t key_len, len;
510     libssh2_curve_type type;
511     struct string_buf buf;
512 
513     if(abstract != NULL && *abstract) {
514         hostkey_method_ssh_ecdsa_dtor(session, abstract);
515         *abstract = NULL;
516     }
517 
518     if(hostkey_data_len < 39) {
519         _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
520                        "host key length too short");
521         return -1;
522     }
523 
524     buf.data = (unsigned char *)hostkey_data;
525     buf.dataptr = buf.data;
526     buf.len = hostkey_data_len;
527 
528     if(_libssh2_get_string(&buf, &type_str, &len) || len != 19)
529         return -1;
530 
531     if(strncmp((char *) type_str, "ecdsa-sha2-nistp256", 19) == 0) {
532         type = LIBSSH2_EC_CURVE_NISTP256;
533     }
534     else if(strncmp((char *) type_str, "ecdsa-sha2-nistp384", 19) == 0) {
535         type = LIBSSH2_EC_CURVE_NISTP384;
536     }
537     else if(strncmp((char *) type_str, "ecdsa-sha2-nistp521", 19) == 0) {
538         type = LIBSSH2_EC_CURVE_NISTP521;
539     }
540     else {
541         return -1;
542     }
543 
544     if(_libssh2_get_string(&buf, &domain, &len) || len != 8)
545         return -1;
546 
547     if(type == LIBSSH2_EC_CURVE_NISTP256 &&
548        strncmp((char *)domain, "nistp256", 8) != 0) {
549         return -1;
550     }
551     else if(type == LIBSSH2_EC_CURVE_NISTP384 &&
552             strncmp((char *)domain, "nistp384", 8) != 0) {
553         return -1;
554     }
555     else if(type == LIBSSH2_EC_CURVE_NISTP521 &&
556             strncmp((char *)domain, "nistp521", 8) != 0) {
557         return -1;
558     }
559 
560     /* public key */
561     if(_libssh2_get_string(&buf, &public_key, &key_len))
562         return -1;
563 
564     if(_libssh2_ecdsa_curve_name_with_octal_new(&ecdsactx, public_key,
565                                                 key_len, type))
566         return -1;
567 
568     if(abstract != NULL)
569         *abstract = ecdsactx;
570 
571     return 0;
572 }
573 
574 /*
575  * hostkey_method_ssh_ecdsa_initPEM
576  *
577  * Load a Private Key from a PEM file
578  */
579 static int
hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session,const char * privkeyfile,unsigned const char * passphrase,void ** abstract)580 hostkey_method_ssh_ecdsa_initPEM(LIBSSH2_SESSION * session,
581                              const char *privkeyfile,
582                              unsigned const char *passphrase,
583                              void **abstract)
584 {
585     libssh2_ecdsa_ctx *ec_ctx = NULL;
586     int ret;
587 
588     if(abstract != NULL && *abstract) {
589         hostkey_method_ssh_ecdsa_dtor(session, abstract);
590         *abstract = NULL;
591     }
592 
593     ret = _libssh2_ecdsa_new_private(&ec_ctx, session,
594                                      privkeyfile, passphrase);
595 
596     if(abstract != NULL)
597         *abstract = ec_ctx;
598 
599     return ret;
600 }
601 
602 /*
603  * hostkey_method_ssh_ecdsa_initPEMFromMemory
604  *
605  * Load a Private Key from memory
606  */
607 static int
hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session,const char * privkeyfiledata,size_t privkeyfiledata_len,unsigned const char * passphrase,void ** abstract)608 hostkey_method_ssh_ecdsa_initPEMFromMemory(LIBSSH2_SESSION * session,
609                                          const char *privkeyfiledata,
610                                          size_t privkeyfiledata_len,
611                                          unsigned const char *passphrase,
612                                          void **abstract)
613 {
614     libssh2_ecdsa_ctx *ec_ctx = NULL;
615     int ret;
616 
617     if(abstract != NULL && *abstract) {
618         hostkey_method_ssh_ecdsa_dtor(session, abstract);
619         *abstract = NULL;
620     }
621 
622     ret = _libssh2_ecdsa_new_private_frommemory(&ec_ctx, session,
623                                                 privkeyfiledata,
624                                                 privkeyfiledata_len,
625                                                 passphrase);
626     if(ret) {
627         return -1;
628     }
629 
630     if(abstract != NULL)
631         *abstract = ec_ctx;
632 
633     return 0;
634 }
635 
636 /*
637  * hostkey_method_ecdsa_sig_verify
638  *
639  * Verify signature created by remote
640  */
641 static int
hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,const unsigned char * sig,size_t sig_len,const unsigned char * m,size_t m_len,void ** abstract)642 hostkey_method_ssh_ecdsa_sig_verify(LIBSSH2_SESSION * session,
643                                     const unsigned char *sig,
644                                     size_t sig_len,
645                                     const unsigned char *m,
646                                     size_t m_len, void **abstract)
647 {
648     unsigned char *r, *s, *name;
649     size_t r_len, s_len, name_len;
650     unsigned int len;
651     struct string_buf buf;
652     libssh2_ecdsa_ctx *ctx = (libssh2_ecdsa_ctx *) (*abstract);
653 
654     (void) session;
655 
656     if(sig_len < 35)
657         return -1;
658 
659     /* keyname_len(4) + keyname(19){"ecdsa-sha2-nistp256"} +
660        signature_len(4) */
661     buf.data = (unsigned char *)sig;
662     buf.dataptr = buf.data;
663     buf.len = sig_len;
664 
665    if(_libssh2_get_string(&buf, &name, &name_len) || name_len != 19)
666         return -1;
667 
668     if(_libssh2_get_u32(&buf, &len) != 0 || len < 8)
669         return -1;
670 
671     if(_libssh2_get_string(&buf, &r, &r_len))
672        return -1;
673 
674     if(_libssh2_get_string(&buf, &s, &s_len))
675         return -1;
676 
677     return _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len);
678 }
679 
680 
681 #define LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(digest_type)               \
682     {                                                                   \
683         unsigned char hash[SHA##digest_type##_DIGEST_LENGTH];           \
684         libssh2_sha##digest_type##_ctx ctx;                             \
685         int i;                                                          \
686         libssh2_sha##digest_type##_init(&ctx);                          \
687         for(i = 0; i < veccount; i++) {                                 \
688             libssh2_sha##digest_type##_update(ctx, datavec[i].iov_base, \
689                                               datavec[i].iov_len);      \
690         }                                                               \
691         libssh2_sha##digest_type##_final(ctx, hash);                    \
692         ret = _libssh2_ecdsa_sign(session, ec_ctx, hash,                \
693                                   SHA##digest_type##_DIGEST_LENGTH,     \
694                                   signature, signature_len);            \
695     }
696 
697 
698 /*
699  * hostkey_method_ecdsa_signv
700  *
701  * Construct a signature from an array of vectors
702  */
703 static int
hostkey_method_ssh_ecdsa_signv(LIBSSH2_SESSION * session,unsigned char ** signature,size_t * signature_len,int veccount,const struct iovec datavec[],void ** abstract)704 hostkey_method_ssh_ecdsa_signv(LIBSSH2_SESSION * session,
705                                unsigned char **signature,
706                                size_t *signature_len,
707                                int veccount,
708                                const struct iovec datavec[],
709                                void **abstract)
710 {
711     libssh2_ecdsa_ctx *ec_ctx = (libssh2_ecdsa_ctx *) (*abstract);
712     libssh2_curve_type type = _libssh2_ecdsa_key_get_curve_type(ec_ctx);
713     int ret = 0;
714 
715     if(type == LIBSSH2_EC_CURVE_NISTP256) {
716         LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(256);
717     }
718     else if(type == LIBSSH2_EC_CURVE_NISTP384) {
719         LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(384);
720     }
721     else if(type == LIBSSH2_EC_CURVE_NISTP521) {
722         LIBSSH2_HOSTKEY_METHOD_EC_SIGNV_HASH(512);
723     }
724     else {
725         return -1;
726     }
727 
728     return ret;
729 }
730 
731 /*
732  * hostkey_method_ssh_ecdsa_dtor
733  *
734  * Shutdown the hostkey by freeing EC_KEY context
735  */
736 static int
hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session,void ** abstract)737 hostkey_method_ssh_ecdsa_dtor(LIBSSH2_SESSION * session, void **abstract)
738 {
739     libssh2_ecdsa_ctx *keyctx = (libssh2_ecdsa_ctx *) (*abstract);
740     (void) session;
741 
742     if(keyctx != NULL)
743         _libssh2_ecdsa_free(keyctx);
744 
745     *abstract = NULL;
746 
747     return 0;
748 }
749 
750 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp256 = {
751     "ecdsa-sha2-nistp256",
752     SHA256_DIGEST_LENGTH,
753     hostkey_method_ssh_ecdsa_init,
754     hostkey_method_ssh_ecdsa_initPEM,
755     hostkey_method_ssh_ecdsa_initPEMFromMemory,
756     hostkey_method_ssh_ecdsa_sig_verify,
757     hostkey_method_ssh_ecdsa_signv,
758     NULL,                       /* encrypt */
759     hostkey_method_ssh_ecdsa_dtor,
760 };
761 
762 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp384 = {
763     "ecdsa-sha2-nistp384",
764     SHA384_DIGEST_LENGTH,
765     hostkey_method_ssh_ecdsa_init,
766     hostkey_method_ssh_ecdsa_initPEM,
767     hostkey_method_ssh_ecdsa_initPEMFromMemory,
768     hostkey_method_ssh_ecdsa_sig_verify,
769     hostkey_method_ssh_ecdsa_signv,
770     NULL,                       /* encrypt */
771     hostkey_method_ssh_ecdsa_dtor,
772 };
773 
774 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ecdsa_ssh_nistp521 = {
775     "ecdsa-sha2-nistp521",
776     SHA512_DIGEST_LENGTH,
777     hostkey_method_ssh_ecdsa_init,
778     hostkey_method_ssh_ecdsa_initPEM,
779     hostkey_method_ssh_ecdsa_initPEMFromMemory,
780     hostkey_method_ssh_ecdsa_sig_verify,
781     hostkey_method_ssh_ecdsa_signv,
782     NULL,                       /* encrypt */
783     hostkey_method_ssh_ecdsa_dtor,
784 };
785 
786 #endif /* LIBSSH2_ECDSA */
787 
788 #if LIBSSH2_ED25519
789 
790 /* ***********
791  * ed25519 *
792  *********** */
793 
794 static int hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session,
795                                            void **abstract);
796 
797 /*
798  * hostkey_method_ssh_ed25519_init
799  *
800  * Initialize the server hostkey working area with e/n pair
801  */
802 static int
hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session,const unsigned char * hostkey_data,size_t hostkey_data_len,void ** abstract)803 hostkey_method_ssh_ed25519_init(LIBSSH2_SESSION * session,
804                                 const unsigned char *hostkey_data,
805                                 size_t hostkey_data_len,
806                                 void **abstract)
807 {
808     const unsigned char *s;
809     unsigned long len, key_len;
810     libssh2_ed25519_ctx *ctx = NULL;
811 
812     if(*abstract) {
813         hostkey_method_ssh_ed25519_dtor(session, abstract);
814         *abstract = NULL;
815     }
816 
817     if(hostkey_data_len < 19) {
818         _libssh2_debug(session, LIBSSH2_TRACE_ERROR,
819                        "host key length too short");
820         return -1;
821     }
822 
823     s = hostkey_data;
824     len = _libssh2_ntohu32(s);
825     s += 4;
826 
827     if(len != 11 || strncmp((char *) s, "ssh-ed25519", 11) != 0) {
828         return -1;
829     }
830 
831     s += 11;
832 
833     /* public key */
834     key_len = _libssh2_ntohu32(s);
835     s += 4;
836 
837     if(_libssh2_ed25519_new_public(&ctx, session, s, key_len) != 0) {
838         return -1;
839     }
840 
841     *abstract = ctx;
842 
843     return 0;
844 }
845 
846 /*
847  * hostkey_method_ssh_ed25519_initPEM
848  *
849  * Load a Private Key from a PEM file
850  */
851 static int
hostkey_method_ssh_ed25519_initPEM(LIBSSH2_SESSION * session,const char * privkeyfile,unsigned const char * passphrase,void ** abstract)852 hostkey_method_ssh_ed25519_initPEM(LIBSSH2_SESSION * session,
853                              const char *privkeyfile,
854                              unsigned const char *passphrase,
855                              void **abstract)
856 {
857     libssh2_ed25519_ctx *ec_ctx = NULL;
858     int ret;
859 
860     if(*abstract) {
861         hostkey_method_ssh_ed25519_dtor(session, abstract);
862         *abstract = NULL;
863     }
864 
865     ret = _libssh2_ed25519_new_private(&ec_ctx, session,
866                                        privkeyfile, passphrase);
867     if(ret) {
868         return -1;
869     }
870 
871     *abstract = ec_ctx;
872 
873     return ret;
874 }
875 
876 /*
877  * hostkey_method_ssh_ed25519_initPEMFromMemory
878  *
879  * Load a Private Key from memory
880  */
881 static int
hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session,const char * privkeyfiledata,size_t privkeyfiledata_len,unsigned const char * passphrase,void ** abstract)882 hostkey_method_ssh_ed25519_initPEMFromMemory(LIBSSH2_SESSION * session,
883                                              const char *privkeyfiledata,
884                                              size_t privkeyfiledata_len,
885                                              unsigned const char *passphrase,
886                                              void **abstract)
887 {
888     libssh2_ed25519_ctx *ed_ctx = NULL;
889     int ret;
890 
891     if(abstract != NULL && *abstract) {
892         hostkey_method_ssh_ed25519_dtor(session, abstract);
893         *abstract = NULL;
894     }
895 
896     ret = _libssh2_ed25519_new_private_frommemory(&ed_ctx, session,
897                                                   privkeyfiledata,
898                                                   privkeyfiledata_len,
899                                                   passphrase);
900     if(ret) {
901         return -1;
902     }
903 
904     if(abstract != NULL)
905         *abstract = ed_ctx;
906 
907     return 0;
908 }
909 
910 /*
911  * hostkey_method_ssh_ed25519_sig_verify
912  *
913  * Verify signature created by remote
914  */
915 static int
hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session,const unsigned char * sig,size_t sig_len,const unsigned char * m,size_t m_len,void ** abstract)916 hostkey_method_ssh_ed25519_sig_verify(LIBSSH2_SESSION * session,
917                                       const unsigned char *sig,
918                                       size_t sig_len,
919                                       const unsigned char *m,
920                                       size_t m_len, void **abstract)
921 {
922     libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract);
923     (void) session;
924 
925     if(sig_len < 19)
926         return -1;
927 
928     /* Skip past keyname_len(4) + keyname(11){"ssh-ed25519"} +
929        signature_len(4) */
930     sig += 19;
931     sig_len -= 19;
932 
933     if(sig_len != LIBSSH2_ED25519_SIG_LEN)
934         return -1;
935 
936     return _libssh2_ed25519_verify(ctx, sig, sig_len, m, m_len);
937 }
938 
939 /*
940  * hostkey_method_ssh_ed25519_signv
941  *
942  * Construct a signature from an array of vectors
943  */
944 static int
hostkey_method_ssh_ed25519_signv(LIBSSH2_SESSION * session,unsigned char ** signature,size_t * signature_len,int veccount,const struct iovec datavec[],void ** abstract)945 hostkey_method_ssh_ed25519_signv(LIBSSH2_SESSION * session,
946                            unsigned char **signature,
947                            size_t *signature_len,
948                            int veccount,
949                            const struct iovec datavec[],
950                            void **abstract)
951 {
952     libssh2_ed25519_ctx *ctx = (libssh2_ed25519_ctx *) (*abstract);
953 
954     if(veccount != 1) {
955         return -1;
956     }
957 
958     return _libssh2_ed25519_sign(ctx, session, signature, signature_len,
959                                  datavec[0].iov_base, datavec[0].iov_len);
960 }
961 
962 
963 /*
964  * hostkey_method_ssh_ed25519_dtor
965  *
966  * Shutdown the hostkey by freeing key context
967  */
968 static int
hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session,void ** abstract)969 hostkey_method_ssh_ed25519_dtor(LIBSSH2_SESSION * session, void **abstract)
970 {
971     libssh2_ed25519_ctx *keyctx = (libssh2_ed25519_ctx*) (*abstract);
972     (void) session;
973 
974     if(keyctx)
975         _libssh2_ed25519_free(keyctx);
976 
977     *abstract = NULL;
978 
979     return 0;
980 }
981 
982 static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_ed25519 = {
983     "ssh-ed25519",
984     SHA256_DIGEST_LENGTH,
985     hostkey_method_ssh_ed25519_init,
986     hostkey_method_ssh_ed25519_initPEM,
987     hostkey_method_ssh_ed25519_initPEMFromMemory,
988     hostkey_method_ssh_ed25519_sig_verify,
989     hostkey_method_ssh_ed25519_signv,
990     NULL,                       /* encrypt */
991     hostkey_method_ssh_ed25519_dtor,
992 };
993 
994 #endif /*LIBSSH2_ED25519*/
995 
996 
997 static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = {
998 #if LIBSSH2_ECDSA
999     &hostkey_method_ecdsa_ssh_nistp256,
1000     &hostkey_method_ecdsa_ssh_nistp384,
1001     &hostkey_method_ecdsa_ssh_nistp521,
1002 #endif
1003 #if LIBSSH2_ED25519
1004     &hostkey_method_ssh_ed25519,
1005 #endif
1006 #if LIBSSH2_RSA
1007     &hostkey_method_ssh_rsa,
1008 #endif /* LIBSSH2_RSA */
1009 #if LIBSSH2_DSA
1010     &hostkey_method_ssh_dss,
1011 #endif /* LIBSSH2_DSA */
1012     NULL
1013 };
1014 
1015 const LIBSSH2_HOSTKEY_METHOD **
libssh2_hostkey_methods(void)1016 libssh2_hostkey_methods(void)
1017 {
1018     return hostkey_methods;
1019 }
1020 
1021 /*
1022  * libssh2_hostkey_hash
1023  *
1024  * Returns hash signature
1025  * Returned buffer should NOT be freed
1026  * Length of buffer is determined by hash type
1027  * i.e. MD5 == 16, SHA1 == 20, SHA256 == 32
1028  */
1029 LIBSSH2_API const char *
libssh2_hostkey_hash(LIBSSH2_SESSION * session,int hash_type)1030 libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
1031 {
1032     switch(hash_type) {
1033 #if LIBSSH2_MD5
1034     case LIBSSH2_HOSTKEY_HASH_MD5:
1035         return (session->server_hostkey_md5_valid)
1036           ? (char *) session->server_hostkey_md5
1037           : NULL;
1038         break;
1039 #endif /* LIBSSH2_MD5 */
1040     case LIBSSH2_HOSTKEY_HASH_SHA1:
1041         return (session->server_hostkey_sha1_valid)
1042           ? (char *) session->server_hostkey_sha1
1043           : NULL;
1044         break;
1045     case LIBSSH2_HOSTKEY_HASH_SHA256:
1046         return (session->server_hostkey_sha256_valid)
1047           ? (char *) session->server_hostkey_sha256
1048           : NULL;
1049         break;
1050     default:
1051         return NULL;
1052     }
1053 }
1054 
hostkey_type(const unsigned char * hostkey,size_t len)1055 static int hostkey_type(const unsigned char *hostkey, size_t len)
1056 {
1057     static const unsigned char rsa[] = {
1058         0, 0, 0, 0x07, 's', 's', 'h', '-', 'r', 's', 'a'
1059     };
1060     static const unsigned char dss[] = {
1061         0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's'
1062     };
1063     static const unsigned char ecdsa_256[] = {
1064         0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-',
1065         'n', 'i', 's', 't', 'p', '2', '5', '6'
1066     };
1067     static const unsigned char ecdsa_384[] = {
1068         0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-',
1069         'n', 'i', 's', 't', 'p', '3', '8', '4'
1070     };
1071     static const unsigned char ecdsa_521[] = {
1072         0, 0, 0, 0x13, 'e', 'c', 'd', 's', 'a', '-', 's', 'h', 'a', '2', '-',
1073         'n', 'i', 's', 't', 'p', '5', '2', '1'
1074     };
1075     static const unsigned char ed25519[] = {
1076         0, 0, 0, 0x0b, 's', 's', 'h', '-', 'e', 'd', '2', '5', '5', '1', '9'
1077     };
1078 
1079     if(len < 11)
1080         return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
1081 
1082     if(!memcmp(rsa, hostkey, 11))
1083         return LIBSSH2_HOSTKEY_TYPE_RSA;
1084 
1085     if(!memcmp(dss, hostkey, 11))
1086         return LIBSSH2_HOSTKEY_TYPE_DSS;
1087 
1088     if(len < 15)
1089         return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
1090 
1091     if(!memcmp(ed25519, hostkey, 15))
1092         return LIBSSH2_HOSTKEY_TYPE_ED25519;
1093 
1094     if(len < 23)
1095         return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
1096 
1097     if(!memcmp(ecdsa_256, hostkey, 23))
1098         return LIBSSH2_HOSTKEY_TYPE_ECDSA_256;
1099 
1100     if(!memcmp(ecdsa_384, hostkey, 23))
1101         return LIBSSH2_HOSTKEY_TYPE_ECDSA_384;
1102 
1103     if(!memcmp(ecdsa_521, hostkey, 23))
1104         return LIBSSH2_HOSTKEY_TYPE_ECDSA_521;
1105 
1106     return LIBSSH2_HOSTKEY_TYPE_UNKNOWN;
1107 }
1108 
1109 /*
1110  * libssh2_session_hostkey()
1111  *
1112  * Returns the server key and length.
1113  *
1114  */
1115 LIBSSH2_API const char *
libssh2_session_hostkey(LIBSSH2_SESSION * session,size_t * len,int * type)1116 libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len, int *type)
1117 {
1118     if(session->server_hostkey_len) {
1119         if(len)
1120             *len = session->server_hostkey_len;
1121         if(type)
1122             *type = hostkey_type(session->server_hostkey,
1123                                  session->server_hostkey_len);
1124         return (char *) session->server_hostkey;
1125     }
1126     if(len)
1127         *len = 0;
1128     return NULL;
1129 }
1130