On Tue, Jan 17, 2012 at 4:34 PM, Joe Turpin <joe.tur...@gmail.com> wrote:
> Hi all,
> I'm trying to do what this poster describes here:
> http://www.libssh2.org/mail/libssh2-devel-archive-2011-04/0004.shtml
>
> I don't see a solution in that thread and was wondering if there has
> been any progress on that front?
>
> Thanks,
> Joe

Okay, since I didn't hear from anyone I decided to code something up.
I exported another function called
libssh2_userauth_publickey_frommemory. If anyone's interested, here's
a patch that should apply cleanly against libssh2 1.3.0.

I may have missed some things in my haste, but I tested and it works.
Comments and criticism are welcome.

Index: libssh2-1.3.0/include/libssh2.h
===================================================================
--- libssh2-1.3.0/include/libssh2.h
+++ libssh2-1.3.0/include/libssh2.h
@@ -513,6 +513,16 @@
                                        const char *privatekey,
                                        const char *passphrase);

+LIBSSH2_API int
+libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
+                                       const char *username,
+                                       unsigned int username_len,
+                                       const char *publickeyfiledata,
+                                       size_t publickeyfiledata_len,
+                                       const char *privatekeyfiledata,
+                                       size_t privatekeyfiledata_len,
+                                       const char *passphrase);
+
 #define libssh2_userauth_publickey_fromfile(session, username, publickey, \
                                             privatekey, passphrase)     \
   libssh2_userauth_publickey_fromfile_ex((session), (username), \
Index: libssh2-1.3.0/src/hostkey.c
===================================================================
--- libssh2-1.3.0/src/hostkey.c
+++ libssh2-1.3.0/src/hostkey.c
@@ -131,6 +131,36 @@
 }

 /*
+ * hostkey_method_ssh_rsa_initPEMFromMemory
+ *
+ * Load a Private Key from a memory
+ */
+static int
+hostkey_method_ssh_rsa_initPEMFromMemory(LIBSSH2_SESSION * session,
+                               const char *privkeyfiledata,
+                               size_t privkeyfiledata_len,
+                               unsigned const char *passphrase,
+                               void **abstract)
+{
+    libssh2_rsa_ctx *rsactx;
+    int ret;
+
+    if (*abstract) {
+        hostkey_method_ssh_rsa_dtor(session, abstract);
+        *abstract = NULL;
+    }
+
+    ret = _libssh2_rsa_new_private_frommemory(&rsactx, session,
privkeyfiledata, privkeyfiledata_len, passphrase);
+    if (ret) {
+        return -1;
+    }
+
+    *abstract = rsactx;
+
+    return 0;
+}
+
+/*
  * hostkey_method_ssh_rsa_sign
  *
  * Verify signature created by remote
@@ -208,6 +238,7 @@
     MD5_DIGEST_LENGTH,
     hostkey_method_ssh_rsa_init,
     hostkey_method_ssh_rsa_initPEM,
+    hostkey_method_ssh_rsa_initPEMFromMemory,
     hostkey_method_ssh_rsa_sig_verify,
     hostkey_method_ssh_rsa_signv,
     NULL,                       /* encrypt */
@@ -306,6 +337,36 @@
 }

 /*
+ * hostkey_method_ssh_dss_initPEMFromMemory
+ *
+ * Load a Private Key from memory
+ */
+static int
+hostkey_method_ssh_dss_initPEMFromMemory(LIBSSH2_SESSION * session,
+                               const char *privkeyfiledata,
+                                                          size_t 
privkeyfiledata_len,
+                               unsigned const char *passphrase,
+                               void **abstract)
+{
+    libssh2_dsa_ctx *dsactx;
+    int ret;
+
+    if (*abstract) {
+        hostkey_method_ssh_dss_dtor(session, abstract);
+        *abstract = NULL;
+    }
+
+    ret = _libssh2_dsa_new_private_frommemory(&dsactx, session,
privkeyfiledata, privkeyfiledata_len, passphrase);
+    if (ret) {
+        return -1;
+    }
+
+    *abstract = dsactx;
+
+    return 0;
+}
+
+/*
  * libssh2_hostkey_method_ssh_dss_sign
  *
  * Verify signature created by remote
@@ -392,6 +453,7 @@
     MD5_DIGEST_LENGTH,
     hostkey_method_ssh_dss_init,
     hostkey_method_ssh_dss_initPEM,
+    hostkey_method_ssh_dss_initPEMFromMemory,
     hostkey_method_ssh_dss_sig_verify,
     hostkey_method_ssh_dss_signv,
     NULL,                       /* encrypt */
Index: libssh2-1.3.0/src/userauth.c
===================================================================
--- libssh2-1.3.0/src/userauth.c
+++ libssh2-1.3.0/src/userauth.c
@@ -441,6 +441,79 @@
     return rc;
 }

+static int
+memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
+                    size_t *method_len,
+                    unsigned char **pubkeydata,
+                    size_t *pubkeydata_len,
+                    const char *pubkeyfiledata,
+                    size_t pubkeyfiledata_len)
+{
+    char c;
+    unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
+    size_t pubkey_len = pubkeyfiledata_len;
+    unsigned int tmp_len;
+
+    if (pubkeyfiledata_len <= 1) {
+        return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                              "Invalid data in public key file");
+    }
+
+    pubkey = LIBSSH2_ALLOC(session, pubkeyfiledata_len);
+    if (!pubkey) {
+        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+                              "Unable to allocate memory for public key data");
+    }
+       if (memcpy_s(pubkey, pubkeyfiledata_len, pubkeyfiledata,
pubkeyfiledata_len) != 0) {
+        LIBSSH2_FREE(session, pubkey);
+        return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                              "Unable to read public key from file");
+    }
+
+       /*
+     * Remove trailing whitespace
+     */
+    while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
+        pubkey_len--;
+
+    if (!pubkey_len) {
+        LIBSSH2_FREE(session, pubkey);
+        return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                              "Missing public key data");
+    }
+
+    if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
+        LIBSSH2_FREE(session, pubkey);
+        return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                              "Invalid public key data");
+    }
+
+    sp1++;
+
+    if ((sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey - 1))) == NULL) {
+        /* Assume that the id string is missing, but that it's okay */
+        sp2 = pubkey + pubkey_len;
+    }
+
+    if (libssh2_base64_decode(session, (char **) &tmp, &tmp_len,
+                              (char *) sp1, sp2 - sp1)) {
+        LIBSSH2_FREE(session, pubkey);
+        return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                              "Invalid key data, not base64 encoded");
+    }
+
+    /* Wasting some bytes here (okay, more than some), but since it's likely
+     * to be freed soon anyway, we'll just avoid the extra free/alloc and call
+     * it a wash */
+    *method = pubkey;
+    *method_len = sp1 - pubkey - 1;
+
+    *pubkeydata = tmp;
+    *pubkeydata_len = tmp_len;
+
+    return 0;
+}
+
 /*
  * file_read_publickey
  *
@@ -543,8 +616,43 @@
     return 0;
 }

+static int
+memory_read_privatekey(LIBSSH2_SESSION * session,
+                     const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
+                     void **hostkey_abstract,
+                     const unsigned char *method, int method_len,
+                     const char *privkeyfiledata, size_t privkeyfiledata_len,
+                     const char *passphrase)
+{
+    const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
+        libssh2_hostkey_methods();

+    *hostkey_method = NULL;
+    *hostkey_abstract = NULL;
+    while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
+        if ((*hostkey_methods_avail)->initPEMFromMemory
+            && strncmp((*hostkey_methods_avail)->name, (const char *) method,
+                       method_len) == 0) {
+            *hostkey_method = *hostkey_methods_avail;
+            break;
+        }
+        hostkey_methods_avail++;
+    }
+    if (!*hostkey_method) {
+        return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
+                              "No handler for specified private key");
+    }

+    if ((*hostkey_method)->
+        initPEMFromMemory(session, privkeyfiledata,
privkeyfiledata_len, (unsigned char *) passphrase,
+                hostkey_abstract)) {
+        return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+                              "Unable to initialize private key from file");
+    }
+
+    return 0;
+}
+
 /* libssh2_file_read_privatekey
  * Read a PEM encoded private key from an id_??? style file
  */
@@ -586,12 +694,49 @@
     return 0;
 }

+
 struct privkey_file {
     const char *filename;
     const char *passphrase;
 };

 static int
+sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
+              const unsigned char *data, size_t data_len, void **abstract)
+{
+    struct privkey_file *pk_file = (struct privkey_file *) (*abstract);
+    const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
+    void *hostkey_abstract;
+    struct iovec datavec;
+    int rc;
+
+    rc = memory_read_privatekey(session, &privkeyobj, &hostkey_abstract,
+                              session->userauth_pblc_method,
+                              session->userauth_pblc_method_len,
+                              pk_file->filename,
+                              strlen(pk_file->filename),
+                              pk_file->passphrase);
+    if(rc)
+        return rc;
+
+    datavec.iov_base = (void *)data;
+    datavec.iov_len  = data_len;
+
+    if (privkeyobj->signv(session, sig, sig_len, 1, &datavec,
+                          &hostkey_abstract)) {
+        if (privkeyobj->dtor) {
+            privkeyobj->dtor(session, abstract);
+        }
+        return -1;
+    }
+
+    if (privkeyobj->dtor) {
+        privkeyobj->dtor(session, &hostkey_abstract);
+    }
+    return 0;
+}
+
+static int
 sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
               const unsigned char *data, size_t data_len, void **abstract)
 {
@@ -1212,6 +1357,59 @@
 }

 /*
+ * userauth_publickey_frommemory
+ * Authenticate using a keypair from memory
+ */
+static int
+userauth_publickey_frommemory(LIBSSH2_SESSION *session,
+                            const char *username,
+                            size_t username_len,
+                            const char *publickey,
+                            size_t publickey_len,
+                            const char *privatekey,
+                            size_t privatekey_len,
+                            const char *passphrase)
+{
+    unsigned char *pubkeydata = NULL;
+    size_t pubkeydata_len = 0;
+    struct privkey_file privkey_file;
+    void *abstract = &privkey_file;
+    int rc;
+
+    privkey_file.filename = privatekey;
+    privkey_file.passphrase = passphrase;
+
+    if (session->userauth_pblc_state == libssh2_NB_state_idle) {
+        if (publickey) {
+            rc = memory_read_publickey(session, &session->userauth_pblc_method,
+                                     &session->userauth_pblc_method_len,
+                                     &pubkeydata, &pubkeydata_len,
publickey, publickey_len);
+            if(rc)
+                return rc;
+        }
+        else {
+            ///* Compute public key from private key. */
+            //if (_libssh2_pub_priv_keyfile(session,
+            //                              &session->userauth_pblc_method,
+            //                              &session->userauth_pblc_method_len,
+            //                              &pubkeydata, &pubkeydata_len,
+            //                              privatekey, passphrase))
+            //    return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+            //                          "Unable to extract public key "
+            //                          "from private key file");
+        }
+    }
+
+    rc = _libssh2_userauth_publickey(session, username, username_len,
+                                     pubkeydata, pubkeydata_len,
+                                     sign_frommemory, &abstract);
+    if(pubkeydata)
+        LIBSSH2_FREE(session, pubkeydata);
+
+    return rc;
+}
+
+/*
  * userauth_publickey_fromfile
  * Authenticate using a keypair found in the named files
  */
@@ -1262,6 +1460,34 @@
     return rc;
 }

+/* libssh2_userauth_publickey_frommemory
+ * Authenticate using a keypair from memory
+ */
+LIBSSH2_API int
+libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
+                                       const char *user,
+                                       unsigned int user_len,
+                                       const char *publickeyfiledata,
+                                       size_t publickeyfiledata_len,
+                                       const char *privatekeyfiledata,
+                                       size_t privatekeyfiledata_len,
+                                       const char *passphrase)
+{
+    int rc;
+
+    if(NULL == passphrase)
+        /* if given a NULL pointer, make it point to a zero-length
+           string to save us from having to check this all over */
+        passphrase="";
+
+    BLOCK_ADJUST(rc, session,
+                 userauth_publickey_frommemory(session, user, user_len,
+                                             publickeyfiledata,
publickeyfiledata_len,
+                                                                               
         privatekeyfiledata, privatekeyfiledata_len,
+                                             passphrase));
+    return rc;
+}
+
 /* libssh2_userauth_publickey_fromfile_ex
  * Authenticate using a keypair found in the named files
  */
Index: libssh2-1.3.0/src/libssh2_priv.h
===================================================================
--- libssh2-1.3.0/src/libssh2_priv.h
+++ libssh2-1.3.0/src/libssh2_priv.h
@@ -849,6 +849,9 @@
                  size_t hostkey_data_len, void **abstract);
     int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile,
                     unsigned const char *passphrase, void **abstract);
+    int (*initPEMFromMemory) (LIBSSH2_SESSION * session,
+                    const char *privkeyfiledata, size_t privkeyfiledata_len,
+                    unsigned const char *passphrase, void **abstract);
     int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig,
                        size_t sig_len, const unsigned char *m,
                        size_t m_len, void **abstract);
Index: libssh2-1.3.0/src/openssl.c
===================================================================
--- libssh2-1.3.0/src/openssl.c
+++ libssh2-1.3.0/src/openssl.c
@@ -370,7 +370,27 @@

 typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *,
                                     void * u);
+static int
+read_private_key_from_memory(void ** key_ctx,
+                           pem_read_bio_func read_private_key,
+                           const char * filedata,
+                           size_t filedata_len,
+                           unsigned const char *passphrase)
+{
+    BIO * bp;

+    *key_ctx = NULL;
+
+       bp = BIO_new_mem_buf(filedata, filedata_len);
+    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;
+}
+
 static int
 read_private_key_from_file(void ** key_ctx,
                            pem_read_bio_func read_private_key,
@@ -394,6 +414,22 @@
 }

 int
+_libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
+                         LIBSSH2_SESSION * session,
+                         const char *filedata, size_t filedata_len,
+                         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_memory((void **) rsa, read_rsa,
+                                      filedata, filedata_len, passphrase);
+}
+
+int
 _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
                          LIBSSH2_SESSION * session,
                          const char *filename, unsigned const char *passphrase)
@@ -410,6 +446,22 @@

 #if LIBSSH2_DSA
 int
+_libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
+                         LIBSSH2_SESSION * session,
+                         const char *filedata, size_t filedata_len,
+                         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_memory((void **) dsa, read_dsa,
+                                      filedata, filedata_len, passphrase);
+}
+
+int
 _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
                          LIBSSH2_SESSION * session,
                          const char *filename, unsigned const char *passphrase)
_______________________________________________
libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel

Reply via email to