feature: Gets signing server and client infrastructure working.

This commit is contained in:
imterah 2024-10-24 11:39:46 -04:00
parent a5e479cc0c
commit e527413faf
Signed by: imterah
GPG key ID: 8FA7DD57BA6CEA37
13 changed files with 865 additions and 62 deletions

312
main.go
View file

@ -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,8 @@ func bismuthClientEntrypoint(cCtx *cli.Context) error {
return nil
}
func bismuthServerEntrypoint(cCtx *cli.Context) error {
relayServers := []string{}
func serverEntrypoint(cCtx *cli.Context) error {
signingServers := []string{}
pubKeyFile, err := os.ReadFile(cCtx.String("pubkey"))
@ -130,7 +137,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.NewBismuthServer(pubKey, privKey, signingServers, core.XChaCha20Poly1305)
bismuth.HandleConnection = func(connBismuth net.Conn, _ *server.ClientMetadata) error {
connDialed, err := net.Dial("tcp", network)
if err != nil {
@ -183,7 +191,7 @@ func bismuthServerEntrypoint(cCtx *cli.Context) error {
}()
return nil
})
}
if err != nil {
return err
@ -201,23 +209,197 @@ 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.")
signServers := []string{}
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.NewBismuthServer(pubKey, privKey, signServers, 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% 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% for certificate")
}
isTrusted, err := signingclient.IsDomainTrusted(conn, keyFingerprint, domainList)
fmt.Printf("is certificate trusted: %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 +464,7 @@ func main() {
},
},
Usage: "client for the Bismuth protocol",
Action: bismuthClientEntrypoint,
Action: clientEntrypoint,
},
{
Name: "server",
@ -308,6 +490,14 @@ func main() {
Usage: "port to connect to",
Required: true,
},
&cli.StringFlag{
Name: "signing-servers",
Usage: "servers trusting/\"signing\" the public key. seperated using colons",
},
&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 +510,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: "domain-names",
Usage: "domain names the key is authorized to use. seperated using colons",
},
&cli.StringFlag{
Name: "signing-server",
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",
},
},
}