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
57
remote.go
57
remote.go
|
@ -2,6 +2,7 @@ package git
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
extern void _go_git_setup_callbacks(git_remote_callbacks *callbacks);
|
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 CredentialsCallback func(url string, username_from_url string, allowed_types CredType) (int, *Cred)
|
||||||
type TransferProgressCallback func(stats TransferProgress) int
|
type TransferProgressCallback func(stats TransferProgress) int
|
||||||
type UpdateTipsCallback func(refname string, a *Oid, b *Oid) 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 {
|
type RemoteCallbacks struct {
|
||||||
SidebandProgressCallback TransportMessageCallback
|
SidebandProgressCallback TransportMessageCallback
|
||||||
|
@ -61,6 +62,39 @@ type Remote struct {
|
||||||
callbacks RemoteCallbacks
|
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) {
|
func populateRemoteCallbacks(ptr *C.git_remote_callbacks, callbacks *RemoteCallbacks) {
|
||||||
C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
|
C.git_remote_init_callbacks(ptr, C.GIT_REMOTE_CALLBACKS_VERSION)
|
||||||
if callbacks == nil {
|
if callbacks == nil {
|
||||||
|
@ -132,21 +166,32 @@ func certificateCheckCallback(_cert *C.git_cert, _valid C.int, _host *C.char, d
|
||||||
host := C.GoString(_host)
|
host := C.GoString(_host)
|
||||||
valid := _valid != 0
|
valid := _valid != 0
|
||||||
|
|
||||||
|
var cert Certificate
|
||||||
if _cert.cert_type == C.GIT_CERT_X509 {
|
if _cert.cert_type == C.GIT_CERT_X509 {
|
||||||
|
cert.Kind = CertificateX509
|
||||||
ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert))
|
ccert := (*C.git_cert_x509)(unsafe.Pointer(_cert))
|
||||||
x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len)))
|
x509_certs, err := x509.ParseCertificates(C.GoBytes(ccert.data, C.int(ccert.len)))
|
||||||
if err != nil {
|
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
|
// 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")
|
cstr := C.CString("Unsupported certificate type")
|
||||||
C.giterr_set_str(C.GITERR_NET, cstr)
|
C.giterr_set_str(C.GITERR_NET, cstr)
|
||||||
C.free(unsafe.Pointer(cstr))
|
C.free(unsafe.Pointer(cstr))
|
||||||
return ErrUser // we don't support anything else atm
|
return -1 // we don't support anything else atm
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return callbacks.CertificateCheckCallback(&cert, valid, host)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoteIsValidName(name string) bool {
|
func RemoteIsValidName(name string) bool {
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"crypto/x509"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -49,8 +47,7 @@ func TestListRemotes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func assertHostname(cert *x509.Certificate, valid bool, hostname string, t *testing.T) int {
|
func assertHostname(cert *Certificate, valid bool, hostname string, t *testing.T) int {
|
||||||
fmt.Println("hostname", hostname)
|
|
||||||
if hostname != "github.com" {
|
if hostname != "github.com" {
|
||||||
t.Fatal("Hostname does not match")
|
t.Fatal("Hostname does not match")
|
||||||
return ErrUser
|
return ErrUser
|
||||||
|
@ -68,7 +65,7 @@ func TestCertificateCheck(t *testing.T) {
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
|
|
||||||
callbacks := RemoteCallbacks{
|
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)
|
return assertHostname(cert, valid, hostname, t)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -77,5 +74,4 @@ func TestCertificateCheck(t *testing.T) {
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
err = remote.Fetch([]string{}, nil, "")
|
err = remote.Fetch([]string{}, nil, "")
|
||||||
checkFatal(t, err)
|
checkFatal(t, err)
|
||||||
fmt.Println("after Fetch()")
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue