diff --git a/README.md b/README.md index 6eeccc4..b9129f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Bismuth Protocol +# Bismuth Protocol [![Go Reference](https://pkg.go.dev/badge/git.greysoh.dev/imterah/bismuthd.svg)](https://pkg.go.dev/git.greysoh.dev/imterah/bismuthd) The Bismuth protocol is a thin wrapper for any protocol that adds TLS-like features, without being TLS on its own. diff --git a/client/client.go b/client/client.go index 7f49ba6..bdb7cf6 100644 --- a/client/client.go +++ b/client/client.go @@ -1,67 +1,128 @@ package client import ( - "crypto/cipher" - "crypto/rand" "fmt" "net" + "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 (bismuth BismuthClient) encryptMessage(aead cipher.AEAD, msg []byte) ([]byte, error) { - nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(msg)+aead.Overhead()) +func computeNodes(children []*BismuthSignResultData) (int, int) { + totalServerCount := 0 + passedServerCount := 0 - if _, err := rand.Read(nonce); err != nil { - return []byte{}, err + 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 + } } - encryptedMsg := aead.Seal(nonce, nonce, msg, nil) - return encryptedMsg, nil + return totalServerCount, passedServerCount } -func (bismuth BismuthClient) decryptMessage(aead cipher.AEAD, encMsg []byte) ([]byte, error) { - if len(encMsg) < aead.NonceSize() { - return []byte{}, fmt.Errorf("ciphertext too short") +// 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(). +func (bismuth *BismuthClient) InitializeClient() error { + if bismuth.pgp == nil { + bismuth.pgp = crypto.PGP() } - // Split nonce and ciphertext. - nonce, ciphertext := encMsg[:aead.NonceSize()], encMsg[aead.NonceSize():] - - // Decrypt the message and check it wasn't tampered with. - decryptedData, err := aead.Open(nil, nonce, ciphertext, nil) - - if err != nil { - return []byte{}, err + if bismuth.CertificateSignChecker == nil { + bismuth.CertificateSignChecker = func(host, certificateFingerprint string, isSelfSigned bool) bool { + fmt.Println("WARNING: Using stub CertificateSignChecker. Returing true and ignoring arguments") + return true + } } - return decryptedData, nil + if bismuth.AddCertificatesToSignCache == nil { + bismuth.AddCertificatesToSignCache = func(certificates []*BismuthCertificates) { + // do nothing + } + } + + if bismuth.ConnectToServer == nil { + bismuth.CheckIfCertificatesAreSigned = true + + bismuth.ConnectToServer = func(address string) (net.Conn, error) { + return net.Dial("tcp", address) + } + } + + bismuth.CheckIfCertificatesAreSigned = true + + return nil } -// Bismuth Client -type BismuthClient struct { - // GOpenPGP public key - PublicKey *crypto.Key - // GOpenPGP private key - PrivateKey *crypto.Key +func (bismuth *BismuthClient) checkIfDomainIsTrusted(servers, advertisedDomains []string) ([]*BismuthSignResultData, error) { + signResultData := make([]*BismuthSignResultData, len(servers)) - pgp *crypto.PGPHandle + 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, error) { +func (bismuth *BismuthClient) Conn(conn net.Conn) (net.Conn, *BismuthSignResults, error) { // Yes, I'm aware defer exists. It won't work if I use it in this context. I'll shank anyone that complains // Exchange our public keys first + hostAndIP := conn.RemoteAddr().String() + hostAndIPColonIndex := strings.Index(hostAndIP, ":") + + if hostAndIPColonIndex == -1 { + return nil, nil, fmt.Errorf("failed to get colon in remote address") + } + + host := hostAndIP[:hostAndIPColonIndex] + ownKey, err := bismuth.PublicKey.GetPublicKey() if err != nil { conn.Close() - return nil, err + return nil, nil, err } pubKeyLengthBytes := make([]byte, 3) @@ -76,17 +137,17 @@ func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) { if _, err = conn.Read(messageMode); err != nil { conn.Close() - return nil, err + return nil, nil, err } if messageMode[0] != core.SendPublicKey { conn.Close() - return nil, fmt.Errorf("server failed to return its public key") + return nil, nil, fmt.Errorf("server failed to return its public key") } if _, err = conn.Read(pubKeyLengthBytes); err != nil { conn.Close() - return nil, err + return nil, nil, err } pubKeyLength = core.Int24ToInt32(pubKeyLengthBytes) @@ -94,12 +155,14 @@ func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) { if _, err = conn.Read(pubKeyBytes); err != nil { conn.Close() - return nil, err + return nil, nil, err } - if _, err = crypto.NewKey(pubKeyBytes); err != nil { + serverPublicKey, err := crypto.NewKey(pubKeyBytes) + + if err != nil { conn.Close() - return nil, err + return nil, nil, err } // Then exchange the symmetric key @@ -108,19 +171,19 @@ func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) { if _, err = conn.Read(messageMode); err != nil { conn.Close() - return nil, err + return nil, nil, err } if messageMode[0] != core.SwitchToSymmetricKey { conn.Close() - return nil, fmt.Errorf("server failed to return symmetric key") + return nil, nil, fmt.Errorf("server failed to return symmetric key") } encryptedSymmKeyLengthInBytes := make([]byte, 3) if _, err = conn.Read(encryptedSymmKeyLengthInBytes); err != nil { conn.Close() - return nil, err + return nil, nil, err } encryptedSymmKeyLength := core.Int24ToInt32(encryptedSymmKeyLengthInBytes) @@ -128,31 +191,186 @@ func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) { if _, err = conn.Read(encryptedSymmKey); err != nil { conn.Close() - return nil, err + return nil, nil, err } decHandleForSymmKey, err := bismuth.pgp.Decryption().DecryptionKey(bismuth.PrivateKey).New() if err != nil { - return nil, err + conn.Close() + return nil, nil, err } decryptedSymmKey, err := decHandleForSymmKey.Decrypt(encryptedSymmKey, crypto.Bytes) if err != nil { - return nil, err + conn.Close() + return nil, nil, err } symmKeyInfo := decryptedSymmKey.Bytes() if symmKeyInfo[0] != core.XChaCha20Poly1305 { conn.Close() - return nil, fmt.Errorf("unsupported encryption method recieved") + return nil, nil, fmt.Errorf("unsupported encryption method recieved") } 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 + totalServerCount, passedServerCount = computeNodes(rootNode.ChildNodes) + } else { + fmt.Printf("ERROR: failed to verify servers (%s).\n", err.Error()) + signResults.OverallTrustScore = 0 + } + } 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)) + + hostInformation[0] = core.ClientSendHost + copy(hostInformation[1:], []byte(host)) + + encryptedHostInformationPacket, err := bismuth.encryptMessage(aead, hostInformation) + + if err != nil { + conn.Close() + return nil, nil, err + } + + hostInformationSize := make([]byte, 3) + + core.Int32ToInt24(hostInformationSize, uint32(len(encryptedHostInformationPacket))) + + conn.Write(hostInformationSize) + conn.Write(encryptedHostInformationPacket) + // Start proxying startForwardingPacket := []byte{ @@ -163,7 +381,7 @@ func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) { if err != nil { conn.Close() - return nil, err + return nil, nil, err } encryptedForwardPacketPacketSize := make([]byte, 3) @@ -185,32 +403,5 @@ func (bismuth BismuthClient) Conn(conn net.Conn) (net.Conn, error) { return core.BismuthConnWrapped{ Bismuth: &bmConn, - }, nil -} - -// Creates a new BismuthClient. -// -// Both `pubKey` and `privKey` are armored PGP public and private keys respectively. -func New(pubKey string, privKey string) (*BismuthClient, error) { - publicKey, err := crypto.NewKeyFromArmored(pubKey) - - if err != nil { - return nil, err - } - - privateKey, err := crypto.NewKeyFromArmored(privKey) - - if err != nil { - return nil, err - } - - pgp := crypto.PGP() - - bismuth := BismuthClient{ - PublicKey: publicKey, - PrivateKey: privateKey, - pgp: pgp, - } - - return &bismuth, nil + }, &signResults, nil } diff --git a/client/typing.go b/client/typing.go new file mode 100644 index 0000000..873a94f --- /dev/null +++ b/client/typing.go @@ -0,0 +1,93 @@ +package client + +import ( + "net" + + "github.com/ProtonMail/gopenpgp/v3/crypto" +) + +// Bismuth Client +type BismuthClient struct { + // GOpenPGP public key for the client + PublicKey *crypto.Key + // GOpenPGP private key for the client + PrivateKey *crypto.Key + + // Check if the certificates are signed if enabled. + // + // If true, "cross-verifies" the server to make sure the certificates are signed. + // + // If false, all certificates will be reported as being self signed because we can't + // really prove otherwise. + CheckIfCertificatesAreSigned bool + + // Checks to see if a certificate is trusted in the client cache. + // + // - `host`: The host of the server. + // - `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) + // + // 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 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. + // + // All of the certificates that will be called by this function in arguments are ones that + // client.CertificateSignChecker has reported to be untrustworthy, but not all untrustworthy + // certificates will be reported, as they can be trusted by future nodes that you have already + // trusted. + // + // This function will only be called if client.CheckIfCertificatesAreSigned is true. + AddCertificatesToSignCache func(certificates []*BismuthCertificates) + + // Connects to a server. + // This function will only be called if client.CheckIfCertificatesAreSigned is true. + // + // Example usage in the client source: + // client.ConnectToServer("google.com:80") + ConnectToServer func(address string) (net.Conn, error) + + // GopenPGP instance + pgp *crypto.PGPHandle +} + +// Sign result data for the node +type BismuthSignResultData struct { + // Future node pointers in the tree + ChildNodes []*BismuthSignResultData + + // If true, the server is already trusting this node + IsTrusting bool +} + +type BismuthSignResults struct { + // Overall trust score calculated + OverallTrustScore int + // Parent node in tree for sign results + Node *BismuthSignResultData + + // GopenPGP public key + ServerPublicKey *crypto.Key +} + +type BismuthCertificates struct { + // The host of the server + Host string + // A fingerprint of the servers key + CertificateFingerprint string + // Certificate UserID + CertificateUsername string + CertificateMail string + + // If true, the certificate is self signed + IsSelfSigned bool + + // If true, the client should not prompt the user, and automatically + // add the certificate instead. + ShouldAutomaticallyAdd bool +} diff --git a/client/utils.go b/client/utils.go new file mode 100644 index 0000000..dc236f5 --- /dev/null +++ b/client/utils.go @@ -0,0 +1,68 @@ +package client + +import ( + "crypto/cipher" + "crypto/rand" + "fmt" + + "github.com/ProtonMail/gopenpgp/v3/crypto" +) + +func (bismuth BismuthClient) encryptMessage(aead cipher.AEAD, msg []byte) ([]byte, error) { + nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(msg)+aead.Overhead()) + + if _, err := rand.Read(nonce); err != nil { + return []byte{}, err + } + + encryptedMsg := aead.Seal(nonce, nonce, msg, nil) + return encryptedMsg, nil +} + +func (bismuth BismuthClient) decryptMessage(aead cipher.AEAD, encMsg []byte) ([]byte, error) { + if len(encMsg) < aead.NonceSize() { + return []byte{}, fmt.Errorf("ciphertext too short") + } + + // Split nonce and ciphertext. + nonce, ciphertext := encMsg[:aead.NonceSize()], encMsg[aead.NonceSize():] + + // Decrypt the message and check it wasn't tampered with. + decryptedData, err := aead.Open(nil, nonce, ciphertext, nil) + + if err != nil { + return []byte{}, err + } + + return decryptedData, nil +} + +// Creates a new BismuthClient. +// +// Both `pubKey` and `privKey` are armored PGP public and private keys respectively. +func New(pubKey string, privKey string) (*BismuthClient, error) { + publicKey, err := crypto.NewKeyFromArmored(pubKey) + + if err != nil { + return nil, err + } + + privateKey, err := crypto.NewKeyFromArmored(privKey) + + if err != nil { + return nil, err + } + + bismuth := BismuthClient{ + PublicKey: publicKey, + PrivateKey: privateKey, + } + + err = bismuth.InitializeClient() + + if err != nil { + return nil, err + } + + return &bismuth, nil +} diff --git a/commons/enum.go b/commons/enum.go index be1848f..3c7f4ff 100644 --- a/commons/enum.go +++ b/commons/enum.go @@ -2,32 +2,41 @@ package commons -// Commands +// Core Protocol Commands const ( - // SendPublicKey: Sending public key back and forth + // Sending public key back and forth SendPublicKey = iota - // SwitchToSymmetricKey: Sent by the client along with the symmetric key that is going to be used + // Sent by the client along with the symmetric key that is going to be used SwitchToSymmetricKey - // ClientSendHost: Currently unimplemented. // Client sends what host they are connecting to. ClientSendHost - // GetSigningServers: Currently unimplemented. // Gets the signing servers trusting/signing the current server. GetSigningServers - // GetTrustedDomains: Currently unimplemented. // Gets the domains that are supported by this certificate (should be cross-checked) GetTrustedDomains - // InitiateForwarding: Starts forwarding traffic over this protocol. + // Starts forwarding traffic over this protocol. InitiateForwarding ) -// Encryption algorithms +// Validation API Commands +const ( + // Checks if the domains are valid for a specified key + AreDomainsValidForKey = iota + // Validate a server and keys + ValidateKey + // Status codes + Success + Failure + InternalError +) + +// Encryption Algorithms const ( // Default and only encryption algorithm XChaCha20Poly1305 = iota ) -// Unsigned integer limits +// Unsigned Integer Limits const ( BitLimit24 = 16_777_215 BitLimit16 = 65535 diff --git a/main.go b/main.go index 4ded7a1..373320d 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "context" _ "embed" + "encoding/hex" "fmt" "net" "os" @@ -11,6 +12,8 @@ import ( "git.greysoh.dev/imterah/bismuthd/client" core "git.greysoh.dev/imterah/bismuthd/commons" "git.greysoh.dev/imterah/bismuthd/server" + "git.greysoh.dev/imterah/bismuthd/signingclient" + "git.greysoh.dev/imterah/bismuthd/signingserver" "github.com/charmbracelet/log" "github.com/urfave/cli/v2" "tailscale.com/net/socks5" @@ -19,7 +22,7 @@ import ( //go:embed ascii.txt var asciiArt string -func bismuthClientEntrypoint(cCtx *cli.Context) error { +func clientEntrypoint(cCtx *cli.Context) error { pubKeyFile, err := os.ReadFile(cCtx.String("pubkey")) if err != nil { @@ -37,6 +40,8 @@ func bismuthClientEntrypoint(cCtx *cli.Context) error { bismuth, err := client.New(pubKey, privKey) + log.Debugf("My key fingerprint is: %s", bismuth.PublicKey.GetFingerprint()) + if err != nil { return err } @@ -82,13 +87,15 @@ func bismuthClientEntrypoint(cCtx *cli.Context) error { return nil, err } - conn, err = bismuth.Conn(conn) + conn, returnData, err := bismuth.Conn(conn) if err != nil && err.Error() != "EOF" { log.Errorf("failed to initialize bismuth connection to '%s:%s': '%s'", ip, port, err.Error()) return nil, err } + log.Debugf("Server key fingerprint for '%s' is: %s", addr, returnData.ServerPublicKey.GetFingerprint()) + return conn, err } else { conn, err := net.Dial(network, addr) @@ -110,8 +117,17 @@ func bismuthClientEntrypoint(cCtx *cli.Context) error { return nil } -func bismuthServerEntrypoint(cCtx *cli.Context) error { - relayServers := []string{} +func serverEntrypoint(cCtx *cli.Context) error { + var domainList []string + var signServers []string + + if cCtx.String("domain-names") != "" { + domainList = strings.Split(cCtx.String("domain-names"), ":") + } + + if cCtx.String("signing-servers") != "" { + signServers = strings.Split(cCtx.String("signing-servers"), ";") + } pubKeyFile, err := os.ReadFile(cCtx.String("pubkey")) @@ -130,7 +146,8 @@ func bismuthServerEntrypoint(cCtx *cli.Context) error { network := fmt.Sprintf("%s:%s", cCtx.String("source-ip"), cCtx.String("source-port")) - bismuth, err := server.NewBismuthServer(pubKey, privKey, relayServers, core.XChaCha20Poly1305, func(connBismuth net.Conn) error { + bismuth, err := server.New(pubKey, privKey, signServers, domainList, core.XChaCha20Poly1305) + bismuth.HandleConnection = func(connBismuth net.Conn, _ *server.ClientMetadata) error { connDialed, err := net.Dial("tcp", network) if err != nil { @@ -183,7 +200,7 @@ func bismuthServerEntrypoint(cCtx *cli.Context) error { }() return nil - }) + } if err != nil { return err @@ -201,23 +218,206 @@ func bismuthServerEntrypoint(cCtx *cli.Context) error { for { conn, err := listener.Accept() + + if err != nil { + log.Warnf("failed to accept connection: '%s'", err.Error()) + continue + } + log.Debugf("Recieved connection from '%s'", conn.RemoteAddr().String()) + go func() { + err := bismuth.HandleProxy(conn) + + if err != nil && err.Error() != "EOF" { + log.Warnf("connection crashed/dropped during proxy handling: '%s'", err.Error()) + } + }() + } +} + +func signingServerEntrypoint(cCtx *cli.Context) error { + log.Warn("Using the built-in bismuth signing server in production is a horrible idea as it has no validation!") + log.Warn("Consider writing using a custom solution that's based on the signing server code, rather than the default implementation.") + + var domainList []string + var signServers []string + + if cCtx.String("domain-names") != "" { + domainList = strings.Split(cCtx.String("domain-names"), ":") + } + + if cCtx.String("signing-servers") != "" { + signServers = strings.Split(cCtx.String("signing-servers"), ";") + } + + pubKeyFile, err := os.ReadFile(cCtx.String("pubkey")) + + if err != nil { + return err + } + + privKeyFile, err := os.ReadFile(cCtx.String("privkey")) + + if err != nil { + return err + } + + pubKey := string(pubKeyFile) + privKey := string(privKeyFile) + + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%s", cCtx.String("ip"), cCtx.String("port"))) + + if err != nil { + return err + } + + bismuthServer, err := server.New(pubKey, privKey, signServers, domainList, core.XChaCha20Poly1305) + + if err != nil { + return nil + } + + // I'd like to use the SigningServer struct, but I can't really do that + _, err = signingserver.New(bismuthServer) + + if err != nil { + return nil + } + + defer listener.Close() + + log.Info("Bismuth signing server is listening...") + + for { + conn, err := listener.Accept() + if err != nil { log.Warn(err.Error()) continue } + log.Debugf("Recieved connection from '%s'", conn.RemoteAddr().String()) + go func() { - err := bismuth.HandleProxy(conn) + err = bismuthServer.HandleProxy(conn) if err != nil && err.Error() != "EOF" { - log.Warnf("Connection crashed/dropped during proxy handling: '%s'", err.Error()) + log.Warnf("connection crashed/dropped during proxy handling: '%s'", err.Error()) + return } }() } } +func verifyCert(cCtx *cli.Context) error { + domainList := strings.Split(cCtx.String("domain-names"), ":") + pubKeyFile, err := os.ReadFile(cCtx.String("pubkey")) + + if err != nil { + return err + } + + privKeyFile, err := os.ReadFile(cCtx.String("privkey")) + + if err != nil { + return err + } + + pubKey := string(pubKeyFile) + privKey := string(privKeyFile) + + bismuthClient, err := client.New(pubKey, privKey) + + if err != nil { + return err + } + + dialedConn, err := net.Dial("tcp", cCtx.String("signing-server")) + + if err != nil { + return err + } + + conn, certResults, err := bismuthClient.Conn(dialedConn) + + if err != nil { + return err + } + + if certResults.OverallTrustScore < 50 { + return fmt.Errorf("overall trust score is below 50 percent for certificate") + } + + fmt.Println("Sending signing request to sign server...") + + hasBeenTrusted, err := signingclient.RequestDomainToBeTrusted(conn, domainList, "") + + if hasBeenTrusted { + fmt.Println("Server has been successfully signed.") + } else { + fmt.Println("Server has not been successfully signed.") + os.Exit(1) + } + + return nil +} + +func signCert(cCtx *cli.Context) error { + domainList := strings.Split(cCtx.String("domain-names"), ":") + keyFingerprint, err := hex.DecodeString(cCtx.String("key-fingerprint")) + + if err != nil { + return err + } + + pubKeyFile, err := os.ReadFile(cCtx.String("pubkey")) + + if err != nil { + return err + } + + privKeyFile, err := os.ReadFile(cCtx.String("privkey")) + + if err != nil { + return err + } + + pubKey := string(pubKeyFile) + privKey := string(privKeyFile) + + bismuthClient, err := client.New(pubKey, privKey) + + if err != nil { + return err + } + + dialedConn, err := net.Dial("tcp", cCtx.String("signing-server")) + + if err != nil { + return err + } + + conn, certResults, err := bismuthClient.Conn(dialedConn) + + if err != nil { + return err + } + + if certResults.OverallTrustScore < 50 { + return fmt.Errorf("overall trust score is below 50 percent for certificate") + } + + isTrusted, err := signingclient.IsDomainTrusted(conn, keyFingerprint, domainList) + fmt.Printf("Certificate trust status: %t\n", isTrusted) + + if !isTrusted { + os.Exit(1) + } + + return nil +} + func main() { fmt.Println(asciiArt) fmt.Print("Implementation of the Bismuth protocol\n\n") @@ -282,7 +482,7 @@ func main() { }, }, Usage: "client for the Bismuth protocol", - Action: bismuthClientEntrypoint, + Action: clientEntrypoint, }, { Name: "server", @@ -308,6 +508,14 @@ func main() { Usage: "port to connect to", Required: true, }, + &cli.StringFlag{ + Name: "signing-servers", + Usage: "servers trusting/\"signing\" the public key. seperated using semicolons", + }, + &cli.StringFlag{ + Name: "domain-names", + Usage: "domain names the key is authorized to use. seperated using colons", + }, &cli.StringFlag{ Name: "dest-ip", Usage: "IP to listen on", @@ -320,7 +528,109 @@ func main() { }, }, Usage: "server for the Bismuth protocol", - Action: bismuthServerEntrypoint, + Action: serverEntrypoint, + }, + { + Name: "test-sign-server", + Aliases: []string{"tss"}, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "pubkey", + Usage: "path to PGP public key", + Required: true, + }, + &cli.StringFlag{ + Name: "privkey", + Usage: "path to PGP private key", + Required: true, + }, + &cli.StringFlag{ + Name: "ip", + Usage: "IP to listen on", + Value: "0.0.0.0", + }, + &cli.StringFlag{ + Name: "port", + Usage: "port to listen on", + Value: "9090", + }, + &cli.StringFlag{ + Name: "signing-servers", + Usage: "servers trusting/\"signing\" the public key. seperated using semicolons", + }, + &cli.StringFlag{ + Name: "domain-names", + Usage: "domain names the key is authorized to use. seperated using colons", + }, + }, + Usage: "test signing server for the Bismuth protocol", + Action: signingServerEntrypoint, + }, + { + Name: "sign-tool", + Aliases: []string{"st"}, + Subcommands: []*cli.Command{ + { + Name: "is-verified", + Aliases: []string{"i", "iv", "cv"}, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "key-fingerprint", + Usage: "fingerprint of key", + Required: true, + }, + &cli.StringFlag{ + Name: "pubkey", + Usage: "path to PGP public key", + }, + &cli.StringFlag{ + Name: "privkey", + Usage: "path to PGP private key", + }, + &cli.StringFlag{ + Name: "domain-names", + Usage: "domain names the key is authorized to use. seperated using colons", + Required: true, + }, + &cli.StringFlag{ + Name: "signing-server", + Usage: "signing server to use", + Required: true, + }, + }, + Usage: "check if a certificate is verified for Bismuth", + Action: signCert, + }, + { + Name: "verify-cert", + Aliases: []string{"v", "vc"}, + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "pubkey", + Usage: "path to PGP public key", + Required: true, + }, + &cli.StringFlag{ + Name: "privkey", + Usage: "path to PGP private key", + Required: true, + }, + &cli.StringFlag{ + Name: "domain-names", + Usage: "domain names the key is authorized to use. seperated using colons", + Required: true, + }, + &cli.StringFlag{ + Name: "signing-server", + Usage: "signing server to use", + Required: true, + }, + }, + Usage: "verifies certificate for Bismuth", + Action: verifyCert, + }, + }, + Usage: "signing tool for Bismuth", }, }, } diff --git a/server/server.go b/server/server.go index 4e1c183..e9d61bd 100644 --- a/server/server.go +++ b/server/server.go @@ -13,54 +13,6 @@ import ( "golang.org/x/crypto/chacha20poly1305" ) -// Bismuth Server -type BismuthServer struct { - // Public key to use for transmission - PublicKey *crypto.Key - // Private key to use for transmission - PrivateKey *crypto.Key - - pgp *crypto.PGPHandle - - // Algorithm to use for encryption (currently XChaCha20Poly1305 is the only option) - SymmetricEncryptionAlgorithm int - // Servers that are signing this server. If none, this server becomes self-signed - // in the clients eyes - SigningServers []string - - // Called after a successful handshake & connection. - HandleConnection func(conn net.Conn) error -} - -func (bismuth BismuthServer) encryptMessage(aead cipher.AEAD, msg []byte) ([]byte, error) { - nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(msg)+aead.Overhead()) - - if _, err := rand.Read(nonce); err != nil { - return []byte{}, err - } - - encryptedMsg := aead.Seal(nonce, nonce, msg, nil) - return encryptedMsg, nil -} - -func (bismuth BismuthServer) decryptMessage(aead cipher.AEAD, encMsg []byte) ([]byte, error) { - if len(encMsg) < aead.NonceSize() { - return []byte{}, fmt.Errorf("ciphertext too short") - } - - // Split nonce and ciphertext. - nonce, ciphertext := encMsg[:aead.NonceSize()], encMsg[aead.NonceSize():] - - // Decrypt the message and check it wasn't tampered with. - decryptedData, err := aead.Open(nil, nonce, ciphertext, nil) - - if err != nil { - return []byte{}, err - } - - return decryptedData, nil -} - // Called to handle a connnection for Bismuth. The conn argument is the client you'd like to handle func (bismuth BismuthServer) HandleProxy(conn net.Conn) error { serverState := "keyHandshake" @@ -211,7 +163,55 @@ func (bismuth BismuthServer) HandleProxy(conn net.Conn) error { return err } - if packet[0] == core.InitiateForwarding { + switch packet[0] { + case core.GetSigningServers: + totalPacketContents := make([]byte, 1) + totalPacketContents[0] = core.GetSigningServers + + for index, signServer := range bismuth.SigningServers { + totalPacketContents = append(totalPacketContents, []byte(signServer)...) + + if index+1 != len(bismuth.SigningServers) { + totalPacketContents = append(totalPacketContents, '\n') + } + } + + encryptedPacket, err := bismuth.encryptMessage(aead, totalPacketContents) + + if err != nil { + return err + } + + encryptedPacketLength := make([]byte, 3) + core.Int32ToInt24(encryptedPacketLength, uint32(len(encryptedPacket))) + + conn.Write(encryptedPacketLength) + conn.Write(encryptedPacket) + case core.GetTrustedDomains: + totalPacketContents := make([]byte, 1) + totalPacketContents[0] = core.GetTrustedDomains + + for index, trustedDomain := range bismuth.TrustedDomains { + fmt.Println("building trusted domains") + totalPacketContents = append(totalPacketContents, []byte(trustedDomain)...) + + if index+1 != len(bismuth.TrustedDomains) { + totalPacketContents = append(totalPacketContents, '\n') + } + } + + encryptedPacket, err := bismuth.encryptMessage(aead, totalPacketContents) + + if err != nil { + return err + } + + encryptedPacketLength := make([]byte, 3) + core.Int32ToInt24(encryptedPacketLength, uint32(len(encryptedPacket))) + + conn.Write(encryptedPacketLength) + conn.Write(encryptedPacket) + case core.InitiateForwarding: bmConn := core.BismuthConn{ Aead: aead, PassedConn: conn, @@ -220,42 +220,16 @@ func (bismuth BismuthServer) HandleProxy(conn net.Conn) error { bmConn.DoInitSteps() + metadata := ClientMetadata{ + ClientPublicKey: clientPublicKey, + } + err := bismuth.HandleConnection(core.BismuthConnWrapped{ Bismuth: &bmConn, - }) + }, &metadata) return err } } } } - -// Initializes a Bismuth server. -// -// Both `pubKey` and `privKey` are armored PGP public and private keys respectively. -func NewBismuthServer(pubKey string, privKey string, signServers []string, encryptionAlgo int, connHandler func(conn net.Conn) error) (*BismuthServer, error) { - publicKey, err := crypto.NewKeyFromArmored(pubKey) - - if err != nil { - return nil, err - } - - privateKey, err := crypto.NewKeyFromArmored(privKey) - - if err != nil { - return nil, err - } - - pgp := crypto.PGP() - - bismuth := BismuthServer{ - PublicKey: publicKey, - PrivateKey: privateKey, - HandleConnection: connHandler, - SigningServers: signServers, - SymmetricEncryptionAlgorithm: encryptionAlgo, - pgp: pgp, - } - - return &bismuth, nil -} diff --git a/server/typing.go b/server/typing.go new file mode 100644 index 0000000..bab25c4 --- /dev/null +++ b/server/typing.go @@ -0,0 +1,36 @@ +package server + +import ( + "net" + + "github.com/ProtonMail/gopenpgp/v3/crypto" +) + +// Bismuth Server +type BismuthServer struct { + // Public key to use for transmission + PublicKey *crypto.Key + // Private key to use for transmission + PrivateKey *crypto.Key + + // GopenPGP instance + pgp *crypto.PGPHandle + + // Algorithm to use for encryption (currently XChaCha20Poly1305 is the only option) + SymmetricEncryptionAlgorithm int + // Servers that are signing this server. If none, this server becomes self-signed + // in the clients eyes. + SigningServers []string + // Domains that the certificate is authorized to use. This will be checked by the + // signing servers. + TrustedDomains []string + + // Called after a successful handshake & connection. + HandleConnection func(conn net.Conn, metadata *ClientMetadata) error +} + +// Metadata from the client that may be helpful for the server to have. +type ClientMetadata struct { + // Client's public key + ClientPublicKey *crypto.Key +} diff --git a/server/utils.go b/server/utils.go new file mode 100644 index 0000000..aff3186 --- /dev/null +++ b/server/utils.go @@ -0,0 +1,68 @@ +package server + +import ( + "crypto/cipher" + "crypto/rand" + "fmt" + + "github.com/ProtonMail/gopenpgp/v3/crypto" +) + +func (bismuth BismuthServer) encryptMessage(aead cipher.AEAD, msg []byte) ([]byte, error) { + nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(msg)+aead.Overhead()) + + if _, err := rand.Read(nonce); err != nil { + return []byte{}, err + } + + encryptedMsg := aead.Seal(nonce, nonce, msg, nil) + return encryptedMsg, nil +} + +func (bismuth BismuthServer) decryptMessage(aead cipher.AEAD, encMsg []byte) ([]byte, error) { + if len(encMsg) < aead.NonceSize() { + return []byte{}, fmt.Errorf("ciphertext too short") + } + + // Split nonce and ciphertext. + nonce, ciphertext := encMsg[:aead.NonceSize()], encMsg[aead.NonceSize():] + + // Decrypt the message and check it wasn't tampered with. + decryptedData, err := aead.Open(nil, nonce, ciphertext, nil) + + if err != nil { + return []byte{}, err + } + + return decryptedData, nil +} + +// Initializes a Bismuth server. +// +// Both `pubKey` and `privKey` are armored PGP public and private keys respectively. +func New(pubKey string, privKey string, signServers []string, trustedDomains []string, encryptionAlgo int) (*BismuthServer, error) { + publicKey, err := crypto.NewKeyFromArmored(pubKey) + + if err != nil { + return nil, err + } + + privateKey, err := crypto.NewKeyFromArmored(privKey) + + if err != nil { + return nil, err + } + + pgp := crypto.PGP() + + bismuth := BismuthServer{ + PublicKey: publicKey, + PrivateKey: privateKey, + SigningServers: signServers, + TrustedDomains: trustedDomains, + SymmetricEncryptionAlgorithm: encryptionAlgo, + pgp: pgp, + } + + return &bismuth, nil +} diff --git a/signingclient/signingclient.go b/signingclient/signingclient.go new file mode 100644 index 0000000..0fe3ebb --- /dev/null +++ b/signingclient/signingclient.go @@ -0,0 +1,69 @@ +package signingclient + +import ( + "encoding/binary" + "net" + "strings" + + core "git.greysoh.dev/imterah/bismuthd/commons" +) + +func IsDomainTrusted(conn net.Conn, keyFingerprint []byte, domainList []string) (bool, error) { + domainListAsString := strings.Join(domainList, "\n") + + keyFingerprintSize := len(keyFingerprint) + domainListSize := len(domainListAsString) + + domainTrustedCommand := make([]byte, 1+2+2+keyFingerprintSize+domainListSize) + + domainTrustedCommand[0] = core.AreDomainsValidForKey + currentOffset := 1 + + binary.BigEndian.PutUint16(domainTrustedCommand[currentOffset:currentOffset+2], uint16(keyFingerprintSize)) + copy(domainTrustedCommand[2+currentOffset:2+currentOffset+keyFingerprintSize], keyFingerprint) + + currentOffset += 2 + keyFingerprintSize + + binary.BigEndian.PutUint16(domainTrustedCommand[currentOffset:currentOffset+2], uint16(domainListSize)) + copy(domainTrustedCommand[2+currentOffset:2+currentOffset+domainListSize], []byte(domainListAsString)) + + conn.Write(domainTrustedCommand) + + requestResponse := make([]byte, 1) + + if _, err := conn.Read(requestResponse); err != nil { + return false, err + } + + return requestResponse[0] == core.Success, nil +} + +func RequestDomainToBeTrusted(conn net.Conn, domainList []string, additionalInformation string) (bool, error) { + domainListAsString := strings.Join(domainList, "\n") + + domainListSize := len(domainListAsString) + additionalInfoSize := len(additionalInformation) + + requestDomainTrust := make([]byte, 1+2+2+domainListSize+additionalInfoSize) + + requestDomainTrust[0] = core.ValidateKey + currentOffset := 1 + + binary.BigEndian.PutUint16(requestDomainTrust[currentOffset:currentOffset+2], uint16(domainListSize)) + copy(requestDomainTrust[2+currentOffset:2+currentOffset+domainListSize], []byte(domainListAsString)) + + currentOffset += 2 + domainListSize + + binary.BigEndian.PutUint16(requestDomainTrust[currentOffset:currentOffset+2], uint16(additionalInfoSize)) + copy(requestDomainTrust[2:currentOffset:2+currentOffset+additionalInfoSize], []byte(additionalInformation)) + + conn.Write(requestDomainTrust) + + requestResponse := make([]byte, 1) + + if _, err := conn.Read(requestResponse); err != nil { + return false, err + } + + return requestResponse[0] == core.Success, nil +} diff --git a/signingserver/signingserver.go b/signingserver/signingserver.go new file mode 100644 index 0000000..0ff29e7 --- /dev/null +++ b/signingserver/signingserver.go @@ -0,0 +1,198 @@ +package signingserver + +import ( + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + "net" + "strings" + + core "git.greysoh.dev/imterah/bismuthd/commons" + "git.greysoh.dev/imterah/bismuthd/server" +) + +func (signServer *BismuthSigningServer) InitializeServer() error { + if signServer.AddVerifyHandler == nil { + fmt.Println("WARN: You are using the default AddVerifyHandler in SignServer! This is a bad idea. Please write your own implementation!") + + signServer.AddVerifyHandler = func(serverAddr string, serverKeyFingerprint string, serverDomainList []string, additionalClientProvidedInfo string) (bool, error) { + domainListHash := sha256.Sum256([]byte(strings.Join(serverDomainList, ":"))) + + signServer.builtInVerifyMapStore[serverAddr+".fingerprint"] = serverKeyFingerprint + signServer.builtInVerifyMapStore[serverAddr+".domainListHash"] = hex.EncodeToString(domainListHash[:]) + + return true, nil + } + } + + if signServer.VerifyServerHandler == nil { + fmt.Println("WARN: You are using the default VerifyServerHandler in SignServer! This is a bad idea. Please write your own implementation!") + + signServer.VerifyServerHandler = func(serverAddr string, serverKeyFingerprint string, serverDomainList []string) (bool, error) { + domainListHash := sha256.Sum256([]byte(strings.Join(serverDomainList, ":"))) + domainListHashHex := hex.EncodeToString(domainListHash[:]) + + if storedKeyFingerprint, ok := signServer.builtInVerifyMapStore[serverAddr+".fingerprint"]; ok { + if storedKeyFingerprint != serverKeyFingerprint { + return false, nil + } + } else { + return false, nil + } + + if storedDomainListHashHex, ok := signServer.builtInVerifyMapStore[serverAddr+".domainListHash"]; ok { + if storedDomainListHashHex != domainListHashHex { + return false, nil + } + } else { + return false, nil + } + + return true, nil + } + } + + if signServer.builtInVerifyMapStore == nil { + signServer.builtInVerifyMapStore = map[string]string{} + } + + signServer.BismuthServer.HandleConnection = signServer.connHandler + return nil +} + +func (signServer *BismuthSigningServer) connHandler(conn net.Conn, metadata *server.ClientMetadata) error { + defer conn.Close() + requestType := make([]byte, 1) + + hostAndIP := conn.RemoteAddr().String() + hostAndIPColonIndex := strings.Index(hostAndIP, ":") + + if hostAndIPColonIndex == -1 { + return fmt.Errorf("failed to get colon in remote address") + } + + host := hostAndIP[:hostAndIPColonIndex] + clientKeyFingerprint := metadata.ClientPublicKey.GetFingerprint() + + for { + if _, err := conn.Read(requestType); err != nil { + return err + } + + if requestType[0] == core.AreDomainsValidForKey { + // This is probably a bit too big, but I'd like to air on the side of caution here... + keyFingerprintLength := make([]byte, 2) + + if _, err := conn.Read(keyFingerprintLength); err != nil { + return err + } + + keyFingerprintBytes := make([]byte, binary.BigEndian.Uint16(keyFingerprintLength)) + + if _, err := conn.Read(keyFingerprintBytes); err != nil { + return err + } + + keyFingerprint := hex.EncodeToString(keyFingerprintBytes) + serverDomainListLength := make([]byte, 2) + + if _, err := conn.Read(serverDomainListLength); err != nil { + return err + } + + serverDomainListBytes := make([]byte, binary.BigEndian.Uint16(serverDomainListLength)) + + if _, err := conn.Read(serverDomainListBytes); err != nil { + return err + } + + serverDomainList := strings.Split(string(serverDomainListBytes), "\n") + + // We can't trust anything if they aren't advertising any domains/IPs + if len(serverDomainList) == 0 { + requestResponse := make([]byte, 1) + requestResponse[0] = core.Failure + + conn.Write(requestResponse) + continue + } + + isVerified, err := signServer.VerifyServerHandler(host, keyFingerprint, serverDomainList) + + if err != nil { + requestResponse := make([]byte, 1) + requestResponse[0] = core.InternalError + + conn.Write(requestResponse) + + return err + } + + if isVerified { + requestResponse := make([]byte, 1) + requestResponse[0] = core.Success + + conn.Write(requestResponse) + } else { + requestResponse := make([]byte, 1) + requestResponse[0] = core.Failure + + conn.Write(requestResponse) + } + } else if requestType[0] == core.ValidateKey { + // This is probably a bit too big, but I'd like to air on the side of caution here... + serverDomainListLength := make([]byte, 2) + + if _, err := conn.Read(serverDomainListLength); err != nil { + return err + } + + serverDomainListBytes := make([]byte, binary.BigEndian.Uint16(serverDomainListLength)) + + if _, err := conn.Read(serverDomainListBytes); err != nil { + return err + } + + serverDomainList := strings.Split(string(serverDomainListBytes), "\n") + + additionalArgumentsLength := make([]byte, 2) + var additionalArgumentsSize uint16 + + if _, err := conn.Read(additionalArgumentsLength); err != nil { + return err + } + + additionalArgumentsSize = binary.BigEndian.Uint16(additionalArgumentsLength) + additionalArguments := "" + + if additionalArgumentsSize != 0 { + additionalArgumentsBytes := make([]byte, additionalArgumentsSize) + + if _, err := conn.Read(additionalArgumentsBytes); err != nil { + return err + } + + additionalArguments = string(additionalArgumentsBytes) + } + + isAddedToTrust, err := signServer.AddVerifyHandler(host, clientKeyFingerprint, serverDomainList, additionalArguments) + + if err != nil { + return err + } + + if isAddedToTrust { + requestResponse := make([]byte, 1) + requestResponse[0] = core.Success + + conn.Write(requestResponse) + } else { + requestResponse := make([]byte, 1) + requestResponse[0] = core.Failure + + conn.Write(requestResponse) + } + } + } +} diff --git a/signingserver/typing.go b/signingserver/typing.go new file mode 100644 index 0000000..e15f7cd --- /dev/null +++ b/signingserver/typing.go @@ -0,0 +1,14 @@ +package signingserver + +import "git.greysoh.dev/imterah/bismuthd/server" + +type AddVerifyHandlerCallback func(serverAddr string, serverKeyFingerprint string, serverAdvertisedTrustList []string, additionalClientProvidedInfo string) (bool, error) +type VerifyServerHandlerCallback func(serverAddr string, serverKeyFingerprint string, serverDomainList []string) (bool, error) + +type BismuthSigningServer struct { + BismuthServer *server.BismuthServer + + AddVerifyHandler AddVerifyHandlerCallback + VerifyServerHandler VerifyServerHandlerCallback + builtInVerifyMapStore map[string]string +} diff --git a/signingserver/utils.go b/signingserver/utils.go new file mode 100644 index 0000000..955524a --- /dev/null +++ b/signingserver/utils.go @@ -0,0 +1,15 @@ +package signingserver + +import "git.greysoh.dev/imterah/bismuthd/server" + +func New(bismuthServer *server.BismuthServer) (*BismuthSigningServer, error) { + signServer := BismuthSigningServer{ + BismuthServer: bismuthServer, + } + + if err := signServer.InitializeServer(); err != nil { + return nil, err + } + + return &signServer, nil +} diff --git a/tests/integration_test.go b/tests/integration_test.go index 9e56be7..bc2e9da 100644 --- a/tests/integration_test.go +++ b/tests/integration_test.go @@ -19,6 +19,7 @@ var testProtocolTxRxBufCount = 32 // Tests protocol transmitting and receiving // This is designed to be a nightmare scenario for the protocol to push the limits on what would be possible. func TestProtocolTxRx(t *testing.T) { + t.Log("running tests") pubKeyCli, privKeyCli, err := CreateKeyring("alice", "alice@contoso.com") if err != nil { @@ -52,7 +53,9 @@ func TestProtocolTxRx(t *testing.T) { t.Fatalf("failed to listen on TCP for localhost (%s)", err.Error()) } - bismuth, err := server.NewBismuthServer(pubKeyServ, privKeyServ, []string{}, commons.XChaCha20Poly1305, func(conn net.Conn) error { + bismuth, err := server.New(pubKeyServ, privKeyServ, []string{}, []string{}, commons.XChaCha20Poly1305) + + bismuth.HandleConnection = func(conn net.Conn, _ *server.ClientMetadata) error { for entryCount, randomDataSlice := range randomDataSlices { _, err = conn.Write(randomDataSlice) @@ -62,7 +65,7 @@ func TestProtocolTxRx(t *testing.T) { } return nil - }) + } // TODO: fix these warnings? go func() { @@ -86,13 +89,15 @@ func TestProtocolTxRx(t *testing.T) { t.Fatalf("failed to initialize bismuthClient (%s)", err.Error()) } + bismuthClient.CheckIfCertificatesAreSigned = false + originalConn, err := net.Dial("tcp", "127.0.0.1:"+strconv.Itoa(port)) if err != nil { t.Fatalf("failed to connect to bismuth server (%s)", err.Error()) } - conn, err := bismuthClient.Conn(originalConn) + conn, _, err := bismuthClient.Conn(originalConn) if err != nil { t.Fatalf("bismuth client failed to handshake when connecting to server (%s)", err.Error())