feature: Adds signing validation support to the client.
This commit is contained in:
parent
86ad3e174f
commit
00a57443d4
6 changed files with 242 additions and 80 deletions
251
client/client.go
251
client/client.go
|
@ -6,11 +6,34 @@ import (
|
|||
"strings"
|
||||
|
||||
core "git.greysoh.dev/imterah/bismuthd/commons"
|
||||
"git.greysoh.dev/imterah/bismuthd/signingclient"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
|
||||
"github.com/ProtonMail/gopenpgp/v3/crypto"
|
||||
)
|
||||
|
||||
func computeNodes(children []*BismuthSignResultData) (int, int) {
|
||||
totalServerCount := 0
|
||||
passedServerCount := 0
|
||||
|
||||
for _, child := range children {
|
||||
totalServerCount += 1
|
||||
|
||||
if child.IsTrusting {
|
||||
passedServerCount += 1
|
||||
}
|
||||
|
||||
if len(child.ChildNodes) != 0 {
|
||||
recievedTotalCount, recievedPassedCount := computeNodes(child.ChildNodes)
|
||||
|
||||
totalServerCount += recievedTotalCount
|
||||
passedServerCount += recievedPassedCount
|
||||
}
|
||||
}
|
||||
|
||||
return totalServerCount, passedServerCount
|
||||
}
|
||||
|
||||
// Initializes the client. Should be done automatically if you call New()
|
||||
//
|
||||
// If you don't call client.New(), you *MUST* call this function before running bismuth.Conn().
|
||||
|
@ -20,7 +43,7 @@ func (bismuth *BismuthClient) InitializeClient() error {
|
|||
}
|
||||
|
||||
if bismuth.CertificateSignChecker == nil {
|
||||
bismuth.CertificateSignChecker = func(host, certificateFingerprint string, isSelfSigned, isTrustworthy bool) bool {
|
||||
bismuth.CertificateSignChecker = func(host, certificateFingerprint string, isSelfSigned bool) bool {
|
||||
fmt.Println("WARNING: Using stub CertificateSignChecker. Returing true and ignoring arguments")
|
||||
return true
|
||||
}
|
||||
|
@ -40,9 +63,46 @@ func (bismuth *BismuthClient) InitializeClient() error {
|
|||
}
|
||||
}
|
||||
|
||||
bismuth.CheckIfCertificatesAreSigned = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bismuth *BismuthClient) checkIfDomainIsTrusted(servers, advertisedDomains []string) ([]*BismuthSignResultData, error) {
|
||||
signResultData := make([]*BismuthSignResultData, len(servers))
|
||||
|
||||
for index, server := range servers {
|
||||
baseConn, err := bismuth.ConnectToServer(server)
|
||||
|
||||
if err != nil {
|
||||
return signResultData, err
|
||||
}
|
||||
|
||||
defer baseConn.Close()
|
||||
|
||||
conn, signResultsForConn, err := bismuth.Conn(baseConn)
|
||||
|
||||
if err != nil {
|
||||
return signResultData, err
|
||||
}
|
||||
|
||||
isTrusted, err := signingclient.IsDomainTrusted(conn, signResultsForConn.ServerPublicKey.GetFingerprintBytes(), advertisedDomains)
|
||||
|
||||
if signResultsForConn.OverallTrustScore < 50 {
|
||||
isTrusted = false
|
||||
}
|
||||
|
||||
signResultData[index] = &BismuthSignResultData{
|
||||
IsTrusting: isTrusted,
|
||||
ChildNodes: []*BismuthSignResultData{
|
||||
signResultsForConn.Node,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return signResultData, nil
|
||||
}
|
||||
|
||||
// Connects to a Bismuth server. This wraps an existing net.Conn interface.
|
||||
// The returned net.Conn is the server, but over bismuth.
|
||||
func (bismuth *BismuthClient) Conn(conn net.Conn) (net.Conn, *BismuthSignResults, error) {
|
||||
|
@ -158,6 +218,139 @@ func (bismuth *BismuthClient) Conn(conn net.Conn) (net.Conn, *BismuthSignResults
|
|||
symmKey := symmKeyInfo[1 : chacha20poly1305.KeySize+1]
|
||||
aead, err := chacha20poly1305.NewX(symmKey)
|
||||
|
||||
// Request trusted domains
|
||||
|
||||
trustedDomainsRequest := make([]byte, 1)
|
||||
trustedDomainsRequest[0] = core.GetTrustedDomains
|
||||
|
||||
encryptedTrustedDomainRequest, err := bismuth.encryptMessage(aead, trustedDomainsRequest)
|
||||
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
trustedDomainLength := make([]byte, 3)
|
||||
core.Int32ToInt24(trustedDomainLength, uint32(len(encryptedTrustedDomainRequest)))
|
||||
|
||||
conn.Write(trustedDomainLength)
|
||||
conn.Write(encryptedTrustedDomainRequest)
|
||||
|
||||
if _, err = conn.Read(trustedDomainLength); err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
encryptedTrustedDomainResponse := make([]byte, core.Int24ToInt32(trustedDomainLength))
|
||||
|
||||
if _, err = conn.Read(encryptedTrustedDomainResponse); err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
trustedDomainResponse, err := bismuth.decryptMessage(aead, encryptedTrustedDomainResponse)
|
||||
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if trustedDomainResponse[0] != core.GetTrustedDomains {
|
||||
conn.Close()
|
||||
return nil, nil, fmt.Errorf("server failed to return its signing servers")
|
||||
}
|
||||
|
||||
trustedDomains := strings.Split(string(trustedDomainResponse[1:]), "\n")
|
||||
|
||||
// Request signing servers
|
||||
|
||||
signingServerRequest := make([]byte, 1)
|
||||
signingServerRequest[0] = core.GetSigningServers
|
||||
|
||||
encryptedSigningServerRequest, err := bismuth.encryptMessage(aead, signingServerRequest)
|
||||
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
signingRequestLength := make([]byte, 3)
|
||||
core.Int32ToInt24(signingRequestLength, uint32(len(encryptedSigningServerRequest)))
|
||||
|
||||
conn.Write(signingRequestLength)
|
||||
conn.Write(encryptedSigningServerRequest)
|
||||
|
||||
if _, err = conn.Read(signingRequestLength); err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
encryptedSigningRequestResponse := make([]byte, core.Int24ToInt32(signingRequestLength))
|
||||
|
||||
if _, err = conn.Read(encryptedSigningRequestResponse); err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
signingServerResponse, err := bismuth.decryptMessage(aead, encryptedSigningRequestResponse)
|
||||
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if signingServerResponse[0] != core.GetSigningServers {
|
||||
conn.Close()
|
||||
return nil, nil, fmt.Errorf("server failed to return its signing servers")
|
||||
}
|
||||
|
||||
// Check if the server is signed
|
||||
|
||||
signingServers := strings.Split(string(signingServerResponse[1:]), "\n")
|
||||
isServerSelfSigned := len(signingServers)-1 == 0 || len(trustedDomains)-1 == 0
|
||||
|
||||
rootNode := &BismuthSignResultData{
|
||||
ChildNodes: []*BismuthSignResultData{},
|
||||
IsTrusting: false,
|
||||
}
|
||||
|
||||
signResults := BismuthSignResults{
|
||||
OverallTrustScore: 0,
|
||||
ServerPublicKey: serverPublicKey,
|
||||
Node: rootNode,
|
||||
}
|
||||
|
||||
totalServerCount, passedServerCount := 0, 0
|
||||
|
||||
if bismuth.CheckIfCertificatesAreSigned {
|
||||
serverKeyFingerprint := serverPublicKey.GetFingerprint()
|
||||
isCertSigned := bismuth.CertificateSignChecker(host, serverKeyFingerprint, isServerSelfSigned)
|
||||
|
||||
if !isServerSelfSigned || !isCertSigned {
|
||||
domainTrustResults, err := bismuth.checkIfDomainIsTrusted(signingServers, trustedDomains)
|
||||
|
||||
if err == nil {
|
||||
rootNode.ChildNodes = domainTrustResults
|
||||
} else {
|
||||
fmt.Printf("ERROR: failed to verify servers (%s).\n", err.Error())
|
||||
signResults.OverallTrustScore = 0
|
||||
}
|
||||
|
||||
totalServerCount, passedServerCount = computeNodes(rootNode.ChildNodes)
|
||||
} else if isCertSigned {
|
||||
rootNode.IsTrusting = isCertSigned
|
||||
|
||||
totalServerCount, passedServerCount = 1, 1
|
||||
rootNode.IsTrusting = true
|
||||
}
|
||||
} else {
|
||||
totalServerCount, passedServerCount = 1, 1
|
||||
}
|
||||
|
||||
if totalServerCount != 0 {
|
||||
signResults.OverallTrustScore = int((float32(passedServerCount) / float32(totalServerCount)) * 100)
|
||||
}
|
||||
|
||||
// After that, we send what host we are connecting to (enables fronting/proxy services)
|
||||
|
||||
hostInformation := make([]byte, 1+len(host))
|
||||
|
@ -179,62 +372,6 @@ func (bismuth *BismuthClient) Conn(conn net.Conn) (net.Conn, *BismuthSignResults
|
|||
conn.Write(hostInformationSize)
|
||||
conn.Write(encryptedHostInformationPacket)
|
||||
|
||||
// Request trusted proxies
|
||||
|
||||
trustedProxyRequest := make([]byte, 1)
|
||||
trustedProxyRequest[0] = core.GetSigningServers
|
||||
|
||||
encryptedTrustedProxyRequest, err := bismuth.encryptMessage(aead, trustedProxyRequest)
|
||||
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
trustedProxyLength := make([]byte, 3)
|
||||
core.Int32ToInt24(trustedProxyLength, uint32(len(encryptedTrustedProxyRequest)))
|
||||
|
||||
conn.Write(trustedProxyLength)
|
||||
conn.Write(encryptedTrustedProxyRequest)
|
||||
|
||||
if _, err = conn.Read(trustedProxyLength); err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
encryptedTrustedProxyResponse := make([]byte, core.Int24ToInt32(trustedProxyLength))
|
||||
|
||||
if _, err = conn.Read(encryptedTrustedProxyResponse); err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
trustedProxyResponse, err := bismuth.decryptMessage(aead, encryptedTrustedProxyResponse)
|
||||
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if trustedProxyResponse[0] != core.GetSigningServers {
|
||||
conn.Close()
|
||||
return nil, nil, fmt.Errorf("server failed to return its signing servers")
|
||||
}
|
||||
|
||||
signingServers := strings.Split(string(trustedProxyResponse[1:]), "\n")
|
||||
isServerSelfSigned := len(trustedProxyResponse)-1 == 0
|
||||
|
||||
if !isServerSelfSigned {
|
||||
fmt.Printf("acquired signing servers: '%s'\n", strings.Join(signingServers, ", "))
|
||||
} else {
|
||||
fmt.Println("server is self signed, not printing (non-existent) signing servers")
|
||||
}
|
||||
|
||||
signResults := BismuthSignResults{
|
||||
OverallTrustScore: 100,
|
||||
ServerPublicKey: serverPublicKey,
|
||||
}
|
||||
|
||||
// Start proxying
|
||||
|
||||
startForwardingPacket := []byte{
|
||||
|
|
|
@ -27,13 +27,12 @@ type BismuthClient struct {
|
|||
// - `certificateFingerprint`: A fingerprint of the servers key.
|
||||
// - `isSelfSigned`: If true, the certificate is either actually self-signed, or
|
||||
// verification is dsabled (CheckIfCertificatesAreSigned in BismuthClient is false)
|
||||
// - `isTrustworthy`: If true, the certificate is signed by 51% or more of peers.
|
||||
//
|
||||
// This function will only be called if client.CheckIfCertificatesAreSigned is true.
|
||||
//
|
||||
// Example usage inside the Bismuth client source:
|
||||
// client.CertificateSignChecker("example.com:9090", "6c5eaff6f5c65e65e6f6ce6fc", false, true)
|
||||
CertificateSignChecker func(host, certificateFingerprint string, isSelfSigned, isTrustworthy bool) bool
|
||||
CertificateSignChecker func(host, certificateFingerprint string, isSelfSigned bool) bool
|
||||
|
||||
// If any certificates are false in the certificate cache, and the client has determined that
|
||||
// they may need to be added, this function will get called.
|
||||
|
@ -49,7 +48,8 @@ type BismuthClient struct {
|
|||
// Connects to a server.
|
||||
// This function will only be called if client.CheckIfCertificatesAreSigned is true.
|
||||
//
|
||||
// client.ConnectToServer("google.com:80")
|
||||
// Example usage in the client source:
|
||||
// client.ConnectToServer("google.com:80")
|
||||
ConnectToServer func(address string) (net.Conn, error)
|
||||
|
||||
// GopenPGP instance
|
||||
|
@ -62,9 +62,7 @@ type BismuthSignResultData struct {
|
|||
ChildNodes []*BismuthSignResultData
|
||||
|
||||
// If true, the server is already trusting this node
|
||||
IsTrustingAlready bool
|
||||
// If true, server is trusting the previous server
|
||||
IsTrustingRootServer bool
|
||||
IsTrusting bool
|
||||
}
|
||||
|
||||
type BismuthSignResults struct {
|
||||
|
@ -79,13 +77,17 @@ type BismuthSignResults struct {
|
|||
|
||||
type BismuthCertificates struct {
|
||||
// The host of the server
|
||||
host string
|
||||
Host string
|
||||
// A fingerprint of the servers key
|
||||
certificateFingerprint string
|
||||
CertificateFingerprint string
|
||||
// Certificate UserID
|
||||
certificateUsername string
|
||||
certificateMail string
|
||||
CertificateUsername string
|
||||
CertificateMail string
|
||||
|
||||
// If true, the certificate is self signed
|
||||
isSelfSigned bool
|
||||
IsSelfSigned bool
|
||||
|
||||
// If true, the client should not prompt the user, and automatically
|
||||
// add the certificate instead.
|
||||
ShouldAutomaticallyAdd bool
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue