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 }