From 51b9ff0f16842f044868f635fa82046bfb22631b Mon Sep 17 00:00:00 2001 From: Simon Josefsson Date: Tue, 23 Jan 2007 08:22:54 +0000 Subject: [PATCH] Abstract RSA/DSA private key file reading and RSA/DSA signing, and implement them in openssl/libgcrypt layer. --- src/hostkey.c | 107 +++----------- src/libgcrypt.c | 370 +++++++++++++++++++++++++++++++++++++++++++----- src/libgcrypt.h | 38 ++++- src/openssl.c | 175 ++++++++++++++++++++++- src/openssl.h | 28 +++- 5 files changed, 589 insertions(+), 129 deletions(-) diff --git a/src/hostkey.c b/src/hostkey.c index ad4224d..16d4fae 100644 --- a/src/hostkey.c +++ b/src/hostkey.c @@ -36,9 +36,6 @@ */ #include "libssh2_priv.h" -#include -#include -#include /* Needed for struct iovec on some platforms */ #ifdef HAVE_SYS_UIO_H @@ -88,7 +85,8 @@ libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, n_len = libssh2_ntohu32(s); s += 4; n = s; s += n_len; - if (_libssh2_rsa_new (&rsactx, e, e_len, n, n_len)) + if (_libssh2_rsa_new (&rsactx, e, e_len, n, n_len, NULL, 0, + NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) return -1; *abstract = rsactx; @@ -97,34 +95,15 @@ libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session, } /* }}} */ -/* {{{ libssh2_hostkey_method_ssh_rsa_passphrase_cb - * TODO: Optionally call a passphrase callback specified by the calling program - */ -static int -libssh2_hostkey_method_ssh_rsadsa_passphrase_cb(char *buf, int size, - int rwflag, char *passphrase) -{ - int passphrase_len = strlen(passphrase); - (void)rwflag; - - if (passphrase_len > (size - 1)) { - passphrase_len = size - 1; - } - memcpy(buf, passphrase, passphrase_len); - buf[passphrase_len] = '\0'; - - return passphrase_len; -} -/* }}} */ - /* {{{ libssh2_hostkey_method_ssh_rsa_initPEM * Load a Private Key from a PEM file */ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, const char *privkeyfile, unsigned const char *passphrase, void **abstract) { - RSA *rsactx; + libssh2_rsa_ctx *rsactx; FILE *fp; + int ret; if (*abstract) { libssh2_hostkey_method_ssh_rsa_dtor(session, abstract); @@ -136,19 +115,11 @@ static int libssh2_hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION *session, return -1; } - if (!EVP_get_cipherbyname("des")) { - /* If this cipher isn't loaded it's a pretty good indication that none are. - * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#( - * Someone buy me an OpenSSL manual and I'll read up on it. - */ - OpenSSL_add_all_ciphers(); - } - rsactx = PEM_read_RSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase); - if (!rsactx) { - fclose(fp); + ret = _libssh2_rsa_new_private (&rsactx, session, fp, passphrase); + fclose(fp); + if (ret) { return -1; } - fclose(fp); *abstract = rsactx; @@ -181,20 +152,11 @@ static int libssh2_hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION *session, static int libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract) { - RSA *rsactx = (RSA*)(*abstract); + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx*)(*abstract); int ret; unsigned int i; unsigned char hash[SHA_DIGEST_LENGTH]; libssh2_sha1_ctx ctx; - unsigned char *sig; - unsigned int sig_len; - - sig_len = RSA_size(rsactx); - sig = LIBSSH2_ALLOC(session, sig_len); - - if (!sig) { - return -1; - } libssh2_sha1_init(&ctx); for(i = 0; i < veccount; i++) { @@ -202,16 +164,12 @@ static int libssh2_hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION *session, unsign } libssh2_sha1_final(ctx, hash); - ret = RSA_sign(NID_sha1, hash, SHA_DIGEST_LENGTH, sig, &sig_len, rsactx); - - if (!ret) { - LIBSSH2_FREE(session, sig); + ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH, + signature, signature_len); + if (ret) { return -1; } - *signature = sig; - *signature_len = sig_len; - return 0; } /* }}} */ @@ -286,7 +244,8 @@ libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session, y_len = libssh2_ntohu32(s); s += 4; y = s; s += y_len; - _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len); + _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, + y, y_len, NULL, 0); *abstract = dsactx; @@ -302,8 +261,9 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, unsigned const char *passphrase, void **abstract) { - DSA *dsactx; + libssh2_dsa_ctx *dsactx; FILE *fp; + int ret; if (*abstract) { libssh2_hostkey_method_ssh_dss_dtor(session, abstract); @@ -315,19 +275,11 @@ static int libssh2_hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION *session, return -1; } - if (!EVP_get_cipherbyname("des")) { - /* If this cipher isn't loaded it's a pretty good indication that none are. - * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#( - * Someone buy me an OpenSSL manual and I'll read up on it. - */ - OpenSSL_add_all_ciphers(); - } - dsactx = PEM_read_DSAPrivateKey(fp, NULL, (void*)libssh2_hostkey_method_ssh_rsadsa_passphrase_cb, (void*)passphrase); - if (!dsactx) { - fclose(fp); + ret = _libssh2_dsa_new_private (&dsactx, session, fp, passphrase); + fclose(fp); + if (ret) { return -1; } - fclose(fp); *abstract = dsactx; @@ -359,11 +311,9 @@ static int libssh2_hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION *session, c static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsigned char **signature, unsigned long *signature_len, unsigned long veccount, const struct iovec datavec[], void **abstract) { - DSA *dsactx = (DSA*)(*abstract); - DSA_SIG *sig; + libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx*)(*abstract); unsigned char hash[SHA_DIGEST_LENGTH]; libssh2_sha1_ctx ctx; - int r_len, s_len, rs_pad; unsigned int i; *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH); @@ -380,26 +330,13 @@ static int libssh2_hostkey_method_ssh_dss_signv(LIBSSH2_SESSION *session, unsign } libssh2_sha1_final(ctx, hash); - sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); - if (!sig) { + if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, + *signature)) + { LIBSSH2_FREE(session, *signature); return -1; } - r_len = BN_num_bytes(sig->r); - s_len = BN_num_bytes(sig->s); - rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len); - if (rs_pad < 0) { - DSA_SIG_free(sig); - LIBSSH2_FREE(session, *signature); - return -1; - } - - BN_bn2bin(sig->r, *signature + rs_pad); - BN_bn2bin(sig->s, *signature + rs_pad + r_len); - - DSA_SIG_free(sig); - return 0; } /* }}} */ diff --git a/src/libgcrypt.c b/src/libgcrypt.c index 38a69b3..667db51 100644 --- a/src/libgcrypt.c +++ b/src/libgcrypt.c @@ -35,18 +35,39 @@ * OF SUCH DAMAGE. */ -#include "libgcrypt.h" +#include "libssh2_priv.h" +#include int _libssh2_rsa_new(libssh2_rsa_ctx **rsa, const unsigned char *edata, unsigned long elen, const unsigned char *ndata, - unsigned long nlen) + 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) { int rc; - rc = gcry_sexp_build (rsa, NULL, "(public-key(rsa(n%b)(e%b)))", - nlen, ndata, elen, edata); + if (ddata) { + rc = gcry_sexp_build + (rsa, NULL, + "(private-key(rsa(n%b)(e%b)(d%b)(p%b)(q%b)(u%b)))", + nlen, ndata, elen, edata, dlen, ddata, plen, pdata, + qlen, qdata, coefflen, coeffdata); + } else { + rc = gcry_sexp_build (rsa, NULL, "(public-key(rsa(n%b)(e%b)))", + nlen, ndata, elen, edata); + } if (rc) { *rsa = NULL; @@ -72,15 +93,13 @@ int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa, rc = gcry_sexp_build (&s_hash, NULL, "(data (flags pkcs1) (hash sha1 %b))", SHA_DIGEST_LENGTH, hash); - if (rc != 0) - { + if (rc != 0) { return -1; } rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig); - if (rc != 0) - { + if (rc != 0) { gcry_sexp_release (s_hash); return -1; } @@ -100,15 +119,24 @@ int _libssh2_dsa_new(libssh2_dsa_ctx **dsactx, const unsigned char *g, unsigned long g_len, const unsigned char *y, - unsigned long y_len) + unsigned long y_len, + const unsigned char *x, + unsigned long x_len) { int rc; - rc = gcry_sexp_build (dsactx, NULL, - "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))", - p_len, p, q_len, q, g_len, g, y_len, y); - if (rc) - { + if (x_len) { + rc = gcry_sexp_build + (dsactx, NULL, + "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", + p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); + } else { + rc = gcry_sexp_build (dsactx, NULL, + "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))", + p_len, p, q_len, q, g_len, g, y_len, y); + } + + if (rc) { *dsactx = NULL; return -1; } @@ -116,6 +144,291 @@ int _libssh2_dsa_new(libssh2_dsa_ctx **dsactx, return 0; } +int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + FILE *fp, + unsigned const char *passphrase) +{ + char *data, *save_data; + unsigned int datalen; + int err; + char *n, *e, *d, *p, *q, *e1, *e2, *coeff; + unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen; + + err = _libssh2_pem_parse (session, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + fp, &data, &datalen); + if (err) { + return -1; + } + + save_data = data; + + if (_libssh2_pem_decode_sequence (&data, &datalen)) { + return -1; + } +/* First read Version field (should be 0). */ + err = _libssh2_pem_decode_integer (&data, &datalen, &n, &nlen); + if (err != 0 || (nlen != 1 && *n != '\0')) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &n, &nlen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &e, &elen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &d, &dlen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &q, &qlen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &e1, &e1len); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &e2, &e2len); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &coeff, &coefflen); + if (err != 0) { + return -1; + } + + if (_libssh2_rsa_new (rsa, n, nlen, e, elen, d, dlen, p, plen, + q, qlen, e1, e1len, e2, e2len, + coeff, coefflen)) { + return -1; + } + + LIBSSH2_FREE (session, save_data); + + return 0; +} + +int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + FILE *fp, + unsigned const char *passphrase) +{ + char *data, *save_data; + unsigned int datalen; + int err; + char *p, *q, *g, *y, *x; + unsigned int plen, qlen, glen, ylen, xlen; + + err = _libssh2_pem_parse (session, + "-----BEGIN DSA PRIVATE KEY-----", + "-----END DSA PRIVATE KEY-----", + fp, &data, &datalen); + if (err) { + return -1; + } + + save_data = data; + + if (_libssh2_pem_decode_sequence (&data, &datalen)) { + return -1; + } + +/* First read Version field (should be 0). */ + err = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen); + if (err != 0 || (plen != 1 && *p != '\0')) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &p, &plen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &q, &qlen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &g, &glen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &y, &ylen); + if (err != 0) { + return -1; + } + + err = _libssh2_pem_decode_integer (&data, &datalen, &x, &xlen); + if (err != 0) { + return -1; + } + + if (datalen != 0) { + return -1; + } + + if (_libssh2_dsa_new (dsa, p, plen, q, qlen, + g, glen, y, ylen, x, xlen)) { + return -1; + } + + LIBSSH2_FREE (session, save_data); + + return 0; +} + +int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session, + libssh2_dsa_ctx *rsactx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char **signature, + unsigned long *signature_len) +{ + gcry_sexp_t sig_sexp; + gcry_sexp_t data; + int rc; + const char *tmp; + size_t size; + + if (hash_len != SHA_DIGEST_LENGTH) + { + return -1; + } + + rc = gcry_sexp_build (&data, NULL, + "(data (flags pkcs1) (hash sha1 %b))", + hash_len, hash); + if (rc != 0) { + return -1; + } + + rc = gcry_pk_sign (&sig_sexp, data, rsactx); + + gcry_sexp_release (data); + + if (rc != 0) { + return -1; + } + + data = gcry_sexp_find_token(sig_sexp, "s", 0); + if (!data) { + return -1; + } + + tmp = gcry_sexp_nth_data(data, 1, &size); + if (!tmp) { + return -1; + } + + if (tmp[0] == '\0') { + tmp++; + size--; + } + + *signature = LIBSSH2_ALLOC(session, size); + memcpy (*signature, tmp, size); + *signature_len = size; + + return rc; +} + +int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char *sig) +{ + unsigned char zhash[SHA_DIGEST_LENGTH+1]; + gcry_sexp_t sig_sexp; + gcry_sexp_t data; + int rc; + const char *tmp; + size_t size; + + if (hash_len != SHA_DIGEST_LENGTH) + { + return -1; + } + + memcpy (zhash + 1, hash, hash_len); + zhash[0] = 0; + + rc = gcry_sexp_build (&data, NULL, "(data (value %b))", + hash_len + 1, zhash); + if (rc != 0) { + return -1; + } + + rc = gcry_pk_sign (&sig_sexp, data, dsactx); + + gcry_sexp_release (data); + + if (rc != 0) { + return -1; + } + + + data = gcry_sexp_find_token(sig_sexp, "r", 0); + if (!data) { + return -1; + } + + tmp = gcry_sexp_nth_data(data, 1, &size); + if (!tmp) { + return -1; + } + + if (tmp[0] == '\0') { + tmp++; + size--; + } + + if (size != 20) { + return -1; + } + + memcpy (sig, tmp, 20); + + data = gcry_sexp_find_token(sig_sexp,"s",0); + if (!data) { + return -1; + } + + tmp = gcry_sexp_nth_data(data, 1, &size); + if (!tmp) { + return -1; + } + + if (tmp[0] == '\0') { + tmp++; + size--; + } + + if (size != 20) { + return -1; + } + + memcpy (sig + 20, tmp, 20); + + return rc; +} int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx, const unsigned char *sig, @@ -133,15 +446,13 @@ int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx, rc = gcry_sexp_build (&s_hash, NULL, "(data(flags raw)(value %b))", SHA_DIGEST_LENGTH+1, hash); - if (rc != 0) - { + if (rc != 0) { return -1; } rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))", 20, sig, 20, sig + 20); - if (rc != 0) - { + if (rc != 0) { gcry_sexp_release (s_hash); return -1; } @@ -162,34 +473,30 @@ int _libssh2_cipher_init (_libssh2_cipher_ctx *h, int mode = 0, err; int keylen = gcry_cipher_get_algo_keylen (algo); - if (algo != GCRY_CIPHER_ARCFOUR) - { + if (algo != GCRY_CIPHER_ARCFOUR) { mode = GCRY_CIPHER_MODE_CBC; } err = gcry_cipher_open (h, algo, mode, 0); - if (err) - { + if (err) { return -1; } err = gcry_cipher_setkey (*h, secret, keylen); - if (err) - { + if (err) { gcry_cipher_close (*h); return -1; } - if (algo != GCRY_CIPHER_ARCFOUR) - { + if (algo != GCRY_CIPHER_ARCFOUR) { int blklen = gcry_cipher_get_algo_blklen (algo); err = gcry_cipher_setiv (*h, iv, blklen); - if (err) - { + if (err) { gcry_cipher_close (*h); return -1; } } + return 0; } @@ -205,13 +512,10 @@ int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx, blklen = 8; } - if (encrypt) - { + if (encrypt) { err = gcry_cipher_encrypt (*ctx, block, blklen, block, blklen); - } - else - { + } else { err = gcry_cipher_decrypt (*ctx, block, blklen, block, blklen); } diff --git a/src/libgcrypt.h b/src/libgcrypt.h index ce205ef..b026a5d 100644 --- a/src/libgcrypt.h +++ b/src/libgcrypt.h @@ -97,12 +97,34 @@ int _libssh2_rsa_new(libssh2_rsa_ctx **rsa, const unsigned char *edata, unsigned long elen, const unsigned char *ndata, - unsigned long nlen); + 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); +int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + FILE *fp, + unsigned const char *passphrase); 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); +int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session, + libssh2_rsa_ctx *rsactx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char **signature, + unsigned long *signature_len); #define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx) @@ -116,12 +138,22 @@ int _libssh2_dsa_new(libssh2_dsa_ctx **dsa, const unsigned char *gdata, unsigned long glen, const unsigned char *ydata, - unsigned long ylen); -int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsa, + unsigned long ylen, + const unsigned char *x, + unsigned long x_len); +int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + FILE *fp, + unsigned const char *passphrase); + int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsa, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len); +int _libssh2_dsa_sign(libssh2_dsa_ctx *dsactx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char *sig); #define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx) diff --git a/src/openssl.c b/src/openssl.c index 7943a20..28d5f21 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -1,5 +1,6 @@ /* Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. * Author: Simon Josefsson + * Copyright (c) 2004-2006, Sara Golemon * * Redistribution and use in source and binary forms, * with or without modification, are permitted provided @@ -35,20 +36,55 @@ * OF SUCH DAMAGE. */ +#include "libssh2_priv.h" #include -#include "openssl.h" int _libssh2_rsa_new(libssh2_rsa_ctx **rsa, const unsigned char *edata, unsigned long elen, const unsigned char *ndata, - unsigned long nlen) + 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) { *rsa = RSA_new(); + (*rsa)->e = BN_new(); BN_bin2bn(edata, elen, (*rsa)->e); + (*rsa)->n = BN_new(); BN_bin2bn(ndata, nlen, (*rsa)->n); + + if (ddata) + { + (*rsa)->d = BN_new(); + BN_bin2bn(ddata, dlen, (*rsa)->d); + + (*rsa)->p = BN_new(); + BN_bin2bn(pdata, plen, (*rsa)->p); + + (*rsa)->q = BN_new(); + BN_bin2bn(qdata, qlen, (*rsa)->q); + + (*rsa)->dmp1 = BN_new(); + BN_bin2bn(e1data, e1len, (*rsa)->dmp1); + + (*rsa)->dmq1 = BN_new(); + BN_bin2bn(e2data, e2len, (*rsa)->dmq1); + + (*rsa)->iqmp = BN_new(); + BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp); + } return 0; } @@ -75,17 +111,29 @@ int _libssh2_dsa_new(libssh2_dsa_ctx **dsactx, const unsigned char *g, unsigned long g_len, const unsigned char *y, - unsigned long y_len) + unsigned long y_len, + const unsigned char *x, + unsigned long x_len) { *dsactx = DSA_new(); + (*dsactx)->p = BN_new(); BN_bin2bn(p, p_len, (*dsactx)->p); + (*dsactx)->q = BN_new(); BN_bin2bn(q, q_len, (*dsactx)->q); + (*dsactx)->g = BN_new(); BN_bin2bn(g, g_len, (*dsactx)->g); + (*dsactx)->pub_key = BN_new(); BN_bin2bn(y, y_len, (*dsactx)->pub_key); + + if (x_len) { + (*dsactx)->priv_key = BN_new(); + BN_bin2bn(x, x_len, (*dsactx)->priv_key); + } + return 0; } @@ -140,3 +188,124 @@ int _libssh2_cipher_crypt(_libssh2_cipher_ctx *ctx, } return ret == 1 ? 0 : 1; } + +/* TODO: Optionally call a passphrase callback specified by the + * calling program + */ +static int +passphrase_cb(char *buf, int size, + int rwflag, char *passphrase) +{ + int passphrase_len = strlen(passphrase); + (void)rwflag; + + if (passphrase_len > (size - 1)) { + passphrase_len = size - 1; + } + memcpy(buf, passphrase, passphrase_len); + buf[passphrase_len] = '\0'; + + return passphrase_len; +} + +int _libssh2_rsa_new_private (libssh2_rsa_ctx **rsa, + LIBSSH2_SESSION *session, + FILE *fp, + unsigned const char *passphrase) +{ + if (!EVP_get_cipherbyname("des")) { +/* If this cipher isn't loaded it's a pretty good indication that none are. + * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#( + * Someone buy me an OpenSSL manual and I'll read up on it. + */ + OpenSSL_add_all_ciphers(); + } + *rsa = PEM_read_RSAPrivateKey(fp, NULL, (void*)passphrase_cb, + (void*)passphrase); + if (!*rsa) { + return -1; + } + return 0; +} + +int _libssh2_dsa_new_private (libssh2_dsa_ctx **dsa, + LIBSSH2_SESSION *session, + FILE *fp, + unsigned const char *passphrase) +{ + if (!EVP_get_cipherbyname("des")) { +/* If this cipher isn't loaded it's a pretty good indication that none are. + * I have *NO DOUBT* that there's a better way to deal with this ($#&%#$(%$#( + * Someone buy me an OpenSSL manual and I'll read up on it. + */ + OpenSSL_add_all_ciphers(); + } + *dsa = PEM_read_DSAPrivateKey(fp, NULL, (void*)passphrase_cb, + (void*)passphrase); + if (!*dsa) { + return -1; + } + return 0; +} + +int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION *session, + libssh2_rsa_ctx *rsactx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char **signature, + unsigned long *signature_len) +{ + int ret; + unsigned int i; + libssh2_sha1_ctx ctx; + unsigned char *sig; + unsigned int sig_len; + + sig_len = RSA_size(rsactx); + sig = LIBSSH2_ALLOC(session, sig_len); + + if (!sig) { + return -1; + } + + ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx); + + if (!ret) { + LIBSSH2_FREE(session, sig); + return -1; + } + + *signature = sig; + *signature_len = sig_len; + + return 0; +} + +int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char *signature) +{ + DSA_SIG *sig; + int r_len, s_len, rs_pad; + + sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); + if (!sig) { + return -1; + } + + r_len = BN_num_bytes(sig->r); + s_len = BN_num_bytes(sig->s); + rs_pad = (2 * SHA_DIGEST_LENGTH) - (r_len + s_len); + if (rs_pad < 0) { + DSA_SIG_free(sig); + return -1; + } + + BN_bn2bin(sig->r, signature + rs_pad); + BN_bn2bin(sig->s, signature + rs_pad + r_len); + + DSA_SIG_free(sig); + + return 0; +} diff --git a/src/openssl.h b/src/openssl.h index 62b42f7..53d46b4 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -131,10 +131,22 @@ #define libssh2_rsa_ctx RSA 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 *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); int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx *rsa, const unsigned char *sig, unsigned long sig_len, @@ -153,12 +165,18 @@ int _libssh2_dsa_new(libssh2_dsa_ctx **dsa, const unsigned char *gdata, unsigned long glen, const unsigned char *ydata, - unsigned long ylen); + unsigned long ylen, + const unsigned char *x, + unsigned long x_len); int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx *dsactx, const unsigned char *sig, unsigned long sig_len, const unsigned char *m, unsigned long m_len); +int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx *dsactx, + const unsigned char *hash, + unsigned long hash_len, + unsigned char *sig); #define _libssh2_dsa_free(dsactx) DSA_free(dsactx)