구현체를 기록에 남기기 위해서 백업한다.
해당 function은 libssh2-0.14 소스상에서 src/userauth.c 에서 작업되어졌다. 원본 소스와의 diff 파일을 첨부한다.
diff -u2 src/userauth.c ../../Resource/libssh2-0.14/src/userauth.c
--- src/userauth.c Thu Mar 2 10:07:43 2006
+++ ../../Resource/libssh2-0.14/src/userauth.c Tue Jul 10 16:50:48 2007
@@ -347,4 +347,55 @@
/* }}} */+static int libssh2_memory_read_privatekey(LIBSSH2_SESSION *session, LIBSSH2_HOSTKEY_METHOD **hostkey_method, void **hostkey_abstract,
+ const char *method, int method_len,
+ const char *privkey, const char *passphrase)
+{
+ RSA *rsa = NULL;
+ BIO *mem = BIO_new_mem_buf((char *)privkey, -1);
+ 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)->initPEM &&
+ strncmp((*hostkey_methods_avail)->name, method, method_len) == 0) {
+ *hostkey_method = *hostkey_methods_avail;
+ break;
+ }
+ hostkey_methods_avail++;
+ }
+ if (!*hostkey_method) {
+ libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, "No handler for specified private key", 0);
+ fprintf(stderr, "EXIT #1\n");
+ return -1;
+ }
+
+ if (!passphrase) {
+ fprintf(stderr, "EXIT #2\n");
+ return -1;
+ }
+
+ if (!EVP_get_cipherbyname("des")) {
+ OpenSSL_add_all_ciphers();
+ }
+
+ rsa = PEM_read_bio_RSAPrivateKey(mem, NULL, NULL, (char *)passphrase);
+
+ if (!rsa) {
+ BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+ fprintf(stderr, "EXIT #3\n");
+ return -1;
+ }
+
+ BIO_set_close(mem, BIO_NOCLOSE);
+ BIO_free(mem);
+
+ *hostkey_abstract = (void *)rsa;
+
+ return 0;
+}
+
+
/* {{{ libssh2_userauth_hostbased_fromfile_ex
* Authenticate using a keypair found in the named files
@@ -615,4 +666,168 @@
memcpy(s, method, method_len); s += method_len;
LIBSSH2_FREE(session, method);
+
+ libssh2_htonu32(s, sig_len); s += 4;
+ memcpy(s, sig, sig_len); s += sig_len;
+ LIBSSH2_FREE(session, sig);
+
+#ifdef LIBSSH2_DEBUG_USERAUTH
+ _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
+#endif
+ if (libssh2_packet_write(session, packet, s - packet)) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+ LIBSSH2_FREE(session, packet);
+
+ /* PK_OK is no longer valid */
+ reply_codes[2] = 0;
+
+ if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
+ return -1;
+ }
+
+ if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+#ifdef LIBSSH2_DEBUG_USERAUTH
+ _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Publickey authentication successful");
+#endif
+ /* We are us and we've proved it. */
+ LIBSSH2_FREE(session, data);
+ session->state |= LIBSSH2_STATE_AUTHENTICATED;
+ return 0;
+ }
+
+ /* This public key is not allowed for this user on this server */
+ LIBSSH2_FREE(session, data);
+ libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
+ return -1;
+}
+/* }}} */
+
+/* {{{ libssh2_userauth_publickey_fromstring_ex
+ * Authenticate using a keypair from built-in string
+ */
+LIBSSH2_API int libssh2_userauth_publickey_fromstring_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
+ const char *publickey, int publickey_len, const char *privatekey,
+ const char *passphrase)
+{
+ LIBSSH2_HOSTKEY_METHOD *privkeyobj;
+ void *abstract;
+ unsigned char buf[5];
+ struct iovec datavec[4];
+ unsigned char *method, *pubkeydata, *packet, *s, *b, *sig, *data;
+ unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
+ unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;
+
+ method = "ssh-rsa";
+ method_len = 7;
+ pubkeydata = (char *)publickey;
+ pubkeydata_len = publickey_len;
+
+ packet_len = username_len + method_len + pubkeydata_len + 45; /* packet_type(1) + username_len(4) + servicename_len(4) +
+ service_name(14)"ssh-connection" + authmethod_len(4) +
+ authmethod(9)"publickey" + sig_included(1)'\0' +
+ algmethod_len(4) + publickey_len(4) */
+ /* Preallocate space for an overall length, method name again,
+ * and the signature, which won't be any larger than the size of the publickeydata itself */
+ s = packet = LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));
+
+ *(s++) = SSH_MSG_USERAUTH_REQUEST;
+ libssh2_htonu32(s, username_len); s += 4;
+ memcpy(s, username, username_len); s += username_len;
+
+ libssh2_htonu32(s, 14); s += 4;
+ memcpy(s, "ssh-connection", 14); s += 14;
+
+ libssh2_htonu32(s, 9); s += 4;
+ memcpy(s, "publickey", 9); s += 9;
+
+ b = s;
+ *(s++) = 0; /* Not sending signature with *this* packet */
+
+ libssh2_htonu32(s, method_len); s += 4;
+ memcpy(s, method, method_len); s += method_len;
+
+ libssh2_htonu32(s, pubkeydata_len); s += 4;
+ memcpy(s, pubkeydata, pubkeydata_len); s += pubkeydata_len;
+
+#ifdef LIBSSH2_DEBUG_USERAUTH
+ _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
+#endif
+ if (libssh2_packet_write(session, packet, packet_len)) {
+ libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+
+ if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+
+ if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
+#ifdef LIBSSH2_DEBUG_USERAUTH
+ _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
+#endif
+ /* God help any SSH server that allows an UNVERIFIED public key to validate the user */
+ LIBSSH2_FREE(session, data);
+ LIBSSH2_FREE(session, packet);
+ session->state |= LIBSSH2_STATE_AUTHENTICATED;
+ return 0;
+ }
+
+ if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
+ /* This public key is not allowed for this user on this server */
+ LIBSSH2_FREE(session, data);
+ LIBSSH2_FREE(session, packet);
+ libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
+ return -1;
+ }
+
+ /* Semi-Success! */
+ LIBSSH2_FREE(session, data);
+
+ if (libssh2_memory_read_privatekey(session, &privkeyobj, &abstract, method, method_len, privatekey, passphrase)) {
+ LIBSSH2_FREE(session, packet);
+ return -1;
+ }
+
+ *b = 0xFF;
+
+ libssh2_htonu32(buf, session->session_id_len);
+ datavec[0].iov_base = buf;
+ datavec[0].iov_len = 4;
+ datavec[1].iov_base = session->session_id;
+ datavec[1].iov_len = session->session_id_len;
+ datavec[2].iov_base = packet;
+ datavec[2].iov_len = packet_len;
+
+ if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
+ LIBSSH2_FREE(session, packet);
+ if (privkeyobj->dtor) {
+ privkeyobj->dtor(session, &abstract);
+ }
+ return -1;
+ }
+
+ if (privkeyobj->dtor) {
+ privkeyobj->dtor(session, &abstract);
+ }
+
+ if (sig_len > pubkeydata_len) {
+ /* Should *NEVER* happen, but...well.. better safe than sorry */
+ packet = LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
+ if (!packet) {
+ libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-publickey packet", 0);
+ return -1;
+ }
+ }
+
+ s = packet + packet_len;
+
+ libssh2_htonu32(s, 4 + method_len + 4 + sig_len); s += 4;
+
+ libssh2_htonu32(s, method_len); s += 4;
+ memcpy(s, method, method_len); s += method_len;libssh2_htonu32(s, sig_len); s += 4;
diff -u2 include/libssh2.h ../../Resource/libssh2-0.14/include/libssh2.h
--- include/libssh2.h Fri Jun 23 03:47:56 2006
+++ ../../Resource/libssh2-0.14/include/libssh2.h Fri Apr 13 15:31:32 2007
@@ -288,4 +288,11 @@
#define libssh2_userauth_publickey_fromfile(session, username, publickey, privatekey, passphrase) \
libssh2_userauth_publickey_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase))
+
+LIBSSH2_API int libssh2_userauth_publickey_fromstring_ex(LIBSSH2_SESSION *session, const char *username, int username_len,
+ const char *publickey, int publickey_len, const char *privatekey,
+ const char *passphrase);
+#define libssh2_userauth_publickey_fromstring(session, username, publickey, publickey_len, privatekey, passphrase) \
+ libssh2_userauth_publickey_fromstring_ex((session), (username), strlen(username), (publickey), (publickey_len), (privatekey), (passphrase))
+
LIBSSH2_API int libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, const char *username, int username_len,const char *publickey, const char *privatekey,
diff -u2 include/libssh2_priv.h ../../Resource/libssh2-0.14/include/libssh2_priv.h
--- include/libssh2_priv.h Fri Jun 23 03:30:36 2006
+++ ../../Resource/libssh2-0.14/include/libssh2_priv.h Fri Apr 13 15:22:42 2007
@@ -53,4 +53,7 @@
#include <openssl/md5.h>
#endif
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>#ifdef __hpux
2007/07/04 - [작업로그(SE)/쉘 혹은 명령] - 원격 접속 자동화 (1): rsa 및 dsa key, ssh-agent 사용
2007/07/09 - [작업로그(SE)/쉘 혹은 명령] - 원격 접속 자동화 (2): Script Shell: expect
2007/07/10 - [프로그래밍/Library] - 원격 접속 자동화 (3): libssh
2007/08/09 - [프로그래밍/Library] - 원격 접속 자동화 (3) 추가: libssh2 활용 코드
'프로그래밍 > Library, Utility, ETC' 카테고리의 다른 글
#pragma pack 으로 byte alignment 맞추기 (2) | 2007.08.17 |
---|---|
원격 접속 자동화 (3) 추가: libssh2 활용 코드 (4) | 2007.08.09 |
Socket Programming으로 작성한 HTTP Client를 통한, HTTP 서버로의 요청 / 응답 수신 (1) | 2007.08.03 |
fcntl을 사용한 file lock (lock, unlock) (0) | 2007.07.31 |
conv_addr: inet_addr + Domain Resolving (0) | 2007.07.25 |