Commit c36565c0eea7b97726cffaeaf9abe2a3279ff70b

Brad Morgan 2013-05-07T13:43:10

Added SSH public key authentication

diff --git a/include/git2/transport.h b/include/git2/transport.h
index 31572c1..cc29f8b 100644
--- a/include/git2/transport.h
+++ b/include/git2/transport.h
@@ -11,6 +11,8 @@
 #include "net.h"
 #include "types.h"
 
+#include <libssh2.h>
+
 /**
  * @file git2/transport.h
  * @brief Git transport interfaces and functions
@@ -28,6 +30,7 @@ typedef enum {
 	/* git_cred_userpass_plaintext */
 	GIT_CREDTYPE_USERPASS_PLAINTEXT = 1,
 	GIT_CREDTYPE_SSH_KEYFILE_PASSPHRASE = 2,
+	GIT_CREDTYPE_SSH_PUBLICKEY = 3,
 } git_credtype_t;
 
 /* The base structure for all credential types */
@@ -44,7 +47,7 @@ typedef struct git_cred_userpass_plaintext {
 	char *password;
 } git_cred_userpass_plaintext;
 
-/* A plaintext username and password */
+/* A ssh key file and passphrase */
 typedef struct git_cred_ssh_keyfile_passphrase {
 	git_cred parent;
 	char *publickey;
@@ -52,6 +55,15 @@ typedef struct git_cred_ssh_keyfile_passphrase {
 	char *passphrase;
 } git_cred_ssh_keyfile_passphrase;
 
+/* A ssh public key and authentication callback */
+typedef struct git_cred_ssh_publickey {
+	git_cred parent;
+	char *publickey;
+    size_t publickey_len;
+	void *sign_callback;
+	void *sign_data;
+} git_cred_ssh_publickey;
+
 /**
  * Creates a new plain-text username and password credential object.
  * The supplied credential parameter will be internally duplicated.
@@ -83,6 +95,24 @@ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new(
     const char *passphrase);
 
 /**
+ * Creates a new ssh public key credential object.
+ * The supplied credential parameter will be internally duplicated.
+ *
+ * @param out The newly created credential object.
+ * @param publickey The bytes of the public key.
+ * @param publickey_len The length of the public key in bytes.
+ * @param sign_callback The callback method for authenticating.
+ * @param sign_data The abstract data sent to the sign_callback method.
+ * @return 0 for success or an error code for failure
+ */
+GIT_EXTERN(int) git_cred_ssh_publickey_new(
+	git_cred **out,
+	const char *publickey,
+    size_t publickey_len,
+    LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
+    void *sign_data);
+
+/**
  * Signature of a function which acquires a credential object.
  *
  * @param cred The newly created credential object.
diff --git a/src/transports/cred.c b/src/transports/cred.c
index 83820ec..5d5e745 100644
--- a/src/transports/cred.c
+++ b/src/transports/cred.c
@@ -135,3 +135,52 @@ int git_cred_ssh_keyfile_passphrase_new(
 	*cred = &c->parent;
 	return 0;
 }
+
+static void ssh_publickey_free(struct git_cred *cred)
+{
+	git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred;
+
+    git__free(c->publickey);
+
+    c->sign_callback = NULL;
+    c->sign_data = NULL;
+    
+	memset(c, 0, sizeof(*c));
+
+	git__free(c);
+}
+
+int git_cred_ssh_publickey_new(
+	git_cred **cred,
+	const char *publickey,
+    size_t publickey_len,
+	LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
+    void *sign_data)
+{
+	git_cred_ssh_publickey *c;
+
+	if (!cred)
+		return -1;
+
+	c = git__malloc(sizeof(git_cred_ssh_publickey));
+	GITERR_CHECK_ALLOC(c);
+
+	c->parent.credtype = GIT_CREDTYPE_SSH_PUBLICKEY;
+	c->parent.free = ssh_publickey_free;
+    
+    c->publickey = git__malloc(publickey_len);
+    memcpy(c->publickey, publickey, publickey_len);
+    
+    if (!c->publickey) {
+        git__free(c);
+        return -1;
+    }
+    
+    c->publickey_len = publickey_len;
+    
+    c->sign_callback = sign_callback;
+    c->sign_data = sign_data;
+
+	*cred = &c->parent;
+	return 0;
+}
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 9ee13be..a1df6c4 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -253,6 +253,18 @@ static int _git_ssh_authenticate_session(
 				);
 				break;
 			}
+			case GIT_CREDTYPE_SSH_PUBLICKEY: {
+				git_cred_ssh_publickey *c = (git_cred_ssh_publickey *)cred;
+				rc = libssh2_userauth_publickey(
+					session,
+					user,
+					(const unsigned char *)c->publickey,
+					c->publickey_len,
+					c->sign_callback,
+					&c->sign_data
+				);
+				break;
+			}
 			default:
 				rc = LIBSSH2_ERROR_AUTHENTICATION_FAILED;
 		}