From a2fd1c6a3b868ee5502f5deae8cfe877a988a982 Mon Sep 17 00:00:00 2001 From: "M. Thiercelin" Date: Mon, 31 Oct 2022 15:18:24 +0100 Subject: [PATCH 1/3] Sanitize non utf8 strings before returning them to iOS apps In swift, strings must be strictly utf8, and when golang returns a string with non utf8 characters, it gets translated to an empty string for utf8. To avoid this situation, we sanitize strings before returning them. This behavior is only enabled when building with the "ios" build tag. --- crypto/message.go | 2 +- crypto/mime.go | 3 ++- crypto/sanitize_string.go | 8 ++++++++ crypto/sanitize_string_ios.go | 10 ++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 crypto/sanitize_string.go create mode 100644 crypto/sanitize_string_ios.go diff --git a/crypto/message.go b/crypto/message.go index ccdb5d3..d6072fe 100644 --- a/crypto/message.go +++ b/crypto/message.go @@ -202,7 +202,7 @@ func (msg *PlainMessage) GetBinary() []byte { // GetString returns the content of the message as a string. func (msg *PlainMessage) GetString() string { - return strings.ReplaceAll(string(msg.Data), "\r\n", "\n") + return sanitizeString(strings.ReplaceAll(string(msg.Data), "\r\n", "\n")) } // GetBase64 returns the base-64 encoded binary content of the message as a diff --git a/crypto/mime.go b/crypto/mime.go index 4d55cd0..d756dfc 100644 --- a/crypto/mime.go +++ b/crypto/mime.go @@ -49,7 +49,8 @@ func (keyRing *KeyRing) DecryptMIMEMessage( callbacks.OnVerified(constants.SIGNATURE_OK) } bodyContent, bodyMimeType := body.GetBody() - callbacks.OnBody(bodyContent, bodyMimeType) + bodyContentSanitized := sanitizeString(bodyContent) + callbacks.OnBody(bodyContentSanitized, bodyMimeType) for i := 0; i < len(attachments); i++ { callbacks.OnAttachment(attachmentHeaders[i], []byte(attachments[i])) } diff --git a/crypto/sanitize_string.go b/crypto/sanitize_string.go new file mode 100644 index 0000000..94aa81c --- /dev/null +++ b/crypto/sanitize_string.go @@ -0,0 +1,8 @@ +//go:build !ios +// +build !ios + +package crypto + +func sanitizeString(input string) string { + return input +} diff --git a/crypto/sanitize_string_ios.go b/crypto/sanitize_string_ios.go new file mode 100644 index 0000000..561414b --- /dev/null +++ b/crypto/sanitize_string_ios.go @@ -0,0 +1,10 @@ +//go:build ios +// +build ios + +package crypto + +import "strings" + +func sanitizeString(input string) string { + return strings.ToValidUTF8(input, "\ufffd") +} From 04803505f86eda2e59a27bd7e77290b2b55488ac Mon Sep 17 00:00:00 2001 From: "M. Thiercelin" Date: Mon, 31 Oct 2022 15:42:28 +0100 Subject: [PATCH 2/3] Update changelog --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62936f4..a7c02c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased - ### Changed - - Updated `github.com/ProtonMail/go-mime` to latest versions, which cleans up uneeded dependencies. And fix an issue with PGP/MIME messages with non standard encodings. +- iOS only: sanitize strings returned in `MIMECallbacks.OnBody()` and `PlainMessage.GetString()`. Strings that have non utf8 characters will be sanitized to have the "character unknown" character : � instead. ## [2.4.10] 2022-08-22 ### Changed From 4971d78a532f270f173568a46919fdce822ea9fc Mon Sep 17 00:00:00 2001 From: "M. Thiercelin" Date: Thu, 3 Nov 2022 12:26:48 +0100 Subject: [PATCH 3/3] Sanitize strings by default on all platforms. Instead of sanitizing strings only on iOS, we do it on all platforms. --- CHANGELOG.md | 2 +- crypto/message_test.go | 8 +++++++- crypto/sanitize_string.go | 7 +++---- crypto/sanitize_string_ios.go | 10 ---------- 4 files changed, 11 insertions(+), 16 deletions(-) delete mode 100644 crypto/sanitize_string_ios.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a7c02c2..2b20845 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Changed - Updated `github.com/ProtonMail/go-mime` to latest versions, which cleans up uneeded dependencies. And fix an issue with PGP/MIME messages with non standard encodings. -- iOS only: sanitize strings returned in `MIMECallbacks.OnBody()` and `PlainMessage.GetString()`. Strings that have non utf8 characters will be sanitized to have the "character unknown" character : � instead. +- Sanitize strings returned in `MIMECallbacks.OnBody()` and `PlainMessage.GetString()`. Strings that have non utf8 characters will be sanitized to have the "character unknown" character : � instead. ## [2.4.10] 2022-08-22 ### Changed diff --git a/crypto/message_test.go b/crypto/message_test.go index 0f93b82..17be0d6 100644 --- a/crypto/message_test.go +++ b/crypto/message_test.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "errors" "io" + "io/ioutil" "testing" "time" @@ -83,7 +84,12 @@ func TestTextMixedMessageDecryptionWithPassword(t *testing.T) { t.Fatal("Expected no error when decrypting, got:", err) } - assert.Exactly(t, readTestFile("message_mixedPasswordPublicExpected", true), decrypted.GetString()) + expected, err := ioutil.ReadFile("testdata/message_mixedPasswordPublicExpected") + if err != nil { + panic(err) + } + + assert.Exactly(t, expected, decrypted.GetBinary()) } func TestTextMessageEncryption(t *testing.T) { diff --git a/crypto/sanitize_string.go b/crypto/sanitize_string.go index 94aa81c..854e11f 100644 --- a/crypto/sanitize_string.go +++ b/crypto/sanitize_string.go @@ -1,8 +1,7 @@ -//go:build !ios -// +build !ios - package crypto +import "strings" + func sanitizeString(input string) string { - return input + return strings.ToValidUTF8(input, "\ufffd") } diff --git a/crypto/sanitize_string_ios.go b/crypto/sanitize_string_ios.go deleted file mode 100644 index 561414b..0000000 --- a/crypto/sanitize_string_ios.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build ios -// +build ios - -package crypto - -import "strings" - -func sanitizeString(input string) string { - return strings.ToValidUTF8(input, "\ufffd") -}