diff --git a/include/git2/transport.h b/include/git2/transport.h index 31572c16a..cc29f8b0e 100644 --- a/include/git2/transport.h +++ b/include/git2/transport.h @@ -11,6 +11,8 @@ #include "net.h" #include "types.h" +#include + /** * @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. @@ -82,6 +94,24 @@ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( const char *privatekey, 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. * diff --git a/src/transports/cred.c b/src/transports/cred.c index 83820ec05..5d5e745ff 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 9ee13becf..a1df6c492 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; }