3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-22 10:42:52 +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 (
"bytes"
"crypto/x509"
"encoding/json"
"fmt"
"sort"
@ -1466,7 +1467,7 @@ func (am *AccountManager) ChannelsForAccount(account string) (channels []string)
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 == "" {
return errAccountInvalidCredentials
}
@ -1495,7 +1496,7 @@ func (am *AccountManager) AuthenticateByCertFP(client *Client, certfp, authzid s
if config.Accounts.AuthScript.Enabled {
var output AuthScriptOutput
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 {
am.server.logger.Error("internal", "failed shell auth invocation", err.Error())
} else if output.Success && output.AccountName != "" {

View File

@ -4,7 +4,9 @@
package irc
import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"net"
@ -13,9 +15,11 @@ import (
// JSON-serializable input and output types for the script
type AuthScriptInput struct {
AccountName string `json:"accountName,omitempty"`
Passphrase string `json:"passphrase,omitempty"`
Certfp string `json:"certfp,omitempty"`
AccountName string `json:"accountName,omitempty"`
Passphrase string `json:"passphrase,omitempty"`
Certfp string `json:"certfp,omitempty"`
PeerCerts []string `json:"peerCerts,omitempty"`
peerCerts []*x509.Certificate
IP string `json:"ip,omitempty"`
}
@ -31,6 +35,14 @@ func CheckAuthScript(sem utils.Semaphore, config ScriptConfig, input AuthScriptI
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)
if err != nil {
return

View File

@ -6,6 +6,7 @@
package irc
import (
"crypto/x509"
"fmt"
"net"
"runtime/debug"
@ -163,6 +164,7 @@ type Session struct {
destroyed uint32
certfp string
peerCerts []*x509.Certificate
sasl saslStatus
passStatus serverPassStatus
@ -384,7 +386,7 @@ func (server *Server) RunClient(conn IRCConn) {
if wConn.Config.TLSConfig != nil {
// 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 {

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
// set tls info
session.certfp = ""
session.peerCerts = nil
client.SetMode(modes.TLS, tls)
return nil, ""

View File

@ -303,7 +303,7 @@ func authExternalHandler(server *Server, client *Client, mechanism string, value
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 {

View File

@ -721,7 +721,7 @@ func nsIdentifyHandler(server *Server, client *Client, command string, params []
// try 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)
}

View File

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