Add support for hostkey certificates
While they're not exactly certificates, they belong in the same category.
This commit is contained in:
parent
a81abd10ca
commit
d9dfc4bce8
65
remote.go
65
remote.go
|
@ -2,6 +2,7 @@ package git
|
|||
|
||||
/*
|
||||
#include <git2.h>
|
||||
#include <strings.h>
|
||||
|
||||
extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
|
||||
|
||||
|
@ -45,7 +46,7 @@ type CompletionCallback func(RemoteCompletion) int
|
|||
type CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (int, *Cred)
|
||||
type TransferProgressCallback func(stats TransferProgress) int
|
||||
type UpdateTipsCallback func(refname string, a *Oid, b *Oid) int
|
||||
type CertificateCheckCallback func(cert *x509.Certificate, valid bool, hostname string) int
|
||||
type CertificateCheckCallback func(cert *Certificate, valid bool, hostname string) int
|
||||
|
||||
type RemoteCallbacks struct {
|
||||
SidebandProgressCallback TransportMessageCallback
|
||||
|
@ -61,6 +62,39 @@ type Remote struct {
|
|||
callbacks RemoteCallbacks
|
||||
}
|
||||
|
||||
type CertificateKind uint
|
||||
|
||||
const (
|
||||
CertificateX509 CertificateKind = C.GIT_CERT_X509
|
||||
CertificateHostkey = C.GIT_CERT_HOSTKEY_LIBSSH2
|
||||
)
|
||||
|
||||
// Certificate represents the two possible certificates which libgit2
|
||||
// knows it might find. If Kind is CertficateX509 then the X509 field
|
||||
// will be filled. If Kind is CertificateHostkey then the Hostkey
|
||||
// field will be fille.d
|
||||
type Certificate struct {
|
||||
Kind CertificateKind
|
||||
X509 *x509.Certificate
|
||||
Hostkey HostkeyCertificate
|
||||
}
|
||||
|
||||
type HostkeyKind uint
|
||||
|
||||
const (
|
||||
HostkeyMD5 HostkeyKind = C.GIT_CERT_SSH_MD5
|
||||
HostkeySHA1 = C.GIT_CERT_SSH_SHA1
|
||||
)
|
||||
|
||||
// Server host key information. If Kind is HostkeyMD5 the MD5 field
|
||||
// will be filled. If Kind is HostkeySHA1, then HashSHA1 will be
|
||||
// filled.
|
||||
type HostkeyCertificate struct {
|
||||
Kind HostkeyKind
|
||||
HashMD5 [16]byte
|
||||
HashSHA1 [20]byte
|
||||
}
|
||||
|
||||
func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) {
|
||||
C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
|
||||
if callbacks == nil {
|
||||
|
@ -124,7 +158,7 @@ func updateTipsCallback(_refname *C.char, _a *C.git_oid, _b *C.git_oid, data uns
|
|||
}
|
||||
|
||||
//export certificateCheckCallback
|
||||
func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, data unsafe.Pointer) int {
|
||||
func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, data unsafe.Pointer) int {
|
||||
callbacks := (*RemoteCallbacks)(data)
|
||||
if callbacks.CertificateCheckCallback == nil {
|
||||
return 0
|
||||
|
@ -132,21 +166,32 @@ func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, d
|
|||
host := C.GoString(_host)
|
||||
valid := _valid != 0
|
||||
|
||||
var cert Certificate
|
||||
if _cert.cert_type == C.GIT_CERT_X509 {
|
||||
cert.Kind = CertificateX509
|
||||
ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert))
|
||||
x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len)))
|
||||
if err != nil {
|
||||
return C.GIT_EUSER;
|
||||
return C.GIT_EUSER
|
||||
}
|
||||
|
||||
// we assume there's only one, which should hold true for any web server we want to talk to
|
||||
return callbacks.CertificateCheckCallback(x509_certs[0], valid, host)
|
||||
cert.X509 = x509_certs[0]
|
||||
} else if _cert.cert_type == C.GIT_CERT_HOSTKEY_LIBSSH2 {
|
||||
cert.Kind = CertificateHostkey
|
||||
ccert := (*C.git_cert_hostkey)(unsafe.Pointer(_cert))
|
||||
cert.Hostkey.Kind = HostkeyKind(ccert._type)
|
||||
C.memcpy(unsafe.Pointer(&cert.Hostkey.HashMD5[0]), unsafe.Pointer(&ccert.hash_md5[0]), C.size_t(len(cert.Hostkey.HashMD5)))
|
||||
C.memcpy(unsafe.Pointer(&cert.Hostkey.HashSHA1[0]), unsafe.Pointer(&ccert.hash_sha1[0]), C.size_t(len(cert.Hostkey.HashSHA1)))
|
||||
} else {
|
||||
cstr := C.CString("Unsupported certificate type")
|
||||
C.giterr_set_str(C.GITERR_NET, cstr)
|
||||
C.free(unsafe.Pointer(cstr))
|
||||
return -1 // we don't support anything else atm
|
||||
}
|
||||
|
||||
cstr := C.CString("Unsupported certificate type")
|
||||
C.giterr_set_str(C.GITERR_NET, cstr)
|
||||
C.free(unsafe.Pointer(cstr))
|
||||
return ErrUser // we don't support anything else atm
|
||||
|
||||
return callbacks.CertificateCheckCallback(&cert, valid, host)
|
||||
}
|
||||
|
||||
func RemoteIsValidName(name string) bool {
|
||||
|
@ -462,11 +507,11 @@ func (o *Remote) RefspecCount() uint {
|
|||
}
|
||||
|
||||
func (o *Remote) SetUpdateFetchHead(val bool) {
|
||||
C.git_remote_set_update_fetchhead(o.ptr, cbool(val))
|
||||
C.git_remote_set_update_fetchhead(o.ptr, cbool(val))
|
||||
}
|
||||
|
||||
func (o *Remote) UpdateFetchHead() bool {
|
||||
return C.git_remote_update_fetchhead(o.ptr) > 0
|
||||
return C.git_remote_update_fetchhead(o.ptr) > 0
|
||||
}
|
||||
|
||||
// Fetch performs a fetch operation. refspecs specifies which refspecs
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
@ -49,8 +47,7 @@ func TestListRemotes(t *testing.T) {
|
|||
}
|
||||
|
||||
|
||||
func assertHostname(cert *x509.Certificate, valid bool, hostname string, t *testing.T) int {
|
||||
fmt.Println("hostname", hostname)
|
||||
func assertHostname(cert *Certificate, valid bool, hostname string, t *testing.T) int {
|
||||
if hostname != "github.com" {
|
||||
t.Fatal("Hostname does not match")
|
||||
return ErrUser
|
||||
|
@ -68,7 +65,7 @@ func TestCertificateCheck(t *testing.T) {
|
|||
checkFatal(t, err)
|
||||
|
||||
callbacks := RemoteCallbacks{
|
||||
CertificateCheckCallback: func (cert *x509.Certificate, valid bool, hostname string) int {
|
||||
CertificateCheckCallback: func (cert *Certificate, valid bool, hostname string) int {
|
||||
return assertHostname(cert, valid, hostname, t)
|
||||
},
|
||||
}
|
||||
|
@ -77,5 +74,4 @@ func TestCertificateCheck(t *testing.T) {
|
|||
checkFatal(t, err)
|
||||
err = remote.Fetch([]string{}, nil, "")
|
||||
checkFatal(t, err)
|
||||
fmt.Println("after Fetch()")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue