diff options
| author | lhchavez <[email protected]> | 2020-12-06 11:55:04 -0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-12-06 11:55:04 -0800 |
| commit | abf02bc7d79dfb7b0bbcd404ebecb202cff2a18e (patch) | |
| tree | ec93caf1ed9238b91e7ec6a1c1e470441860f6fc /credentials.go | |
| parent | 54afccfa0f5a5574525cbba3b4568cbda252a3df (diff) | |
Add `NewCredentialSSHKeyFromSigner` (#706)
This change adds `NewCredentialSSHKeyFromSigner`, which allows idiomatic
use of SSH keys from Go. This also lets us spin off an SSH server in the
tests.
Diffstat (limited to 'credentials.go')
| -rw-r--r-- | credentials.go | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/credentials.go b/credentials.go index b1051b9..deb399a 100644 --- a/credentials.go +++ b/credentials.go @@ -3,15 +3,20 @@ package git /* #include <git2.h> #include <git2/credential.h> +#include <git2/sys/credential.h> git_credential_t _go_git_credential_credtype(git_credential *cred); +void _go_git_populate_credential_ssh_custom(git_credential_ssh_custom *cred); */ import "C" import ( + "crypto/rand" "fmt" "runtime" "strings" "unsafe" + + "golang.org/x/crypto/ssh" ) // CredentialType is a bitmask of supported credential types. @@ -192,6 +197,63 @@ func NewCredentialSSHKeyFromAgent(username string) (*Credential, error) { return cred, nil } +type credentialSSHCustomData struct { + signer ssh.Signer +} + +//export credentialSSHCustomFree +func credentialSSHCustomFree(cred *C.git_credential_ssh_custom) { + if cred == nil { + return + } + + C.free(unsafe.Pointer(cred.username)) + C.free(unsafe.Pointer(cred.publickey)) + pointerHandles.Untrack(cred.payload) + C.free(unsafe.Pointer(cred)) +} + +//export credentialSSHSignCallback +func credentialSSHSignCallback( + errorMessage **C.char, + sig **C.uchar, + sig_len *C.size_t, + data *C.uchar, + data_len C.size_t, + handle unsafe.Pointer, +) C.int { + signer := pointerHandles.Get(handle).(*credentialSSHCustomData).signer + signature, err := signer.Sign(rand.Reader, C.GoBytes(unsafe.Pointer(data), C.int(data_len))) + if err != nil { + return setCallbackError(errorMessage, err) + } + *sig = (*C.uchar)(C.CBytes(signature.Blob)) + *sig_len = C.size_t(len(signature.Blob)) + return C.int(ErrorCodeOK) +} + +// NewCredentialSSHKeyFromSigner creates new SSH credentials using the provided signer. +func NewCredentialSSHKeyFromSigner(username string, signer ssh.Signer) (*Credential, error) { + publicKey := signer.PublicKey().Marshal() + + ccred := (*C.git_credential_ssh_custom)(C.calloc(1, C.size_t(unsafe.Sizeof(C.git_credential_ssh_custom{})))) + ccred.parent.credtype = C.GIT_CREDENTIAL_SSH_CUSTOM + ccred.username = C.CString(username) + ccred.publickey = (*C.char)(C.CBytes(publicKey)) + ccred.publickey_len = C.size_t(len(publicKey)) + C._go_git_populate_credential_ssh_custom(ccred) + + data := credentialSSHCustomData{ + signer: signer, + } + ccred.payload = pointerHandles.Track(&data) + + cred := newCredential() + cred.ptr = &ccred.parent + + return cred, nil +} + func NewCredentialDefault() (*Credential, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() |
