--- ./libssh2-1.0/src/userauth.c	2008-11-28 00:12:41.000000000 +0100
+++ /tmp/userauth.c	2009-03-27 12:06:35.000000000 +0100
@@ -46,6 +46,277 @@
 #endif
 
 
+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,
+                          unsigned long*   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 = (unsigned long)(p - key);
+    return key;
+}
+
+
+static unsigned char* gen_publickey_from_dsa(
+                          LIBSSH2_SESSION* session,
+                          DSA*             dsa,
+                          unsigned long*   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 = (unsigned long)(p - key);
+    return key;
+}
+
+
+static int gen_publickey_from_rsa_evp(
+               LIBSSH2_SESSION* session,
+               unsigned char**  method,
+               unsigned long*   method_len,
+               unsigned char**  pubkeydata,
+               unsigned long*   pubkeydata_len,
+               EVP_PKEY*        pk)
+{
+    RSA*           rsa = NULL;
+    unsigned char* key;
+    unsigned char* method_buf = NULL;
+    unsigned long  key_len;
+
+    _libssh2_debug(session,
+                   LIBSSH2_DBG_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);
+    }
+
+    libssh2_error(session,
+                  LIBSSH2_ERROR_ALLOC,
+                  "Unable to allocate memory for private key data", 0);
+    return -1;
+}
+
+
+static int gen_publickey_from_dsa_evp(
+               LIBSSH2_SESSION* session,
+               unsigned char**  method,
+               unsigned long*   method_len,
+               unsigned char**  pubkeydata,
+               unsigned long*   pubkeydata_len,
+               EVP_PKEY*        pk)
+{
+    DSA*           dsa = NULL;
+    unsigned char* key;
+    unsigned char* method_buf = NULL;
+    unsigned long  key_len;
+
+    _libssh2_debug(session,
+                   LIBSSH2_DBG_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);
+    }
+
+    libssh2_error(session,
+                  LIBSSH2_ERROR_ALLOC,
+                  "Unable to allocate memory for private key data", 0);
+    return -1;
+}
+
+
+static int gen_publickey_from_private_keyfile(
+               LIBSSH2_SESSION* session,
+               unsigned char**  method,
+               unsigned long*   method_len,
+               unsigned char**  pubkeydata,
+               unsigned long*   pubkeydata_len,
+               const char*      privatekey,
+               const char*      passphrase)
+{
+    int       st;
+    FILE*     fp;
+    EVP_PKEY* pk;
+
+    _libssh2_debug(session,
+                   LIBSSH2_DBG_AUTH,
+                   "Computing public key from private key file: %s",
+                   privatekey);
+
+    fp = fopen(privatekey, "r");
+    if (fp == NULL) {
+        libssh2_error(session,
+                      LIBSSH2_ERROR_FILE,
+                      "Unable to open private key file", 0);
+        return -1;
+    }
+
+    pk = PEM_read_PrivateKey(fp, NULL, NULL, (void*)passphrase);
+    fclose(fp);
+
+    if (pk == NULL) {
+        libssh2_error(session,
+                      LIBSSH2_ERROR_FILE,
+                      "Wrong passphrase or invalid/unrecognized "
+                      "private key file format", 0);
+        return -1;
+    }
+
+    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 = -1;
+        libssh2_error(session,
+                      LIBSSH2_ERROR_FILE,
+                      "Unsupported private key file format", 0);
+        break;
+    }
+
+    EVP_PKEY_free(pk);
+    return st;
+}
+
+
 /* {{{ proto libssh2_userauth_list
  * List authentication methods
  * Will yield successful login if "none" happens to be allowable for this user
@@ -607,11 +878,28 @@
         memset(&session->userauth_host_packet_requirev_state, 0,
                sizeof(session->userauth_host_packet_requirev_state));
 
-        if (libssh2_file_read_publickey
-            (session, &session->userauth_host_method,
-             &session->userauth_host_method_len, &pubkeydata, &pubkeydata_len,
-             publickey)) {
-            return -1;
+        if (publickey != NULL) {
+            if (libssh2_file_read_publickey(
+                    session,
+                    &session->userauth_host_method,
+                    &session->userauth_host_method_len,
+                    &pubkeydata, &pubkeydata_len,
+                    publickey)) {
+                return -1;
+            }
+        }
+        else {
+            /* Compute public key from private key. */
+            if (gen_publickey_from_private_keyfile(
+                    session,
+                    &session->userauth_host_method,
+                    &session->userauth_host_method_len,
+                    &pubkeydata,
+                    &pubkeydata_len,
+                    privatekey,
+                    passphrase)) {
+                return -1;
+            }
         }
 
         /*
@@ -841,11 +1129,29 @@
         memset(&session->userauth_pblc_packet_requirev_state, 0,
                sizeof(session->userauth_pblc_packet_requirev_state));
 
-        if (libssh2_file_read_publickey
-            (session, &session->userauth_pblc_method,
-             &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len,
-             publickey)) {
-            return -1;
+        if (publickey != NULL) {
+            if (libssh2_file_read_publickey(
+                    session,
+                    &session->userauth_pblc_method,
+                    &session->userauth_pblc_method_len,
+                    &pubkeydata,
+                    &pubkeydata_len,
+                    publickey)) {
+                return -1;
+            }
+        }
+        else {
+            /* Compute public key from private key. */
+            if (gen_publickey_from_private_keyfile(
+                    session,
+                    &session->userauth_pblc_method,
+                    &session->userauth_pblc_method_len,
+                    &pubkeydata,
+                    &pubkeydata_len,
+                    privatekey,
+                    passphrase)) {
+                return -1;
+            }
         }
 
         /*
