Files
Ilia Denisov dc1c9b109c phase 3
2026-05-07 09:40:37 +02:00

52 lines
1.6 KiB
Go

package canon
import (
"crypto/ed25519"
"encoding/base64"
"errors"
)
var (
// ErrInvalidClientPublicKey reports that the provided client public key is
// not a base64-encoded raw Ed25519 public key.
ErrInvalidClientPublicKey = errors.New("client_public_key is not a valid base64-encoded Ed25519 public key")
// ErrInvalidRequestSignature reports that a request signature is not a raw
// Ed25519 signature for the canonical request signing input.
ErrInvalidRequestSignature = errors.New("invalid request signature")
)
// VerifyRequestSignature decodes the base64-encoded raw Ed25519 client public
// key, builds the canonical v1 signing input from fields, and verifies that
// signature authenticates the request.
//
// The base64 string form matches how a backend hands the client public key
// back to the gateway after device-session resolution
// (see docs/ARCHITECTURE.md §15).
func VerifyRequestSignature(clientPublicKey string, signature []byte, fields RequestSigningFields) error {
publicKey, err := decodeClientPublicKey(clientPublicKey)
if err != nil {
return err
}
if len(signature) != ed25519.SignatureSize {
return ErrInvalidRequestSignature
}
if !ed25519.Verify(publicKey, BuildRequestSigningInput(fields), signature) {
return ErrInvalidRequestSignature
}
return nil
}
func decodeClientPublicKey(value string) (ed25519.PublicKey, error) {
decoded, err := base64.StdEncoding.Strict().DecodeString(value)
if err != nil {
return nil, ErrInvalidClientPublicKey
}
if len(decoded) != ed25519.PublicKeySize {
return nil, ErrInvalidClientPublicKey
}
return ed25519.PublicKey(decoded), nil
}