mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-28 23:19:30 +01:00
commit
815852191c
@ -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 != "" {
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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, ""
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user