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 }
76 else {
77 rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))",
78 nlen, ndata, elen, edata);
79 }
80 if(rc) {
81 *rsa = NULL;
82 return -1;
83 }
84
85 return 0;
86 }
87
88 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)89 _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
90 const unsigned char *sig,
91 unsigned long sig_len,
92 const unsigned char *m, unsigned long m_len)
93 {
94 unsigned char hash[SHA_DIGEST_LENGTH];
95 gcry_sexp_t s_sig, s_hash;
96 int rc = -1;
97
98 libssh2_sha1(m, m_len, hash);
99
100 rc = gcry_sexp_build(&s_hash, NULL,
101 "(data (flags pkcs1) (hash sha1 %b))",
102 SHA_DIGEST_LENGTH, hash);
103 if(rc != 0) {
104 return -1;
105 }
106
107 rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig);
108 if(rc != 0) {
109 gcry_sexp_release(s_hash);
110 return -1;
111 }
112
113 rc = gcry_pk_verify(s_sig, s_hash, rsa);
114 gcry_sexp_release(s_sig);
115 gcry_sexp_release(s_hash);
116
117 return (rc == 0) ? 0 : -1;
118 }
119
120 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)121 _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx,
122 const unsigned char *p,
123 unsigned long p_len,
124 const unsigned char *q,
125 unsigned long q_len,
126 const unsigned char *g,
127 unsigned long g_len,
128 const unsigned char *y,
129 unsigned long y_len,
130 const unsigned char *x, unsigned long x_len)
131 {
132 int rc;
133
134 if(x_len) {
135 rc = gcry_sexp_build
136 (dsactx, NULL,
137 "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))",
138 p_len, p, q_len, q, g_len, g, y_len, y, x_len, x);
139 }
140 else {
141 rc = gcry_sexp_build(dsactx, NULL,
142 "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))",
143 p_len, p, q_len, q, g_len, g, y_len, y);
144 }
145
146 if(rc) {
147 *dsactx = NULL;
148 return -1;
149 }
150
151 return 0;
152 }
153
154 int
_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,const char * filedata,size_t filedata_len,unsigned const char * passphrase)155 _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
156 LIBSSH2_SESSION * session,
157 const char *filedata, size_t filedata_len,
158 unsigned const char *passphrase)
159 {
160 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
161 "Unable to extract private key from memory: "
162 "Method unimplemented in libgcrypt backend");
163 }
164
165 int
_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,LIBSSH2_SESSION * session,const char * filename,unsigned const char * passphrase)166 _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
167 LIBSSH2_SESSION * session,
168 const char *filename, unsigned const char *passphrase)
169 {
170 FILE *fp;
171 unsigned char *data, *save_data;
172 unsigned int datalen;
173 int ret;
174 unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff;
175 unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen;
176
177 fp = fopen(filename, FOPEN_READTEXT);
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 passphrase,
186 fp, &data, &datalen);
187 fclose(fp);
188 if(ret) {
189 return -1;
190 }
191
192 save_data = data;
193
194 if(_libssh2_pem_decode_sequence(&data, &datalen)) {
195 ret = -1;
196 goto fail;
197 }
198 /* First read Version field (should be 0). */
199 ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
200 if(ret != 0 || (nlen != 1 && *n != '\0')) {
201 ret = -1;
202 goto fail;
203 }
204
205 ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen);
206 if(ret != 0) {
207 ret = -1;
208 goto fail;
209 }
210
211 ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen);
212 if(ret != 0) {
213 ret = -1;
214 goto fail;
215 }
216
217 ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen);
218 if(ret != 0) {
219 ret = -1;
220 goto fail;
221 }
222
223 ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen);
224 if(ret != 0) {
225 ret = -1;
226 goto fail;
227 }
228
229 ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen);
230 if(ret != 0) {
231 ret = -1;
232 goto fail;
233 }
234
235 ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len);
236 if(ret != 0) {
237 ret = -1;
238 goto fail;
239 }
240
241 ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len);
242 if(ret != 0) {
243 ret = -1;
244 goto fail;
245 }
246
247 ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen);
248 if(ret != 0) {
249 ret = -1;
250 goto fail;
251 }
252
253 if(_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen,
254 q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) {
255 ret = -1;
256 goto fail;
257 }
258
259 ret = 0;
260
261 fail:
262 LIBSSH2_FREE(session, save_data);
263 return ret;
264 }
265
266 int
_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,const char * filedata,size_t filedata_len,unsigned const char * passphrase)267 _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
268 LIBSSH2_SESSION * session,
269 const char *filedata, size_t filedata_len,
270 unsigned const char *passphrase)
271 {
272 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
273 "Unable to extract private key from memory: "
274 "Method unimplemented in libgcrypt backend");
275 }
276
277 int
_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,LIBSSH2_SESSION * session,const char * filename,unsigned const char * passphrase)278 _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
279 LIBSSH2_SESSION * session,
280 const char *filename, unsigned const char *passphrase)
281 {
282 FILE *fp;
283 unsigned char *data, *save_data;
284 unsigned int datalen;
285 int ret;
286 unsigned char *p, *q, *g, *y, *x;
287 unsigned int plen, qlen, glen, ylen, xlen;
288
289 fp = fopen(filename, FOPEN_READTEXT);
290 if(!fp) {
291 return -1;
292 }
293
294 ret = _libssh2_pem_parse(session,
295 "-----BEGIN DSA PRIVATE KEY-----",
296 "-----END DSA PRIVATE KEY-----",
297 passphrase,
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 gcry_sexp_release(data);
404 return -1;
405 }
406
407 if(tmp[0] == '\0') {
408 tmp++;
409 size--;
410 }
411
412 *signature = LIBSSH2_ALLOC(session, size);
413 if(!*signature) {
414 gcry_sexp_release(data);
415 return -1;
416 }
417 memcpy(*signature, tmp, size);
418 *signature_len = size;
419
420 gcry_sexp_release(data);
421
422 return rc;
423 }
424
425 int
_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,const unsigned char * hash,unsigned long hash_len,unsigned char * sig)426 _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
427 const unsigned char *hash,
428 unsigned long hash_len, unsigned char *sig)
429 {
430 unsigned char zhash[SHA_DIGEST_LENGTH + 1];
431 gcry_sexp_t sig_sexp;
432 gcry_sexp_t data;
433 int ret;
434 const char *tmp;
435 size_t size;
436
437 if(hash_len != SHA_DIGEST_LENGTH) {
438 return -1;
439 }
440
441 memcpy(zhash + 1, hash, hash_len);
442 zhash[0] = 0;
443
444 if(gcry_sexp_build(&data, NULL, "(data (value %b))",
445 hash_len + 1, zhash)) {
446 return -1;
447 }
448
449 ret = gcry_pk_sign(&sig_sexp, data, dsactx);
450
451 gcry_sexp_release(data);
452
453 if(ret != 0) {
454 return -1;
455 }
456
457 memset(sig, 0, 40);
458
459 /* Extract R. */
460
461 data = gcry_sexp_find_token(sig_sexp, "r", 0);
462 if(!data)
463 goto err;
464
465 tmp = gcry_sexp_nth_data(data, 1, &size);
466 if(!tmp)
467 goto err;
468
469 if(tmp[0] == '\0') {
470 tmp++;
471 size--;
472 }
473
474 if(size < 1 || size > 20)
475 goto err;
476
477 memcpy(sig + (20 - size), tmp, size);
478
479 gcry_sexp_release(data);
480
481 /* Extract S. */
482
483 data = gcry_sexp_find_token(sig_sexp, "s", 0);
484 if(!data)
485 goto err;
486
487 tmp = gcry_sexp_nth_data(data, 1, &size);
488 if(!tmp)
489 goto err;
490
491 if(tmp[0] == '\0') {
492 tmp++;
493 size--;
494 }
495
496 if(size < 1 || size > 20)
497 goto err;
498
499 memcpy(sig + 20 + (20 - size), tmp, size);
500 goto out;
501
502 err:
503 ret = -1;
504
505 out:
506 if(sig_sexp) {
507 gcry_sexp_release(sig_sexp);
508 }
509 if(data) {
510 gcry_sexp_release(data);
511 }
512 return ret;
513 }
514
515 int
_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,const unsigned char * sig,const unsigned char * m,unsigned long m_len)516 _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
517 const unsigned char *sig,
518 const unsigned char *m, unsigned long m_len)
519 {
520 unsigned char hash[SHA_DIGEST_LENGTH + 1];
521 gcry_sexp_t s_sig, s_hash;
522 int rc = -1;
523
524 libssh2_sha1(m, m_len, hash + 1);
525 hash[0] = 0;
526
527 if(gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))",
528 SHA_DIGEST_LENGTH + 1, hash)) {
529 return -1;
530 }
531
532 if(gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))",
533 20, sig, 20, sig + 20)) {
534 gcry_sexp_release(s_hash);
535 return -1;
536 }
537
538 rc = gcry_pk_verify(s_sig, s_hash, dsactx);
539 gcry_sexp_release(s_sig);
540 gcry_sexp_release(s_hash);
541
542 return (rc == 0) ? 0 : -1;
543 }
544
545 int
_libssh2_cipher_init(_libssh2_cipher_ctx * h,_libssh2_cipher_type (algo),unsigned char * iv,unsigned char * secret,int encrypt)546 _libssh2_cipher_init(_libssh2_cipher_ctx * h,
547 _libssh2_cipher_type(algo),
548 unsigned char *iv, unsigned char *secret, int encrypt)
549 {
550 int ret;
551 int cipher = _libssh2_gcry_cipher(algo);
552 int mode = _libssh2_gcry_mode(algo);
553 int keylen = gcry_cipher_get_algo_keylen(cipher);
554
555 (void) encrypt;
556
557 ret = gcry_cipher_open(h, cipher, mode, 0);
558 if(ret) {
559 return -1;
560 }
561
562 ret = gcry_cipher_setkey(*h, secret, keylen);
563 if(ret) {
564 gcry_cipher_close(*h);
565 return -1;
566 }
567
568 if(mode != GCRY_CIPHER_MODE_STREAM) {
569 int blklen = gcry_cipher_get_algo_blklen(cipher);
570 if(mode == GCRY_CIPHER_MODE_CTR)
571 ret = gcry_cipher_setctr(*h, iv, blklen);
572 else
573 ret = gcry_cipher_setiv(*h, iv, blklen);
574 if(ret) {
575 gcry_cipher_close(*h);
576 return -1;
577 }
578 }
579
580 return 0;
581 }
582
583 int
_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,_libssh2_cipher_type (algo),int encrypt,unsigned char * block,size_t blklen)584 _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
585 _libssh2_cipher_type(algo),
586 int encrypt, unsigned char *block, size_t blklen)
587 {
588 int cipher = _libssh2_gcry_cipher(algo);
589 int ret;
590
591 if(encrypt) {
592 ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen);
593 }
594 else {
595 ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen);
596 }
597 return ret;
598 }
599
600 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)601 _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
602 unsigned char **method,
603 size_t *method_len,
604 unsigned char **pubkeydata,
605 size_t *pubkeydata_len,
606 const char *privatekeydata,
607 size_t privatekeydata_len,
608 const char *passphrase)
609 {
610 return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
611 "Unable to extract public key from private "
612 "key in memory: "
613 "Method unimplemented in libgcrypt backend");
614 }
615
616 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)617 _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
618 unsigned char **method,
619 size_t *method_len,
620 unsigned char **pubkeydata,
621 size_t *pubkeydata_len,
622 const char *privatekey,
623 const char *passphrase)
624 {
625 return _libssh2_error(session, LIBSSH2_ERROR_FILE,
626 "Unable to extract public key from private key file: "
627 "Method unimplemented in libgcrypt backend");
628 }
629
_libssh2_init_aes_ctr(void)630 void _libssh2_init_aes_ctr(void)
631 {
632 /* no implementation */
633 }
634
635 void
_libssh2_dh_init(_libssh2_dh_ctx * dhctx)636 _libssh2_dh_init(_libssh2_dh_ctx *dhctx)
637 {
638 *dhctx = gcry_mpi_new(0); /* Random from client */
639 }
640
641 int
_libssh2_dh_key_pair(_libssh2_dh_ctx * dhctx,_libssh2_bn * public,_libssh2_bn * g,_libssh2_bn * p,int group_order)642 _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
643 _libssh2_bn *g, _libssh2_bn *p, int group_order)
644 {
645 /* Generate x and e */
646 gcry_mpi_randomize(*dhctx, group_order * 8 - 1, GCRY_WEAK_RANDOM);
647 gcry_mpi_powm(public, g, *dhctx, p);
648 return 0;
649 }
650
651 int
_libssh2_dh_secret(_libssh2_dh_ctx * dhctx,_libssh2_bn * secret,_libssh2_bn * f,_libssh2_bn * p)652 _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
653 _libssh2_bn *f, _libssh2_bn *p)
654 {
655 /* Compute the shared secret */
656 gcry_mpi_powm(secret, f, *dhctx, p);
657 return 0;
658 }
659
660 void
_libssh2_dh_dtor(_libssh2_dh_ctx * dhctx)661 _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
662 {
663 gcry_mpi_release(*dhctx);
664 *dhctx = NULL;
665 }
666
667 #endif /* LIBSSH2_LIBGCRYPT */
668