summaryrefslogtreecommitdiff
path: root/libssh2-sys/libssh2-1.5.0/src/openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh2-sys/libssh2-1.5.0/src/openssl.c')
-rw-r--r--libssh2-sys/libssh2-1.5.0/src/openssl.c820
1 files changed, 820 insertions, 0 deletions
diff --git a/libssh2-sys/libssh2-1.5.0/src/openssl.c b/libssh2-sys/libssh2-1.5.0/src/openssl.c
new file mode 100644
index 0000000..056b0b7
--- /dev/null
+++ b/libssh2-sys/libssh2-1.5.0/src/openssl.c
@@ -0,0 +1,820 @@
+/* Copyright (C) 2009, 2010 Simon Josefsson
+ * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved.
+ * Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
+ *
+ * Author: Simon Josefsson
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the copyright holder nor the names
+ * of any other contributors may be used to endorse or
+ * promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "libssh2_priv.h"
+
+#ifdef LIBSSH2_OPENSSL /* compile only if we build with openssl */
+
+#include <string.h>
+
+#ifndef EVP_MAX_BLOCK_LENGTH
+#define EVP_MAX_BLOCK_LENGTH 32
+#endif
+
+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)
+{
+ *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;
+}
+
+int
+_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
+ const unsigned char *sig,
+ unsigned long sig_len,
+ const unsigned char *m, unsigned long m_len)
+{
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ int ret;
+
+ libssh2_sha1(m, m_len, hash);
+ ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
+ (unsigned char *) sig, sig_len, rsactx);
+ return (ret == 1) ? 0 : -1;
+}
+
+#if LIBSSH2_DSA
+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)
+{
+ *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;
+}
+
+int
+_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
+ const unsigned char *sig,
+ const unsigned char *m, unsigned long m_len)
+{
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ DSA_SIG dsasig;
+ int ret;
+
+ dsasig.r = BN_new();
+ BN_bin2bn(sig, 20, dsasig.r);
+ dsasig.s = BN_new();
+ BN_bin2bn(sig + 20, 20, dsasig.s);
+
+ libssh2_sha1(m, m_len, hash);
+ ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx);
+ BN_clear_free(dsasig.s);
+ BN_clear_free(dsasig.r);
+
+ return (ret == 1) ? 0 : -1;
+}
+#endif /* LIBSSH_DSA */
+
+int
+_libssh2_cipher_init(_libssh2_cipher_ctx * h,
+ _libssh2_cipher_type(algo),
+ unsigned char *iv, unsigned char *secret, int encrypt)
+{
+ EVP_CIPHER_CTX_init(h);
+ return !EVP_CipherInit(h, algo(), secret, iv, encrypt);
+}
+
+int
+_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
+ _libssh2_cipher_type(algo),
+ int encrypt, unsigned char *block, size_t blocksize)
+{
+ unsigned char buf[EVP_MAX_BLOCK_LENGTH];
+ int ret;
+ (void) algo;
+ (void) encrypt;
+
+ ret = EVP_Cipher(ctx, buf, block, blocksize);
+ if (ret == 1) {
+ memcpy(block, buf, blocksize);
+ }
+ return ret == 1 ? 0 : 1;
+}
+
+#if LIBSSH2_AES_CTR
+
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+
+typedef struct
+{
+ AES_KEY key;
+ EVP_CIPHER_CTX *aes_ctx;
+ unsigned char ctr[AES_BLOCK_SIZE];
+} aes_ctr_ctx;
+
+static int
+aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+ const unsigned char *iv, int enc) /* init key */
+{
+ /*
+ * variable "c" is leaked from this scope, but is later freed
+ * in aes_ctr_cleanup
+ */
+ aes_ctr_ctx *c;
+ const EVP_CIPHER *aes_cipher;
+ (void) enc;
+
+ switch (ctx->key_len) {
+ case 16:
+ aes_cipher = EVP_aes_128_ecb();
+ break;
+ case 24:
+ aes_cipher = EVP_aes_192_ecb();
+ break;
+ case 32:
+ aes_cipher = EVP_aes_256_ecb();
+ break;
+ default:
+ return 0;
+ }
+
+ c = malloc(sizeof(*c));
+ if (c == NULL)
+ return 0;
+
+ c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX));
+ if (c->aes_ctx == NULL) {
+ free(c);
+ return 0;
+ }
+
+ if (EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) {
+ free(c->aes_ctx);
+ free(c);
+ return 0;
+ }
+
+ EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0);
+
+ memcpy(c->ctr, iv, AES_BLOCK_SIZE);
+
+ EVP_CIPHER_CTX_set_app_data(ctx, c);
+
+ return 1;
+}
+
+static int
+aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in,
+ size_t inl) /* encrypt/decrypt data */
+{
+ aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
+ unsigned char b1[AES_BLOCK_SIZE];
+ size_t i = 0;
+ int outlen = 0;
+
+ if (inl != 16) /* libssh2 only ever encrypt one block */
+ return 0;
+
+ if (c == NULL) {
+ return 0;
+ }
+
+/*
+ To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each
+ blocks of length L), the encryptor first encrypts <X> with <cipher>
+ to obtain a block B1. The block B1 is then XORed with P1 to generate
+ the ciphertext block C1. The counter X is then incremented
+*/
+
+ if (EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, c->ctr, AES_BLOCK_SIZE) != 1) {
+ return 0;
+ }
+
+ for (i = 0; i < 16; i++)
+ *out++ = *in++ ^ b1[i];
+
+ i = 15;
+ while (c->ctr[i]++ == 0xFF) {
+ if (i == 0)
+ break;
+ i--;
+ }
+
+ return 1;
+}
+
+static int
+aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */
+{
+ aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx);
+
+ if (c == NULL) {
+ return 1;
+ }
+
+ if (c->aes_ctx != NULL) {
+ _libssh2_cipher_dtor(c->aes_ctx);
+ free(c->aes_ctx);
+ }
+
+ free(c);
+
+ return 1;
+}
+
+static const EVP_CIPHER *
+make_ctr_evp (size_t keylen, EVP_CIPHER *aes_ctr_cipher)
+{
+ aes_ctr_cipher->block_size = 16;
+ aes_ctr_cipher->key_len = keylen;
+ aes_ctr_cipher->iv_len = 16;
+ aes_ctr_cipher->init = aes_ctr_init;
+ aes_ctr_cipher->do_cipher = aes_ctr_do_cipher;
+ aes_ctr_cipher->cleanup = aes_ctr_cleanup;
+
+ return aes_ctr_cipher;
+}
+
+const EVP_CIPHER *
+_libssh2_EVP_aes_128_ctr(void)
+{
+ static EVP_CIPHER aes_ctr_cipher;
+ return !aes_ctr_cipher.key_len?
+ make_ctr_evp (16, &aes_ctr_cipher) : &aes_ctr_cipher;
+}
+
+const EVP_CIPHER *
+_libssh2_EVP_aes_192_ctr(void)
+{
+ static EVP_CIPHER aes_ctr_cipher;
+ return !aes_ctr_cipher.key_len?
+ make_ctr_evp (24, &aes_ctr_cipher) : &aes_ctr_cipher;
+}
+
+const EVP_CIPHER *
+_libssh2_EVP_aes_256_ctr(void)
+{
+ static EVP_CIPHER aes_ctr_cipher;
+ return !aes_ctr_cipher.key_len?
+ make_ctr_evp (32, &aes_ctr_cipher) : &aes_ctr_cipher;
+}
+
+void _libssh2_init_aes_ctr(void)
+{
+ _libssh2_EVP_aes_128_ctr();
+ _libssh2_EVP_aes_192_ctr();
+ _libssh2_EVP_aes_256_ctr();
+}
+
+#else
+void _libssh2_init_aes_ctr(void) {}
+#endif /* LIBSSH2_AES_CTR */
+
+/* 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;
+}
+
+typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *,
+ void * u);
+
+static int
+read_private_key_from_file(void ** key_ctx,
+ pem_read_bio_func read_private_key,
+ const char * filename,
+ unsigned const char *passphrase)
+{
+ BIO * bp;
+
+ *key_ctx = NULL;
+
+ bp = BIO_new_file(filename, "r");
+ if (!bp) {
+ return -1;
+ }
+
+ *key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb,
+ (void *) passphrase);
+
+ BIO_free(bp);
+ return (*key_ctx) ? 0 : -1;
+}
+
+int
+_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
+ LIBSSH2_SESSION * session,
+ const char *filename, unsigned const char *passphrase)
+{
+ pem_read_bio_func read_rsa =
+ (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey;
+ (void) session;
+
+ _libssh2_init_if_needed ();
+
+ return read_private_key_from_file((void **) rsa, read_rsa,
+ filename, passphrase);
+}
+
+#if LIBSSH2_DSA
+int
+_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
+ LIBSSH2_SESSION * session,
+ const char *filename, unsigned const char *passphrase)
+{
+ pem_read_bio_func read_dsa =
+ (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey;
+ (void) session;
+
+ _libssh2_init_if_needed ();
+
+ return read_private_key_from_file((void **) dsa, read_dsa,
+ filename, passphrase);
+}
+#endif /* LIBSSH_DSA */
+
+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)
+{
+ int ret;
+ 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;
+}
+
+#if LIBSSH2_DSA
+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;
+ (void) hash_len;
+
+ sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx);
+ if (!sig) {
+ return -1;
+ }
+
+ r_len = BN_num_bytes(sig->r);
+ if (r_len < 1 || r_len > 20) {
+ DSA_SIG_free(sig);
+ return -1;
+ }
+ s_len = BN_num_bytes(sig->s);
+ if (s_len < 1 || s_len > 20) {
+ DSA_SIG_free(sig);
+ return -1;
+ }
+
+ memset(signature, 0, 40);
+
+ BN_bn2bin(sig->r, signature + (20 - r_len));
+ BN_bn2bin(sig->s, signature + 20 + (20 - s_len));
+
+ DSA_SIG_free(sig);
+
+ return 0;
+}
+#endif /* LIBSSH_DSA */
+
+int
+libssh2_sha1_init(libssh2_sha1_ctx *ctx)
+{
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit(ctx, EVP_get_digestbyname("sha1"));
+}
+
+void
+libssh2_sha1(const unsigned char *message, unsigned long len,
+ unsigned char *out)
+{
+ EVP_MD_CTX ctx;
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_DigestInit(&ctx, EVP_get_digestbyname("sha1"));
+ EVP_DigestUpdate(&ctx, message, len);
+ EVP_DigestFinal(&ctx, out, NULL);
+}
+
+int
+libssh2_md5_init(libssh2_md5_ctx *ctx)
+{
+ EVP_MD_CTX_init(ctx);
+ return EVP_DigestInit(ctx, EVP_get_digestbyname("md5"));
+}
+
+void
+libssh2_md5(const unsigned char *message, unsigned long len,
+ unsigned char *out)
+{
+ EVP_MD_CTX ctx;
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_DigestInit(&ctx, EVP_get_digestbyname("md5"));
+ EVP_DigestUpdate(&ctx, message, len);
+ EVP_DigestFinal(&ctx, out, NULL);
+}
+
+static unsigned char *
+write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes)
+{
+ unsigned char *p = buf;
+
+ /* Left space for bn size which will be written below. */
+ p += 4;
+
+ *p = 0;
+ BN_bn2bin(bn, p + 1);
+ if (!(*(p + 1) & 0x80)) {
+ memmove(p, p + 1, --bn_bytes);
+ }
+ _libssh2_htonu32(p - 4, bn_bytes); /* Post write bn size. */
+
+ return p + bn_bytes;
+}
+
+static unsigned char *
+gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa,
+ size_t *key_len)
+{
+ int e_bytes, n_bytes;
+ unsigned long len;
+ unsigned char* key;
+ unsigned char* p;
+
+ e_bytes = BN_num_bytes(rsa->e) + 1;
+ n_bytes = BN_num_bytes(rsa->n) + 1;
+
+ /* Key form is "ssh-rsa" + e + n. */
+ len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;
+
+ key = LIBSSH2_ALLOC(session, len);
+ if (key == NULL) {
+ return NULL;
+ }
+
+ /* Process key encoding. */
+ p = key;
+
+ _libssh2_htonu32(p, 7); /* Key type. */
+ p += 4;
+ memcpy(p, "ssh-rsa", 7);
+ p += 7;
+
+ p = write_bn(p, rsa->e, e_bytes);
+ p = write_bn(p, rsa->n, n_bytes);
+
+ *key_len = (size_t)(p - key);
+ return key;
+}
+
+static unsigned char *
+gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa,
+ size_t *key_len)
+{
+ int p_bytes, q_bytes, g_bytes, k_bytes;
+ unsigned long len;
+ unsigned char* key;
+ unsigned char* p;
+
+ p_bytes = BN_num_bytes(dsa->p) + 1;
+ q_bytes = BN_num_bytes(dsa->q) + 1;
+ g_bytes = BN_num_bytes(dsa->g) + 1;
+ k_bytes = BN_num_bytes(dsa->pub_key) + 1;
+
+ /* Key form is "ssh-dss" + p + q + g + pub_key. */
+ len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes;
+
+ key = LIBSSH2_ALLOC(session, len);
+ if (key == NULL) {
+ return NULL;
+ }
+
+ /* Process key encoding. */
+ p = key;
+
+ _libssh2_htonu32(p, 7); /* Key type. */
+ p += 4;
+ memcpy(p, "ssh-dss", 7);
+ p += 7;
+
+ p = write_bn(p, dsa->p, p_bytes);
+ p = write_bn(p, dsa->q, q_bytes);
+ p = write_bn(p, dsa->g, g_bytes);
+ p = write_bn(p, dsa->pub_key, k_bytes);
+
+ *key_len = (size_t)(p - key);
+ return key;
+}
+
+static int
+gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ EVP_PKEY *pk)
+{
+ RSA* rsa = NULL;
+ unsigned char* key;
+ unsigned char* method_buf = NULL;
+ size_t key_len;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from RSA private key envelop");
+
+ rsa = EVP_PKEY_get1_RSA(pk);
+ if (rsa == NULL) {
+ /* Assume memory allocation error... what else could it be ? */
+ goto __alloc_error;
+ }
+
+ method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */
+ if (method_buf == NULL) {
+ goto __alloc_error;
+ }
+
+ key = gen_publickey_from_rsa(session, rsa, &key_len);
+ if (key == NULL) {
+ goto __alloc_error;
+ }
+ RSA_free(rsa);
+
+ memcpy(method_buf, "ssh-rsa", 7);
+ *method = method_buf;
+ *method_len = 7;
+ *pubkeydata = key;
+ *pubkeydata_len = key_len;
+ return 0;
+
+ __alloc_error:
+ if (rsa != NULL) {
+ RSA_free(rsa);
+ }
+ if (method_buf != NULL) {
+ LIBSSH2_FREE(session, method_buf);
+ }
+
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+}
+
+static int
+gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ EVP_PKEY *pk)
+{
+ DSA* dsa = NULL;
+ unsigned char* key;
+ unsigned char* method_buf = NULL;
+ size_t key_len;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from DSA private key envelop");
+
+ dsa = EVP_PKEY_get1_DSA(pk);
+ if (dsa == NULL) {
+ /* Assume memory allocation error... what else could it be ? */
+ goto __alloc_error;
+ }
+
+ method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */
+ if (method_buf == NULL) {
+ goto __alloc_error;
+ }
+
+ key = gen_publickey_from_dsa(session, dsa, &key_len);
+ if (key == NULL) {
+ goto __alloc_error;
+ }
+ DSA_free(dsa);
+
+ memcpy(method_buf, "ssh-dss", 7);
+ *method = method_buf;
+ *method_len = 7;
+ *pubkeydata = key;
+ *pubkeydata_len = key_len;
+ return 0;
+
+ __alloc_error:
+ if (dsa != NULL) {
+ DSA_free(dsa);
+ }
+ if (method_buf != NULL) {
+ LIBSSH2_FREE(session, method_buf);
+ }
+
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for private key data");
+}
+
+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)
+{
+ int st;
+ BIO* bp;
+ EVP_PKEY* pk;
+
+ _libssh2_debug(session,
+ LIBSSH2_TRACE_AUTH,
+ "Computing public key from private key file: %s",
+ privatekey);
+
+ bp = BIO_new_file(privatekey, "r");
+ if (bp == NULL) {
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_FILE,
+ "Unable to extract public key from private key "
+ "file: Unable to open private key file");
+ }
+ 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();
+ }
+ BIO_reset(bp);
+ pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase);
+ BIO_free(bp);
+
+ if (pk == NULL) {
+ return _libssh2_error(session,
+ LIBSSH2_ERROR_FILE,
+ "Unable to extract public key "
+ "from private key file: "
+ "Wrong passphrase or invalid/unrecognized "
+ "private key file format");
+ }
+
+ switch (pk->type) {
+ case EVP_PKEY_RSA :
+ st = gen_publickey_from_rsa_evp(
+ session, method, method_len, pubkeydata, pubkeydata_len, pk);
+ break;
+
+ case EVP_PKEY_DSA :
+ st = gen_publickey_from_dsa_evp(
+ session, method, method_len, pubkeydata, pubkeydata_len, pk);
+ break;
+
+ default :
+ st = _libssh2_error(session,
+ LIBSSH2_ERROR_FILE,
+ "Unable to extract public key "
+ "from private key file: "
+ "Unsupported private key file format");
+ break;
+ }
+
+ EVP_PKEY_free(pk);
+ return st;
+}
+
+#endif /* LIBSSH2_OPENSSL */