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