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