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 uint32_t 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_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