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