From d940af61fab2a8518f9a89d32c264b62fb6ac7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Fri, 15 Mar 2024 15:59:35 +0100 Subject: [PATCH] Replace all panics in browserbiometrics with proper error checking --- browserbiometrics/communication.go | 41 +++++++------ browserbiometrics/crypto.go | 24 ++++---- browserbiometrics/main.go | 10 +++- browserbiometrics/protocol.go | 95 +++++++++++++++++++----------- 4 files changed, 105 insertions(+), 65 deletions(-) diff --git a/browserbiometrics/communication.go b/browserbiometrics/communication.go index 89d95b4..301e3f7 100644 --- a/browserbiometrics/communication.go +++ b/browserbiometrics/communication.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/binary" "encoding/json" + "fmt" "os" "unsafe" @@ -25,44 +26,50 @@ func setupCommunication() { } } -func dataToBytes(msg SendMessage) []byte { +func dataToBytes(msg SendMessage) ([]byte, error) { byteMsg, err := json.Marshal(msg) if err != nil { - logging.Panicf("Unable to marshal OutgoingMessage struct to slice of bytes: " + err.Error()) + return nil, fmt.Errorf("unable to marshal OutgoingMessage struct to slice of bytes: %w", err) } - return byteMsg + return byteMsg, nil } -func writeMessageLength(msg []byte) { +func writeMessageLength(msg []byte) error { err := binary.Write(os.Stdout, nativeEndian, uint32(len(msg))) if err != nil { - logging.Panicf("Unable to write message length to Stdout: " + err.Error()) + return fmt.Errorf("unable to write message length to stdout: %w", err) } + return nil } -func readMessageLength(msg []byte) int { - var length uint32 +func readMessageLength(msg []byte) (int, error) { + var length int buf := bytes.NewBuffer(msg) err := binary.Read(buf, nativeEndian, &length) if err != nil { - logging.Panicf("Unable to read bytes representing message length:" + err.Error()) + return 0, fmt.Errorf("Unable to read bytes representing message length: %w", err) } - return int(length) + return length, nil } -func send(msg SendMessage) { - byteMsg := dataToBytes(msg) +func send(msg SendMessage) error { + byteMsg, err := dataToBytes(msg) + if err != nil { + return err + } + logging.Debugf("[SENSITIVE] Sending message: " + string(byteMsg)) - writeMessageLength(byteMsg) + err = writeMessageLength(byteMsg) + if err != nil { + return err + } var msgBuf bytes.Buffer - _, err := msgBuf.Write(byteMsg) + _, err = msgBuf.Write(byteMsg) if err != nil { - logging.Panicf(err.Error()) + return err } _, err = msgBuf.WriteTo(os.Stdout) - if err != nil { - logging.Panicf(err.Error()) - } + return err } diff --git a/browserbiometrics/crypto.go b/browserbiometrics/crypto.go index 4809b76..607fc1b 100644 --- a/browserbiometrics/crypto.go +++ b/browserbiometrics/crypto.go @@ -23,7 +23,7 @@ func pkcs7Pad(b []byte, blocksize int) ([]byte, error) { if blocksize <= 0 { return nil, ErrInvalidBlockSize } - if b == nil || len(b) == 0 { + if len(b) == 0 { return nil, ErrInvalidPKCS7Data } n := blocksize - (len(b) % blocksize) @@ -37,7 +37,7 @@ func pkcs7Unpad(b []byte, blocksize int) ([]byte, error) { if blocksize <= 0 { return nil, ErrInvalidBlockSize } - if b == nil || len(b) == 0 { + if len(b) == 0 { return nil, ErrInvalidPKCS7Data } if len(b)%blocksize != 0 { @@ -56,10 +56,10 @@ func pkcs7Unpad(b []byte, blocksize int) ([]byte, error) { return b[:len(b)-n], nil } -func decryptStringSymmetric(key []byte, ivb64 string, data string) string { +func decryptStringSymmetric(key []byte, ivb64 string, data string) (string, error) { block, err := aes.NewCipher(key) if err != nil { - panic(err) + return "", err } iv, _ := base64.StdEncoding.DecodeString(ivb64) ciphertext, _ := base64.StdEncoding.DecodeString(data) @@ -67,19 +67,19 @@ func decryptStringSymmetric(key []byte, ivb64 string, data string) string { bm.CryptBlocks(ciphertext, ciphertext) ciphertext, _ = pkcs7Unpad(ciphertext, aes.BlockSize) - return string(ciphertext) + return string(ciphertext), nil } -func encryptStringSymmetric(key []byte, data []byte) EncryptedString { +func encryptStringSymmetric(key []byte, data []byte) (EncryptedString, error) { block, err := aes.NewCipher(key) if err != nil { - panic(err) + return EncryptedString{}, err } data, _ = pkcs7Pad(data, block.BlockSize()) ciphertext := make([]byte, aes.BlockSize+len(data)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { - panic(err) + return EncryptedString{}, err } bm := cipher.NewCBCEncrypter(block, iv) bm.CryptBlocks(ciphertext[aes.BlockSize:], data) @@ -88,15 +88,15 @@ func encryptStringSymmetric(key []byte, data []byte) EncryptedString { IV: base64.StdEncoding.EncodeToString(ciphertext[:aes.BlockSize]), Data: base64.StdEncoding.EncodeToString(ciphertext[aes.BlockSize:]), EncType: 0, - } + }, nil } -func generateTransportKey() []byte { +func generateTransportKey() ([]byte, error) { key := make([]byte, 32) if _, err := io.ReadFull(rand.Reader, key); err != nil { - panic(err) + return nil, err } - return key + return key, nil } func rsaEncrypt(keyB64 string, message []byte) (string, error) { diff --git a/browserbiometrics/main.go b/browserbiometrics/main.go index 0abf918..895f403 100644 --- a/browserbiometrics/main.go +++ b/browserbiometrics/main.go @@ -26,13 +26,17 @@ const appID = "com.quexten.bw-bio-handler" var transportKey []byte -func Main(rtCfg *config.RuntimeConfig) { +func Main(rtCfg *config.RuntimeConfig) error { logging.Debugf("Starting browserbiometrics") - transportKey = generateTransportKey() + var err error + transportKey, err = generateTransportKey() + if err != nil { + return err + } logging.Debugf("Generated transport key") setupCommunication() - readLoop(rtCfg) + return readLoop(rtCfg) } func DetectAndInstallBrowsers() error { diff --git a/browserbiometrics/protocol.go b/browserbiometrics/protocol.go index 8eef4d2..93799b3 100644 --- a/browserbiometrics/protocol.go +++ b/browserbiometrics/protocol.go @@ -3,6 +3,7 @@ package browserbiometrics import ( "bufio" "encoding/json" + "fmt" "io" "os" @@ -14,7 +15,7 @@ import ( var runtimeConfig *config.RuntimeConfig -func readLoop(rtCfg *config.RuntimeConfig) { +func readLoop(rtCfg *config.RuntimeConfig) error { runtimeConfig = rtCfg v := bufio.NewReader(os.Stdin) s := bufio.NewReaderSize(v, bufferSize) @@ -23,64 +24,86 @@ func readLoop(rtCfg *config.RuntimeConfig) { lengthNum := int(0) logging.Debugf("Sending connected message") - send(SendMessage{ + err := send(SendMessage{ Command: "connected", AppID: appID, }) + if err != nil { + return err + } logging.Debugf("Starting read loop") for b, err := s.Read(lengthBytes); b > 0 && err == nil; b, err = s.Read(lengthBytes) { - lengthNum = readMessageLength(lengthBytes) + lengthNum, err = readMessageLength(lengthBytes) + if err != nil { + return err + } content := make([]byte, lengthNum) _, err := s.Read(content) if err != nil && err != io.EOF { - logging.Panicf(err.Error()) + return err } - parseMessage(content) + err = parseMessage(content) + if err != nil { + return err + } } + return nil } -func parseMessage(msg []byte) { +func parseMessage(msg []byte) error { logging.Debugf("Received message: " + string(msg)) var genericMessage GenericRecvMessage err := json.Unmarshal(msg, &genericMessage) if err != nil { - logging.Panicf("Unable to unmarshal json to struct: " + err.Error()) + return fmt.Errorf("unable to unmarshal json to struct: %w", err) } + if _, ok := (genericMessage.Message.(map[string]interface{})["command"]); ok { logging.Debugf("Message is unencrypted") var unmsg UnencryptedRecvMessage err := json.Unmarshal(msg, &unmsg) if err != nil { - logging.Panicf("Unable to unmarshal json to struct: " + err.Error()) + return fmt.Errorf("unable to unmarshal json to struct: %w", err) } - handleUnencryptedMessage(unmsg) + err = handleUnencryptedMessage(unmsg) + if err != nil { + return err + } } else { logging.Debugf("Message is encrypted") var encmsg EncryptedRecvMessage err := json.Unmarshal(msg, &encmsg) if err != nil { - logging.Panicf("Unable to unmarshal json to struct: " + err.Error()) + return fmt.Errorf("unable to unmarshal json to struct: %w", err) } - decryptedMessage := decryptStringSymmetric(transportKey, encmsg.Message.IV, encmsg.Message.Data) + decryptedMessage, err := decryptStringSymmetric(transportKey, encmsg.Message.IV, encmsg.Message.Data) + if err != nil { + return err + } var payloadMsg PayloadMessage err = json.Unmarshal([]byte(decryptedMessage), &payloadMsg) if err != nil { - logging.Panicf("Unable to unmarshal json to struct: " + err.Error()) + return fmt.Errorf("unable to unmarshal json to struct: %w", err) } - handlePayloadMessage(payloadMsg, genericMessage.AppID) + err = handlePayloadMessage(payloadMsg, genericMessage.AppID) + if err != nil { + return err + } } + + return nil } -func handleUnencryptedMessage(msg UnencryptedRecvMessage) { +func handleUnencryptedMessage(msg UnencryptedRecvMessage) error { logging.Debugf("Received unencrypted message: %+v", msg.Message) logging.Debugf(" with command: %s", msg.Message.Command) @@ -88,17 +111,22 @@ func handleUnencryptedMessage(msg UnencryptedRecvMessage) { case "setupEncryption": sharedSecret, err := rsaEncrypt(msg.Message.PublicKey, transportKey) if err != nil { - logging.Panicf(err.Error()) + return err } - send(SendMessage{ + err = send(SendMessage{ Command: "setupEncryption", AppID: msg.AppID, SharedSecret: sharedSecret, }) - break + if err != nil { + return err + } } + + return nil } -func handlePayloadMessage(msg PayloadMessage, appID string) { + +func handlePayloadMessage(msg PayloadMessage, appID string) error { logging.Debugf("Received unencrypted message: %+v", msg) switch msg.Command { @@ -108,7 +136,7 @@ func handlePayloadMessage(msg PayloadMessage, appID string) { home, err := os.UserHomeDir() if err != nil { - panic(err) + return err } if runtimeConfig.GoldwardenSocketPath == "" { @@ -127,16 +155,12 @@ func handlePayloadMessage(msg PayloadMessage, appID string) { result, err := client.NewUnixSocketClient(runtimeConfig).SendToAgent(messages.GetBiometricsKeyRequest{}) if err != nil { - logging.Errorf("Unable to send message to agent: %s", err.Error()) - return + return fmt.Errorf("Unable to send message to agent: %w", err) } - switch result.(type) { - case messages.GetBiometricsKeyResponse: - if err != nil { - logging.Panicf(err.Error()) - } - var key = result.(messages.GetBiometricsKeyResponse).Key + switch result := result.(type) { + case messages.GetBiometricsKeyResponse: + var key = result.Key var payloadMsg ReceiveMessage = ReceiveMessage{ Command: "biometricUnlock", Response: "unlocked", @@ -145,18 +169,23 @@ func handlePayloadMessage(msg PayloadMessage, appID string) { } payloadStr, err := json.Marshal(payloadMsg) if err != nil { - logging.Panicf(err.Error()) + return err } logging.Debugf("Payload: %s", payloadStr) - encStr := encryptStringSymmetric(transportKey, payloadStr) - send(SendMessage{ + encStr, err := encryptStringSymmetric(transportKey, payloadStr) + if err != nil { + return err + } + err = send(SendMessage{ AppID: appID, Message: encStr, }) - break + if err != nil { + return err + } } - - break } + + return nil }