forked from External/grumble
Enforce certhash-based bans and add strong certificate checking (non-working for now, crypto/tls doesn't verify client certificates)
This commit is contained in:
parent
0b1794f9b5
commit
1240fe3eb6
3 changed files with 55 additions and 20 deletions
10
client.go
10
client.go
|
|
@ -7,6 +7,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/tls"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"goprotobuf.googlecode.com/hg/proto"
|
"goprotobuf.googlecode.com/hg/proto"
|
||||||
"grumble/blobstore"
|
"grumble/blobstore"
|
||||||
|
|
@ -125,6 +126,15 @@ func (client *Client) ShownName() string {
|
||||||
return client.Username
|
return client.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether the client's certificate is
|
||||||
|
// verified.
|
||||||
|
func (client *Client) IsVerified() bool {
|
||||||
|
tlsconn := client.conn.(*tls.Conn)
|
||||||
|
state := tlsconn.ConnectionState()
|
||||||
|
client.Printf("%v", state.VerifiedChains)
|
||||||
|
return len(state.VerifiedChains) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// Log a panic and disconnect the client.
|
// Log a panic and disconnect the client.
|
||||||
func (client *Client) Panic(v ...interface{}) {
|
func (client *Client) Panic(v ...interface{}) {
|
||||||
client.Print(v)
|
client.Print(v)
|
||||||
|
|
|
||||||
|
|
@ -1327,7 +1327,7 @@ func (server *Server) handleUserStatsMessage(client *Client, msg *Message) {
|
||||||
for i := len(state.PeerCertificates) - 1; i >= 0; i-- {
|
for i := len(state.PeerCertificates) - 1; i >= 0; i-- {
|
||||||
stats.Certificates = append(stats.Certificates, state.PeerCertificates[i].Raw)
|
stats.Certificates = append(stats.Certificates, state.PeerCertificates[i].Raw)
|
||||||
}
|
}
|
||||||
// fixme(mkrautz): strong certificate checking
|
stats.StrongCertificate = proto.Bool(target.IsVerified())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
63
server.go
63
server.go
|
|
@ -227,7 +227,7 @@ func (server *Server) CheckSuperUserPassword(password string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by the server to initiate a new client connection.
|
// Called by the server to initiate a new client connection.
|
||||||
func (server *Server) NewClient(conn net.Conn) (err error) {
|
func (server *Server) handleIncomingClient(conn net.Conn) (err error) {
|
||||||
client := new(Client)
|
client := new(Client)
|
||||||
addr := conn.RemoteAddr()
|
addr := conn.RemoteAddr()
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
|
|
@ -253,6 +253,30 @@ func (server *Server) NewClient(conn net.Conn) (err error) {
|
||||||
|
|
||||||
client.user = nil
|
client.user = nil
|
||||||
|
|
||||||
|
// Extract user's cert hash
|
||||||
|
tlsconn := client.conn.(*tls.Conn)
|
||||||
|
err = tlsconn.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
client.Printf("TLS handshake failed: %v", err)
|
||||||
|
client.Disconnect()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
state := tlsconn.ConnectionState()
|
||||||
|
if len(state.PeerCertificates) > 0 {
|
||||||
|
hash := sha1.New()
|
||||||
|
hash.Write(state.PeerCertificates[0].Raw)
|
||||||
|
sum := hash.Sum()
|
||||||
|
client.CertHash = hex.EncodeToString(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether the client's cert hash is banned
|
||||||
|
if server.IsCertHashBanned(client.CertHash) {
|
||||||
|
client.Printf("Certificate hash is banned")
|
||||||
|
client.Disconnect()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
go client.receiver()
|
go client.receiver()
|
||||||
go client.udpreceiver()
|
go client.udpreceiver()
|
||||||
|
|
||||||
|
|
@ -434,26 +458,13 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
||||||
|
|
||||||
client.Username = *auth.Username
|
client.Username = *auth.Username
|
||||||
|
|
||||||
// Extract certhash
|
|
||||||
tlsconn, ok := client.conn.(*tls.Conn)
|
|
||||||
if !ok {
|
|
||||||
client.Panic("Invalid connection")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
state := tlsconn.ConnectionState()
|
|
||||||
if len(state.PeerCertificates) > 0 {
|
|
||||||
hash := sha1.New()
|
|
||||||
hash.Write(state.PeerCertificates[0].Raw)
|
|
||||||
sum := hash.Sum()
|
|
||||||
client.CertHash = hex.EncodeToString(sum)
|
|
||||||
}
|
|
||||||
|
|
||||||
if client.Username == "SuperUser" {
|
if client.Username == "SuperUser" {
|
||||||
if auth.Password == nil {
|
if auth.Password == nil {
|
||||||
client.RejectAuth(mumbleproto.Reject_WrongUserPW, "")
|
client.RejectAuth(mumbleproto.Reject_WrongUserPW, "")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if server.CheckSuperUserPassword(*auth.Password) {
|
if server.CheckSuperUserPassword(*auth.Password) {
|
||||||
|
ok := false
|
||||||
client.user, ok = server.UserNameMap[client.Username]
|
client.user, ok = server.UserNameMap[client.Username]
|
||||||
if !ok {
|
if !ok {
|
||||||
client.RejectAuth(mumbleproto.Reject_InvalidUsername, "")
|
client.RejectAuth(mumbleproto.Reject_InvalidUsername, "")
|
||||||
|
|
@ -1155,7 +1166,7 @@ func (server *Server) RemoveExpiredBans() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the incoming connection conn banned?
|
// Is the incoming connection conn banned?
|
||||||
func (server *Server) IsBanned(conn net.Conn) bool {
|
func (server *Server) IsConnectionBanned(conn net.Conn) bool {
|
||||||
server.banlock.RLock()
|
server.banlock.RLock()
|
||||||
defer server.banlock.RUnlock()
|
defer server.banlock.RUnlock()
|
||||||
|
|
||||||
|
|
@ -1169,6 +1180,20 @@ func (server *Server) IsBanned(conn net.Conn) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the certificate hash banned?
|
||||||
|
func (server *Server) IsCertHashBanned(hash string) bool {
|
||||||
|
server.banlock.RLock()
|
||||||
|
defer server.banlock.RUnlock()
|
||||||
|
|
||||||
|
for _, ban := range server.Bans {
|
||||||
|
if ban.CertHash == hash && !ban.IsExpired() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Filter incoming text according to the server's current rules.
|
// Filter incoming text according to the server's current rules.
|
||||||
func (server *Server) FilterText(text string) (filtered string, err error) {
|
func (server *Server) FilterText(text string) (filtered string, err error) {
|
||||||
options := &htmlfilter.Options{
|
options := &htmlfilter.Options{
|
||||||
|
|
@ -1197,8 +1222,8 @@ func (server *Server) acceptLoop() {
|
||||||
// Remove expired bans
|
// Remove expired bans
|
||||||
server.RemoveExpiredBans()
|
server.RemoveExpiredBans()
|
||||||
|
|
||||||
// Is the client banned?
|
// Is the client IP-banned?
|
||||||
if server.IsBanned(conn) {
|
if server.IsConnectionBanned(conn) {
|
||||||
server.Printf("Rejected client %v: Banned", conn.RemoteAddr())
|
server.Printf("Rejected client %v: Banned", conn.RemoteAddr())
|
||||||
err := conn.Close()
|
err := conn.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1209,7 +1234,7 @@ func (server *Server) acceptLoop() {
|
||||||
|
|
||||||
// Create a new client connection from our *tls.Conn
|
// Create a new client connection from our *tls.Conn
|
||||||
// which wraps net.TCPConn.
|
// which wraps net.TCPConn.
|
||||||
err = server.NewClient(conn)
|
err = server.handleIncomingClient(conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.Printf("Unable to handle new client: %v", err)
|
server.Printf("Unable to handle new client: %v", err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue