1 /* Copyright (C) 2008, 2009, Simon Josefsson
2 * Copyright (C) 2006, 2007, The Written Word, Inc.
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
41 #ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */
42
43 #include <string.h>
44
45 int
_libssh2_rsa_new(libssh2_rsa_ctx ** rsa,const unsigned char * edata,unsigned long elen,const unsigned char * ndata,unsigned long nlen,const unsigned char * ddata,unsigned long dlen,const unsigned char * pdata,unsigned long plen,const unsigned char * qdata,unsigned long qlen,const unsigned char * e1data,unsigned long e1len,const unsigned char * e2data,unsigned long e2len,const unsigned char * coeffdata,unsigned long coefflen)46 _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
47 const unsigned char *edata,
48 unsigned long elen,
49 const unsigned char *ndata,
50 unsigned long nlen,
51 const unsigned char *ddata,
52 unsigned long dlen,
53 const unsigned char *pdata,
54 unsigned long plen,
55 const unsigned char *qdata,
56 unsigned long qlen,
57 const unsigned char *e1data,
58 unsigned long e1len,
59 const unsigned char *e2data,
60 unsigned long e2len,
61 const unsigned char *coeffdata, unsigned long coefflen)
62 {
63 int rc;
64 (void) e1data;
65 (void) e1len;
66 (void) e2data;
67 (void) e2len;
68
69 if (ddata) {
70 rc = gcry_sexp_build
71 (rsa, NULL,
72 "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))",
73 nlen, ndata, elen, edata, dlen, ddata, plen, pdata,
74 qlen, qdata, coefflen, coeffdata);
75 } else {
76 rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))",
77 nlen, ndata, elen, edata);
78 }
79 if (rc) {
80 *rsa = NULL;
81 return -1;
82 }
83
84 return 0;
85 }
86
87 int
_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,const unsigned char * sig,unsigned long sig_len,const unsigned char * m,unsigned long m_len)88 _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
89 const unsigned char *sig,
90 unsigned long sig_len,
91 const unsigned char *m, unsigned long m_len)
92 {
93 unsigned char hash[SHA_DIGEST_LENGTH];
94 gcry_sexp_t s_sig, s_hash;
95 int rc = -1;
96
97 libssh2_sha1(m, m_len, hash);
98
99 rc = gcry_sexp_build(&s_hash, NULL,
100 "(data (flags pkcs1) (hash sha1 %b))",
101 SHA_DIGEST_LENGTH, hash);
102 if (rc != 0) {
103 return -1;
104 }
105
106 rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig);
107 if (rc != 0) {
108 gcry_sexp_release(s_hash);
109 return -1;
110 }
111
112 rc = gcry_pk_verify(s_sig, s_hash, rsa);
113 gcry_sexp_release(s_sig);
114 gcry_sexp_release(s_hash);
115
116 return (rc == 0) ? 0 : -1;
117 }
118
119 int
_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,const unsigned char * p,unsigned long p_len,const unsigned char * q,unsigned long q_len,const unsigned char * g,unsigned long g_len,const unsigned char * y,unsigned long y_len,const unsigned char * x,unsigned long x_len)120 _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
121 const unsigned char *p,
122 unsigned long p_len,
123 const unsigned char *q,
124 unsigned long q_len,
125 const unsigned char *g,
126 unsigned long g_len,
127 const unsigned char *y,
128 unsigned long y_len,
129 const unsigned char *x, unsigned long x_len)
130 {
131 int rc;
132
133 if (x_len) {
134 rc = gcry_sexp_build
135 (dsactx, NULL,
136 "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))",
137 p_len, p, q_len, q, g_len, g, y_len, y, x_len, x);
138 } else {
139 rc = gcry_sexp_build(dsactx, NULL,
140 "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))",
141 p_len, p, q_len, q, g_len, g, y_len, y);
142 }
143
144 if (rc) {
145 *dsactx = NULL;
146 return -1;
147 }
148
149 return 0;
150 }
151
152 int
_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,const char * filedata,size_t filedata_len,unsigned const char * passphrase)153 _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
154 LIBSSH2_SESSION * session,
155 const char *filedata, size_t filedata_len,
156 unsigned const char *passphrase)
157 {
158 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
159 "Unable to extract private key from memory: "
160 "Method unimplemented in libgcrypt backend");
161 }
162
163 int
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,const char * filename,unsigned const char * passphrase)164 _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
165 LIBSSH2_SESSION * session,
166 const char *filename, unsigned const char *passphrase)
167 {
168 FILE *fp;
169 unsigned char *data, *save_data;
170 unsigned int datalen;
171 int ret;
172 unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff;
173 unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen;
174
175 (void) passphrase;
176
177 fp = fopen(filename, "r");
178 if (!fp) {
179 return -1;
180 }
181
182 ret = _libssh2_pem_parse(session,
183 "-----BEGIN RSA PRIVATE KEY-----",
184 "-----END RSA PRIVATE KEY-----",
185 fp, &data, &datalen);
186 fclose(fp);
187 if (ret) {
188 return -1;
189 }
190
191 save_data = data;
192
193 if (_libssh2_pem_decode_sequence(&data, &datalen)) {
194 ret = -1;
195 goto fail;
196 }
197 /* First read Version field (should be 0). */
198 ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
199 if (ret != 0 || (nlen != 1 && *n != '\0')) {
200 ret = -1;
201 goto fail;
202 }
203
204 ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
205 if (ret != 0) {
206 ret = -1;
207 goto fail;
208 }
209
210 ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen);
211 if (ret != 0) {
212 ret = -1;
213 goto fail;
214 }
215
216 ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen);
217 if (ret != 0) {
218 ret = -1;
219 goto fail;
220 }
221
222 ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
223 if (ret != 0) {
224 ret = -1;
225 goto fail;
226 }
227
228 ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
229 if (ret != 0) {
230 ret = -1;
231 goto fail;
232 }
233
234 ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len);
235 if (ret != 0) {
236 ret = -1;
237 goto fail;
238 }
239
240 ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len);
241 if (ret != 0) {
242 ret = -1;
243 goto fail;
244 }
245
246 ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen);
247 if (ret != 0) {
248 ret = -1;
249 goto fail;
250 }
251
252 if (_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen,
253 q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) {
254 ret = -1;
255 goto fail;
256 }
257
258 ret = 0;
259
260 fail:
261 LIBSSH2_FREE(session, save_data);
262 return ret;
263 }
264
265 int
_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,const char * filedata,size_t filedata_len,unsigned const char * passphrase)266 _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
267 LIBSSH2_SESSION * session,
268 const char *filedata, size_t filedata_len,
269 unsigned const char *passphrase)
270 {
271 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
272 "Unable to extract private key from memory: "
273 "Method unimplemented in libgcrypt backend");
274 }
275
276 int
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,const char * filename,unsigned const char * passphrase)277 _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
278 LIBSSH2_SESSION * session,
279 const char *filename, unsigned const char *passphrase)
280 {
281 FILE *fp;
282 unsigned char *data, *save_data;
283 unsigned int datalen;
284 int ret;
285 unsigned char *p, *q, *g, *y, *x;
286 unsigned int plen, qlen, glen, ylen, xlen;
287
288 (void) passphrase;
289
290 fp = fopen(filename, "r");
291 if (!fp) {
292 return -1;
293 }
294
295 ret = _libssh2_pem_parse(session,
296 "-----BEGIN DSA PRIVATE KEY-----",
297 "-----END DSA PRIVATE KEY-----",
298 fp, &data, &datalen);
299 fclose(fp);
300 if (ret) {
301 return -1;
302 }
303
304 save_data = data;
305
306 if (_libssh2_pem_decode_sequence(&data, &datalen)) {
307 ret = -1;
308 goto fail;
309 }
310
311 /* First read Version field (should be 0). */
312 ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
313 if (ret != 0 || (plen != 1 && *p != '\0')) {
314 ret = -1;
315 goto fail;
316 }
317
318 ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
319 if (ret != 0) {
320 ret = -1;
321 goto fail;
322 }
323
324 ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
325 if (ret != 0) {
326 ret = -1;
327 goto fail;
328 }
329
330 ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen);
331 if (ret != 0) {
332 ret = -1;
333 goto fail;
334 }
335
336 ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen);
337 if (ret != 0) {
338 ret = -1;
339 goto fail;
340 }
341
342 ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen);
343 if (ret != 0) {
344 ret = -1;
345 goto fail;
346 }
347
348 if (datalen != 0) {
349 ret = -1;
350 goto fail;
351 }
352
353 if (_libssh2_dsa_new(dsa, p, plen, q, qlen, g, glen, y, ylen, x, xlen)) {
354 ret = -1;
355 goto fail;
356 }
357
358 ret = 0;
359
360 fail:
361 LIBSSH2_FREE(session, save_data);
362 return ret;
363 }
364
365 int
_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,libssh2_rsa_ctx * rsactx,const unsigned char * hash,size_t hash_len,unsigned char ** signature,size_t * signature_len)366 _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
367 libssh2_rsa_ctx * rsactx,
368 const unsigned char *hash,
369 size_t hash_len,
370 unsigned char **signature, size_t *signature_len)
371 {
372 gcry_sexp_t sig_sexp;
373 gcry_sexp_t data;
374 int rc;
375 const char *tmp;
376 size_t size;
377
378 if (hash_len != SHA_DIGEST_LENGTH) {
379 return -1;
380 }
381
382 if (gcry_sexp_build(&data, NULL,
383 "(data (flags pkcs1) (hash sha1 %b))",
384 hash_len, hash)) {
385 return -1;
386 }
387
388 rc = gcry_pk_sign(&sig_sexp, data, rsactx);
389
390 gcry_sexp_release(data);
391
392 if (rc != 0) {
393 return -1;
394 }
395
396 data = gcry_sexp_find_token(sig_sexp, "s", 0);
397 if (!data) {
398 return -1;
399 }
400
401 tmp = gcry_sexp_nth_data(data, 1, &size);
402 if (!tmp) {
403 return -1;
404 }
405
406 if (tmp[0] == '\0') {
407 tmp++;
408 size--;
409 }
410
411 *signature = LIBSSH2_ALLOC(session, size);
412 memcpy(*signature, tmp, size);
413 *signature_len = size;
414
415 return rc;
416 }
417
418 int
_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,const unsigned char * hash,unsigned long hash_len,unsigned char * sig)419 _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
420 const unsigned char *hash,
421 unsigned long hash_len, unsigned char *sig)
422 {
423 unsigned char zhash[SHA_DIGEST_LENGTH + 1];
424 gcry_sexp_t sig_sexp;
425 gcry_sexp_t data;
426 int ret;
427 const char *tmp;
428 size_t size;
429
430 if (hash_len != SHA_DIGEST_LENGTH) {
431 return -1;
432 }
433
434 memcpy(zhash + 1, hash, hash_len);
435 zhash[0] = 0;
436
437 if (gcry_sexp_build(&data, NULL, "(data (value %b))", hash_len + 1, zhash)) {
438 return -1;
439 }
440
441 ret = gcry_pk_sign(&sig_sexp, data, dsactx);
442
443 gcry_sexp_release(data);
444
445 if (ret != 0) {
446 return -1;
447 }
448
449 memset(sig, 0, 40);
450
451 /* Extract R. */
452
453 data = gcry_sexp_find_token(sig_sexp, "r", 0);
454 if (!data)
455 goto err;
456
457 tmp = gcry_sexp_nth_data(data, 1, &size);
458 if (!tmp)
459 goto err;
460
461 if (tmp[0] == '\0') {
462 tmp++;
463 size--;
464 }
465
466 if (size < 1 || size > 20)
467 goto err;
468
469 memcpy(sig + (20 - size), tmp, size);
470
471 gcry_sexp_release(data);
472
473 /* Extract S. */
474
475 data = gcry_sexp_find_token(sig_sexp, "s", 0);
476 if (!data)
477 goto err;
478
479 tmp = gcry_sexp_nth_data(data, 1, &size);
480 if (!tmp)
481 goto err;
482
483 if (tmp[0] == '\0') {
484 tmp++;
485 size--;
486 }
487
488 if (size < 1 || size > 20)
489 goto err;
490
491 memcpy(sig + 20 + (20 - size), tmp, size);
492 goto out;
493
494 err:
495 ret = -1;
496
497 out:
498 if (sig_sexp) {
499 gcry_sexp_release(sig_sexp);
500 }
501 if (data) {
502 gcry_sexp_release(data);
503 }
504 return ret;
505 }
506
507 int
_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,const unsigned char * sig,const unsigned char * m,unsigned long m_len)508 _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
509 const unsigned char *sig,
510 const unsigned char *m, unsigned long m_len)
511 {
512 unsigned char hash[SHA_DIGEST_LENGTH + 1];
513 gcry_sexp_t s_sig, s_hash;
514 int rc = -1;
515
516 libssh2_sha1(m, m_len, hash + 1);
517 hash[0] = 0;
518
519 if (gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))",
520 SHA_DIGEST_LENGTH + 1, hash)) {
521 return -1;
522 }
523
524 if (gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
525 20, sig, 20, sig + 20)) {
526 gcry_sexp_release(s_hash);
527 return -1;
528 }
529
530 rc = gcry_pk_verify(s_sig, s_hash, dsactx);
531 gcry_sexp_release(s_sig);
532 gcry_sexp_release(s_hash);
533
534 return (rc == 0) ? 0 : -1;
535 }
536
537 int
_libssh2_cipher_init(_libssh2_cipher_ctx * h,_libssh2_cipher_type (algo),unsigned char * iv,unsigned char * secret,int encrypt)538 _libssh2_cipher_init(_libssh2_cipher_ctx * h,
539 _libssh2_cipher_type(algo),
540 unsigned char *iv, unsigned char *secret, int encrypt)
541 {
542 int ret;
543 int cipher = _libssh2_gcry_cipher (algo);
544 int mode = _libssh2_gcry_mode (algo);
545 int keylen = gcry_cipher_get_algo_keylen(cipher);
546
547 (void) encrypt;
548
549 ret = gcry_cipher_open(h, cipher, mode, 0);
550 if (ret) {
551 return -1;
552 }
553
554 ret = gcry_cipher_setkey(*h, secret, keylen);
555 if (ret) {
556 gcry_cipher_close(*h);
557 return -1;
558 }
559
560 if (mode != GCRY_CIPHER_MODE_STREAM) {
561 int blklen = gcry_cipher_get_algo_blklen(cipher);
562 if (mode == GCRY_CIPHER_MODE_CTR)
563 ret = gcry_cipher_setctr(*h, iv, blklen);
564 else
565 ret = gcry_cipher_setiv(*h, iv, blklen);
566 if (ret) {
567 gcry_cipher_close(*h);
568 return -1;
569 }
570 }
571
572 return 0;
573 }
574
575 int
_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,_libssh2_cipher_type (algo),int encrypt,unsigned char * block,size_t blklen)576 _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
577 _libssh2_cipher_type(algo),
578 int encrypt, unsigned char *block, size_t blklen)
579 {
580 int cipher = _libssh2_gcry_cipher (algo);
581 int ret;
582
583 if (encrypt) {
584 ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen);
585 } else {
586 ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen);
587 }
588 return ret;
589 }
590
591 int
_libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION * session,unsigned char ** method,size_t * method_len,unsigned char ** pubkeydata,size_t * pubkeydata_len,const char * privatekeydata,size_t privatekeydata_len,const char * passphrase)592 _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
593 unsigned char **method,
594 size_t *method_len,
595 unsigned char **pubkeydata,
596 size_t *pubkeydata_len,
597 const char *privatekeydata,
598 size_t privatekeydata_len,
599 const char *passphrase)
600 {
601 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
602 "Unable to extract public key from private key in memory: "
603 "Method unimplemented in libgcrypt backend");
604 }
605
606 int
_libssh2_pub_priv_keyfile(LIBSSH2_SESSION * session,unsigned char ** method,size_t * method_len,unsigned char ** pubkeydata,size_t * pubkeydata_len,const char * privatekey,const char * passphrase)607 _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
608 unsigned char **method,
609 size_t *method_len,
610 unsigned char **pubkeydata,
611 size_t *pubkeydata_len,
612 const char *privatekey,
613 const char *passphrase)
614 {
615 return _libssh2_error(session, LIBSSH2_ERROR_FILE,
616 "Unable to extract public key from private key file: "
617 "Method unimplemented in libgcrypt backend");
618 }
619
_libssh2_init_aes_ctr(void)620 void _libssh2_init_aes_ctr(void)
621 {
622 /* no implementation */
623 }
624 #endif /* LIBSSH2_LIBGCRYPT */
625