mirror of
https://github.com/mumble-voip/grumble.git
synced 2025-12-19 21:59:59 -08:00
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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"goprotobuf.googlecode.com/hg/proto"
|
||||
"grumble/blobstore"
|
||||
|
|
@ -125,6 +126,15 @@ func (client *Client) ShownName() string {
|
|||
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.
|
||||
func (client *Client) Panic(v ...interface{}) {
|
||||
client.Print(v)
|
||||
|
|
|
|||
|
|
@ -1327,7 +1327,7 @@ func (server *Server) handleUserStatsMessage(client *Client, msg *Message) {
|
|||
for i := len(state.PeerCertificates) - 1; i >= 0; i-- {
|
||||
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.
|
||||
func (server *Server) NewClient(conn net.Conn) (err error) {
|
||||
func (server *Server) handleIncomingClient(conn net.Conn) (err error) {
|
||||
client := new(Client)
|
||||
addr := conn.RemoteAddr()
|
||||
if addr == nil {
|
||||
|
|
@ -253,6 +253,30 @@ func (server *Server) NewClient(conn net.Conn) (err error) {
|
|||
|
||||
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.udpreceiver()
|
||||
|
||||
|
|
@ -434,26 +458,13 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
|||
|
||||
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 auth.Password == nil {
|
||||
client.RejectAuth(mumbleproto.Reject_WrongUserPW, "")
|
||||
return
|
||||
} else {
|
||||
if server.CheckSuperUserPassword(*auth.Password) {
|
||||
ok := false
|
||||
client.user, ok = server.UserNameMap[client.Username]
|
||||
if !ok {
|
||||
client.RejectAuth(mumbleproto.Reject_InvalidUsername, "")
|
||||
|
|
@ -1155,7 +1166,7 @@ func (server *Server) RemoveExpiredBans() {
|
|||
}
|
||||
|
||||
// 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()
|
||||
defer server.banlock.RUnlock()
|
||||
|
||||
|
|
@ -1169,6 +1180,20 @@ func (server *Server) IsBanned(conn net.Conn) bool {
|
|||
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.
|
||||
func (server *Server) FilterText(text string) (filtered string, err error) {
|
||||
options := &htmlfilter.Options{
|
||||
|
|
@ -1197,8 +1222,8 @@ func (server *Server) acceptLoop() {
|
|||
// Remove expired bans
|
||||
server.RemoveExpiredBans()
|
||||
|
||||
// Is the client banned?
|
||||
if server.IsBanned(conn) {
|
||||
// Is the client IP-banned?
|
||||
if server.IsConnectionBanned(conn) {
|
||||
server.Printf("Rejected client %v: Banned", conn.RemoteAddr())
|
||||
err := conn.Close()
|
||||
if err != nil {
|
||||
|
|
@ -1209,7 +1234,7 @@ func (server *Server) acceptLoop() {
|
|||
|
||||
// Create a new client connection from our *tls.Conn
|
||||
// which wraps net.TCPConn.
|
||||
err = server.NewClient(conn)
|
||||
err = server.handleIncomingClient(conn)
|
||||
if err != nil {
|
||||
server.Printf("Unable to handle new client: %v", err)
|
||||
continue
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue