We now build libssh2 in Xcode and it's a much better UB/10.4 citizen
[printdrop.git] / Vendor / libssh2 / Source / hostkey.c
1 /* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms,
5 * with or without modification, are permitted provided
6 * that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 *
17 * Neither the name of the copyright holder nor the names
18 * of any other contributors may be used to endorse or
19 * promote products derived from this software without
20 * specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
34 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 */
37
38 #include "libssh2_priv.h"
39
40 /* Needed for struct iovec on some platforms */
41 #ifdef HAVE_SYS_UIO_H
42 #include <sys/uio.h>
43 #endif
44
45 #if LIBSSH2_RSA
46 /* ***********
47 * ssh-rsa *
48 *********** */
49
50 static int libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session,
51 void **abstract);
52
53 /* {{{ libssh2_hostkey_method_ssh_rsa_init
54 * Initialize the server hostkey working area with e/n pair
55 */
56 static int
57 libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session,
58 const unsigned char *hostkey_data,
59 unsigned long hostkey_data_len,
60 void **abstract)
61 {
62 libssh2_rsa_ctx *rsactx;
63 const unsigned char *s, *e, *n;
64 unsigned long len, e_len, n_len;
65
66 (void) hostkey_data_len;
67
68 if (*abstract) {
69 libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
70 *abstract = NULL;
71 }
72
73 s = hostkey_data;
74 len = libssh2_ntohu32(s);
75 s += 4;
76
77 if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) {
78 return -1;
79 }
80 s += 7;
81
82 e_len = libssh2_ntohu32(s);
83 s += 4;
84
85 e = s;
86 s += e_len;
87 n_len = libssh2_ntohu32(s);
88 s += 4;
89 n = s;
90 s += n_len;
91
92 if (_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0,
93 NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0))
94 return -1;
95
96 *abstract = rsactx;
97
98 return 0;
99 }
100
101 /* }}} */
102
103 /* {{{ libssh2_hostkey_method_ssh_rsa_initPEM
104 * Load a Private Key from a PEM file
105 */
106 static int
107 libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session,
108 const char *privkeyfile,
109 unsigned const char *passphrase,
110 void **abstract)
111 {
112 libssh2_rsa_ctx *rsactx;
113 FILE *fp;
114 int ret;
115
116 if (*abstract) {
117 libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
118 *abstract = NULL;
119 }
120
121 fp = fopen(privkeyfile, "r");
122 if (!fp) {
123 return -1;
124 }
125
126 ret = _libssh2_rsa_new_private(&rsactx, session, fp, passphrase);
127 fclose(fp);
128 if (ret) {
129 return -1;
130 }
131
132 *abstract = rsactx;
133
134 return 0;
135 }
136
137 /* }}} */
138
139 /* {{{ libssh2_hostkey_method_ssh_rsa_sign
140 * Verify signature created by remote
141 */
142 static int
143 libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session,
144 const unsigned char *sig,
145 unsigned long sig_len,
146 const unsigned char *m,
147 unsigned long m_len, void **abstract)
148 {
149 libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
150 (void) session;
151
152 /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */
153 sig += 15;
154 sig_len -= 15;
155 return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len);
156 }
157
158 /* }}} */
159
160 /* {{{ libssh2_hostkey_method_ssh_rsa_signv
161 * Construct a signature from an array of vectors
162 */
163 static int
164 libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session,
165 unsigned char **signature,
166 unsigned long *signature_len,
167 unsigned long veccount,
168 const struct iovec datavec[],
169 void **abstract)
170 {
171 libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
172 int ret;
173 unsigned int i;
174 unsigned char hash[SHA_DIGEST_LENGTH];
175 libssh2_sha1_ctx ctx;
176
177 libssh2_sha1_init(&ctx);
178 for(i = 0; i < veccount; i++) {
179 libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
180 }
181 libssh2_sha1_final(ctx, hash);
182
183 ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH,
184 signature, signature_len);
185 if (ret) {
186 return -1;
187 }
188
189 return 0;
190 }
191
192 /* }}} */
193
194 /* {{{ libssh2_hostkey_method_ssh_rsa_dtor
195 * Shutdown the hostkey
196 */
197 static int
198 libssh2_hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract)
199 {
200 libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract);
201 (void) session;
202
203 _libssh2_rsa_free(rsactx);
204
205 *abstract = NULL;
206
207 return 0;
208 }
209
210 /* }}} */
211
212 static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_rsa = {
213 "ssh-rsa",
214 MD5_DIGEST_LENGTH,
215 libssh2_hostkey_method_ssh_rsa_init,
216 libssh2_hostkey_method_ssh_rsa_initPEM,
217 libssh2_hostkey_method_ssh_rsa_sig_verify,
218 libssh2_hostkey_method_ssh_rsa_signv,
219 NULL, /* encrypt */
220 libssh2_hostkey_method_ssh_rsa_dtor,
221 };
222 #endif /* LIBSSH2_RSA */
223
224 #if LIBSSH2_DSA
225 /* ***********
226 * ssh-dss *
227 *********** */
228
229 static int libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session,
230 void **abstract);
231
232 /* {{{ libssh2_hostkey_method_ssh_dss_init
233 * Initialize the server hostkey working area with p/q/g/y set
234 */
235 static int
236 libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session,
237 const unsigned char *hostkey_data,
238 unsigned long hostkey_data_len,
239 void **abstract)
240 {
241 libssh2_dsa_ctx *dsactx;
242 const unsigned char *p, *q, *g, *y, *s;
243 unsigned long p_len, q_len, g_len, y_len, len;
244 (void) hostkey_data_len;
245
246 if (*abstract) {
247 libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
248 *abstract = NULL;
249 }
250
251 s = hostkey_data;
252 len = libssh2_ntohu32(s);
253 s += 4;
254 if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) {
255 return -1;
256 }
257 s += 7;
258
259 p_len = libssh2_ntohu32(s);
260 s += 4;
261 p = s;
262 s += p_len;
263 q_len = libssh2_ntohu32(s);
264 s += 4;
265 q = s;
266 s += q_len;
267 g_len = libssh2_ntohu32(s);
268 s += 4;
269 g = s;
270 s += g_len;
271 y_len = libssh2_ntohu32(s);
272 s += 4;
273 y = s;
274 s += y_len;
275
276 _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len, NULL, 0);
277
278 *abstract = dsactx;
279
280 return 0;
281 }
282
283 /* }}} */
284
285 /* {{{ libssh2_hostkey_method_ssh_dss_initPEM
286 * Load a Private Key from a PEM file
287 */
288 static int
289 libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session,
290 const char *privkeyfile,
291 unsigned const char *passphrase,
292 void **abstract)
293 {
294 libssh2_dsa_ctx *dsactx;
295 FILE *fp;
296 int ret;
297
298 if (*abstract) {
299 libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
300 *abstract = NULL;
301 }
302
303 fp = fopen(privkeyfile, "r");
304 if (!fp) {
305 return -1;
306 }
307
308 ret = _libssh2_dsa_new_private(&dsactx, session, fp, passphrase);
309 fclose(fp);
310 if (ret) {
311 return -1;
312 }
313
314 *abstract = dsactx;
315
316 return 0;
317 }
318
319 /* }}} */
320
321 /* {{{ libssh2_hostkey_method_ssh_dss_sign
322 * Verify signature created by remote
323 */
324 static int
325 libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session,
326 const unsigned char *sig,
327 unsigned long sig_len,
328 const unsigned char *m,
329 unsigned long m_len, void **abstract)
330 {
331 libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
332
333 /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */
334 sig += 15;
335 sig_len -= 15;
336 if (sig_len != 40) {
337 libssh2_error(session, LIBSSH2_ERROR_PROTO,
338 "Invalid DSS signature length", 0);
339 return -1;
340 }
341 return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len);
342 }
343
344 /* }}} */
345
346 /* {{{ libssh2_hostkey_method_ssh_dss_signv
347 * Construct a signature from an array of vectors
348 */
349 static int
350 libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session,
351 unsigned char **signature,
352 unsigned long *signature_len,
353 unsigned long veccount,
354 const struct iovec datavec[],
355 void **abstract)
356 {
357 libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
358 unsigned char hash[SHA_DIGEST_LENGTH];
359 libssh2_sha1_ctx ctx;
360 unsigned int i;
361
362 *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH);
363 if (!*signature) {
364 return -1;
365 }
366
367 *signature_len = 2 * SHA_DIGEST_LENGTH;
368 memset(*signature, 0, 2 * SHA_DIGEST_LENGTH);
369
370 libssh2_sha1_init(&ctx);
371 for(i = 0; i < veccount; i++) {
372 libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len);
373 }
374 libssh2_sha1_final(ctx, hash);
375
376 if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) {
377 LIBSSH2_FREE(session, *signature);
378 return -1;
379 }
380
381 return 0;
382 }
383
384 /* }}} */
385
386 /* {{{ libssh2_hostkey_method_ssh_dss_dtor
387 * Shutdown the hostkey method
388 */
389 static int
390 libssh2_hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract)
391 {
392 libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract);
393 (void) session;
394
395 _libssh2_dsa_free(dsactx);
396
397 *abstract = NULL;
398
399 return 0;
400 }
401
402 /* }}} */
403
404 static const LIBSSH2_HOSTKEY_METHOD libssh2_hostkey_method_ssh_dss = {
405 "ssh-dss",
406 MD5_DIGEST_LENGTH,
407 libssh2_hostkey_method_ssh_dss_init,
408 libssh2_hostkey_method_ssh_dss_initPEM,
409 libssh2_hostkey_method_ssh_dss_sig_verify,
410 libssh2_hostkey_method_ssh_dss_signv,
411 NULL, /* encrypt */
412 libssh2_hostkey_method_ssh_dss_dtor,
413 };
414 #endif /* LIBSSH2_DSA */
415
416 static const LIBSSH2_HOSTKEY_METHOD *_libssh2_hostkey_methods[] = {
417 #if LIBSSH2_RSA
418 &libssh2_hostkey_method_ssh_rsa,
419 #endif /* LIBSSH2_RSA */
420 #if LIBSSH2_DSA
421 &libssh2_hostkey_method_ssh_dss,
422 #endif /* LIBSSH2_DSA */
423 NULL
424 };
425
426 const LIBSSH2_HOSTKEY_METHOD **
427 libssh2_hostkey_methods(void)
428 {
429 return _libssh2_hostkey_methods;
430 }
431
432 /* {{{ libssh2_hostkey_hash
433 * Returns hash signature
434 * Returned buffer should NOT be freed
435 * Length of buffer is determined by hash type
436 * i.e. MD5 == 16, SHA1 == 20
437 */
438 LIBSSH2_API const char *
439 libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type)
440 {
441 switch (hash_type) {
442 #if LIBSSH2_MD5
443 case LIBSSH2_HOSTKEY_HASH_MD5:
444 return (char *) session->server_hostkey_md5;
445 break;
446 #endif /* LIBSSH2_MD5 */
447 case LIBSSH2_HOSTKEY_HASH_SHA1:
448 return (char *) session->server_hostkey_sha1;
449 break;
450 default:
451 return NULL;
452 }
453 }
454
455 /* }}} */