summary refs log tree commit diff
path: root/vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go
diff options
context:
space:
mode:
authorEmile <git@emile.space>2024-10-25 15:55:50 +0200
committerEmile <git@emile.space>2024-10-25 15:55:50 +0200
commitc90f36e3dd179d2de96f4f5fe38d8dc9a9de6dfe (patch)
tree89e9afb41c5bf76f48cfb09305a2d3db8d302b06 /vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go
parent98bbb0f559a8883bc47bae80607dbe326a448e61 (diff)
vendor HEAD main
Diffstat (limited to 'vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go')
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go b/vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go
new file mode 100644
index 0000000..0c4422f
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/signatures/signatures.go
@@ -0,0 +1,94 @@
+// Copyright (c) 2024 Sumner Evans
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package signatures
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"errors"
+	"fmt"
+
+	"github.com/tidwall/gjson"
+	"github.com/tidwall/sjson"
+	"go.mau.fi/util/exgjson"
+
+	"maunium.net/go/mautrix/crypto/canonicaljson"
+	"maunium.net/go/mautrix/crypto/goolm/crypto"
+	"maunium.net/go/mautrix/id"
+)
+
+var (
+	ErrEmptyInput        = errors.New("empty input")
+	ErrSignatureNotFound = errors.New("input JSON doesn't contain signature from specified device")
+)
+
+// Signatures represents a set of signatures for some data from multiple users
+// and keys.
+type Signatures map[id.UserID]map[id.KeyID]string
+
+// NewSingleSignature creates a new [Signatures] object with a single
+// signature.
+func NewSingleSignature(userID id.UserID, algorithm id.KeyAlgorithm, keyID string, signature string) Signatures {
+	return Signatures{
+		userID: {
+			id.NewKeyID(algorithm, keyID): signature,
+		},
+	}
+}
+
+// VerifySignature verifies an Ed25519 signature.
+func VerifySignature(message []byte, key id.Ed25519, signature []byte) (ok bool, err error) {
+	if len(message) == 0 || len(key) == 0 || len(signature) == 0 {
+		return false, ErrEmptyInput
+	}
+	keyDecoded, err := base64.RawStdEncoding.DecodeString(key.String())
+	if err != nil {
+		return false, err
+	}
+	publicKey := crypto.Ed25519PublicKey(keyDecoded)
+	return publicKey.Verify(message, signature), nil
+}
+
+// VerifySignatureJSON verifies the signature in the given JSON object "obj"
+// as described in [Appendix 3] of the Matrix Spec.
+//
+// This function is a wrapper over [Utility.VerifySignatureJSON] that creates
+// and destroys the [Utility] object transparently.
+//
+// If the "obj" is not already a [json.RawMessage], it will re-encoded as JSON
+// for the verification, so "json" tags will be honored.
+//
+// [Appendix 3]: https://spec.matrix.org/v1.9/appendices/#signing-json
+func VerifySignatureJSON(obj any, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
+	var err error
+	objJSON, ok := obj.(json.RawMessage)
+	if !ok {
+		objJSON, err = json.Marshal(obj)
+		if err != nil {
+			return false, err
+		}
+	}
+
+	sig := gjson.GetBytes(objJSON, exgjson.Path("signatures", string(userID), fmt.Sprintf("ed25519:%s", keyName)))
+	if !sig.Exists() || sig.Type != gjson.String {
+		return false, ErrSignatureNotFound
+	}
+	objJSON, err = sjson.DeleteBytes(objJSON, "unsigned")
+	if err != nil {
+		return false, err
+	}
+	objJSON, err = sjson.DeleteBytes(objJSON, "signatures")
+	if err != nil {
+		return false, err
+	}
+	objJSONString := canonicaljson.CanonicalJSONAssumeValid(objJSON)
+	sigBytes, err := base64.RawStdEncoding.DecodeString(sig.Str)
+	if err != nil {
+		return false, err
+	}
+	return VerifySignature(objJSONString, key, sigBytes)
+}