@@ -3,15 +3,20 @@ package git
33/*
44#include <git2.h>
55#include <git2/credential.h>
6+ #include <git2/sys/credential.h>
67
78git_credential_t _go_git_credential_credtype(git_credential *cred);
9+ void _go_git_populate_credential_ssh_custom(git_credential_ssh_custom *cred);
810*/
911import "C"
1012import (
13+ "crypto/rand"
1114 "fmt"
1215 "runtime"
1316 "strings"
1417 "unsafe"
18+
19+ "golang.org/x/crypto/ssh"
1520)
1621
1722// CredentialType is a bitmask of supported credential types.
@@ -192,6 +197,63 @@ func NewCredentialSSHKeyFromAgent(username string) (*Credential, error) {
192197 return cred , nil
193198}
194199
200+ type credentialSSHCustomData struct {
201+ signer ssh.Signer
202+ }
203+
204+ //export credentialSSHCustomFree
205+ func credentialSSHCustomFree (cred * C.git_credential_ssh_custom ) {
206+ if cred == nil {
207+ return
208+ }
209+
210+ C .free (unsafe .Pointer (cred .username ))
211+ C .free (unsafe .Pointer (cred .publickey ))
212+ pointerHandles .Untrack (cred .payload )
213+ C .free (unsafe .Pointer (cred ))
214+ }
215+
216+ //export credentialSSHSignCallback
217+ func credentialSSHSignCallback (
218+ errorMessage * * C.char ,
219+ sig * * C.uchar ,
220+ sig_len * C.size_t ,
221+ data * C.uchar ,
222+ data_len C.size_t ,
223+ handle unsafe.Pointer ,
224+ ) C.int {
225+ signer := pointerHandles .Get (handle ).(* credentialSSHCustomData ).signer
226+ signature , err := signer .Sign (rand .Reader , C .GoBytes (unsafe .Pointer (data ), C .int (data_len )))
227+ if err != nil {
228+ return setCallbackError (errorMessage , err )
229+ }
230+ * sig = (* C .uchar )(C .CBytes (signature .Blob ))
231+ * sig_len = C .size_t (len (signature .Blob ))
232+ return C .int (ErrorCodeOK )
233+ }
234+
235+ // NewCredentialSSHKeyFromSigner creates new SSH credentials using the provided signer.
236+ func NewCredentialSSHKeyFromSigner (username string , signer ssh.Signer ) (* Credential , error ) {
237+ publicKey := signer .PublicKey ().Marshal ()
238+
239+ ccred := (* C .git_credential_ssh_custom )(C .calloc (1 , C .size_t (unsafe .Sizeof (C.git_credential_ssh_custom {}))))
240+ ccred .parent .credtype = C .GIT_CREDENTIAL_SSH_CUSTOM
241+ ccred .username = C .CString (username )
242+ ccred .publickey = (* C .char )(C .CBytes (publicKey ))
243+ ccred .publickey_len = C .size_t (len (publicKey ))
244+ C ._go_git_populate_credential_ssh_custom (ccred )
245+
246+ data := credentialSSHCustomData {
247+ signer : signer ,
248+ }
249+ ccred .payload = pointerHandles .Track (& data )
250+
251+ cred := newCredential ()
252+ cred .ptr = & ccred .parent
253+
254+ return cred , nil
255+ }
256+
195257func NewCredentialDefault () (* Credential , error ) {
196258 runtime .LockOSThread ()
197259 defer runtime .UnlockOSThread ()
0 commit comments