3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-22 20:09:41 +01:00
This commit is contained in:
Shivaram Lingamneni 2020-09-23 02:23:35 -04:00
parent e7eea14b9d
commit 1a9f501383
7 changed files with 32 additions and 15 deletions

View File

@ -5,6 +5,7 @@ package irc
import ( import (
"bytes" "bytes"
"crypto/x509"
"encoding/json" "encoding/json"
"fmt" "fmt"
"sort" "sort"
@ -1466,7 +1467,7 @@ func (am *AccountManager) ChannelsForAccount(account string) (channels []string)
return unmarshalRegisteredChannels(channelStr) return unmarshalRegisteredChannels(channelStr)
} }
func (am *AccountManager) AuthenticateByCertFP(client *Client, certfp, authzid string) (err error) { func (am *AccountManager) AuthenticateByCertificate(client *Client, certfp string, peerCerts []*x509.Certificate, authzid string) (err error) {
if certfp == "" { if certfp == "" {
return errAccountInvalidCredentials return errAccountInvalidCredentials
} }
@ -1495,7 +1496,7 @@ func (am *AccountManager) AuthenticateByCertFP(client *Client, certfp, authzid s
if config.Accounts.AuthScript.Enabled { if config.Accounts.AuthScript.Enabled {
var output AuthScriptOutput var output AuthScriptOutput
output, err = CheckAuthScript(am.server.semaphores.AuthScript, config.Accounts.AuthScript.ScriptConfig, output, err = CheckAuthScript(am.server.semaphores.AuthScript, config.Accounts.AuthScript.ScriptConfig,
AuthScriptInput{Certfp: certfp, IP: client.IP().String()}) AuthScriptInput{Certfp: certfp, IP: client.IP().String(), peerCerts: peerCerts})
if err != nil { if err != nil {
am.server.logger.Error("internal", "failed shell auth invocation", err.Error()) am.server.logger.Error("internal", "failed shell auth invocation", err.Error())
} else if output.Success && output.AccountName != "" { } else if output.Success && output.AccountName != "" {

View File

@ -4,7 +4,9 @@
package irc package irc
import ( import (
"crypto/x509"
"encoding/json" "encoding/json"
"encoding/pem"
"fmt" "fmt"
"net" "net"
@ -13,9 +15,11 @@ import (
// JSON-serializable input and output types for the script // JSON-serializable input and output types for the script
type AuthScriptInput struct { type AuthScriptInput struct {
AccountName string `json:"accountName,omitempty"` AccountName string `json:"accountName,omitempty"`
Passphrase string `json:"passphrase,omitempty"` Passphrase string `json:"passphrase,omitempty"`
Certfp string `json:"certfp,omitempty"` Certfp string `json:"certfp,omitempty"`
PeerCerts []string `json:"peerCerts,omitempty"`
peerCerts []*x509.Certificate
IP string `json:"ip,omitempty"` IP string `json:"ip,omitempty"`
} }
@ -31,6 +35,14 @@ func CheckAuthScript(sem utils.Semaphore, config ScriptConfig, input AuthScriptI
defer sem.Release() defer sem.Release()
} }
// PEM-encode the peer certificates before applying JSON
if len(input.peerCerts) != 0 {
input.PeerCerts = make([]string, len(input.peerCerts))
for i, cert := range input.peerCerts {
input.PeerCerts[i] = string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}))
}
}
inputBytes, err := json.Marshal(input) inputBytes, err := json.Marshal(input)
if err != nil { if err != nil {
return return

View File

@ -6,6 +6,7 @@
package irc package irc
import ( import (
"crypto/x509"
"fmt" "fmt"
"net" "net"
"runtime/debug" "runtime/debug"
@ -163,6 +164,7 @@ type Session struct {
destroyed uint32 destroyed uint32
certfp string certfp string
peerCerts []*x509.Certificate
sasl saslStatus sasl saslStatus
passStatus serverPassStatus passStatus serverPassStatus
@ -384,7 +386,7 @@ func (server *Server) RunClient(conn IRCConn) {
if wConn.Config.TLSConfig != nil { if wConn.Config.TLSConfig != nil {
// error is not useful to us here anyways so we can ignore it // error is not useful to us here anyways so we can ignore it
session.certfp, _ = utils.GetCertFP(wConn.Conn, RegisterTimeout) session.certfp, session.peerCerts, _ = utils.GetCertFP(wConn.Conn, RegisterTimeout)
} }
if session.isTor { if session.isTor {

View File

@ -99,6 +99,7 @@ func (client *Client) ApplyProxiedIP(session *Session, proxiedIP net.IP, tls boo
// nickmask will be updated when the client completes registration // nickmask will be updated when the client completes registration
// set tls info // set tls info
session.certfp = "" session.certfp = ""
session.peerCerts = nil
client.SetMode(modes.TLS, tls) client.SetMode(modes.TLS, tls)
return nil, "" return nil, ""

View File

@ -303,7 +303,7 @@ func authExternalHandler(server *Server, client *Client, mechanism string, value
rb.session.deviceID = deviceID rb.session.deviceID = deviceID
} }
} }
err = server.accounts.AuthenticateByCertFP(client, rb.session.certfp, authzid) err = server.accounts.AuthenticateByCertificate(client, rb.session.certfp, rb.session.peerCerts, authzid)
} }
if err != nil { if err != nil {

View File

@ -721,7 +721,7 @@ func nsIdentifyHandler(server *Server, client *Client, command string, params []
// try certfp // try certfp
if !loginSuccessful && rb.session.certfp != "" { if !loginSuccessful && rb.session.certfp != "" {
err = server.accounts.AuthenticateByCertFP(client, rb.session.certfp, "") err = server.accounts.AuthenticateByCertificate(client, rb.session.certfp, rb.session.peerCerts, "")
loginSuccessful = (err == nil) loginSuccessful = (err == nil)
} }

View File

@ -8,6 +8,7 @@ import (
"crypto/sha256" "crypto/sha256"
"crypto/subtle" "crypto/subtle"
"crypto/tls" "crypto/tls"
"crypto/x509"
"encoding/base32" "encoding/base32"
"encoding/base64" "encoding/base64"
"encoding/hex" "encoding/hex"
@ -92,10 +93,10 @@ func NormalizeCertfp(certfp string) (result string, err error) {
return return
} }
func GetCertFP(conn net.Conn, handshakeTimeout time.Duration) (result string, err error) { func GetCertFP(conn net.Conn, handshakeTimeout time.Duration) (fingerprint string, peerCerts []*x509.Certificate, err error) {
tlsConn, isTLS := conn.(*tls.Conn) tlsConn, isTLS := conn.(*tls.Conn)
if !isTLS { if !isTLS {
return "", ErrNotTLS return "", nil, ErrNotTLS
} }
// ensure handshake is performed // ensure handshake is performed
@ -104,16 +105,16 @@ func GetCertFP(conn net.Conn, handshakeTimeout time.Duration) (result string, er
tlsConn.SetDeadline(time.Time{}) tlsConn.SetDeadline(time.Time{})
if err != nil { if err != nil {
return "", err return "", nil, err
} }
peerCerts := tlsConn.ConnectionState().PeerCertificates peerCerts = tlsConn.ConnectionState().PeerCertificates
if len(peerCerts) < 1 { if len(peerCerts) < 1 {
return "", ErrNoPeerCerts return "", nil, ErrNoPeerCerts
} }
rawCert := sha256.Sum256(peerCerts[0].Raw) rawCert := sha256.Sum256(peerCerts[0].Raw)
fingerprint := hex.EncodeToString(rawCert[:]) fingerprint = hex.EncodeToString(rawCert[:])
return fingerprint, nil return fingerprint, peerCerts, nil
} }