siggraph

package
v0.0.0-...-d5168a5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 3, 2024 License: MIT Imports: 8 Imported by: 1

README

Signature Graph

Features

  • Operations to add and revoke keys are chained together with signatures
  • Add and Revoke multiple keys in a single transaction
  • Retroactive Revocation of device keys
  • Implicit revocation of all existing keys when recovering an account
  • Graphviz output of the key graph

Design

Keys are added and revoked from an identity through a series of operations, which can each have a number of different actions that add and revoke public keys. The current state of an identity is represented as a list of json web signatures. Each addition to the list includes in its payload the signature of its predecessor.

An identities representation will be stored on the chain as follows. Each JWS represents an operation that may contain a number of actions that add or revoke keys.

{
    "id": "1234567890",
    "history": [
        {
            "protected": "signed-header",
            "payload": "signed-payload",
            "signature": "signature"
        },
        {
            "protected": "signed-header",
            "payload": "signed-payload",
            "signature": "signature"
        },
        {
            "protected": "signed-header",
            "payload": "signed-payload",
            "signature": "signature"
        }
    ]
}
Protected Header

Each protected header will contain the following:

{
    "alg": "EdDSA",
    "kid": "key-identifier"
}

It denotes the algorithm and ID of the key used to sign the operation. For the first (root) operation in a tree, it will be self signed.

Payload/Operation

Each payload will represent an operation on the identity:

{
    "sequence": 0,
    "previous": "-",
    "timestamp": 1597315919,
    "actions": [
        {
            "kid": "0",
            "type": "device.key",
            "action": "key.add",
            "effective_from": 1597315919,
            "key": "w9U2Wbf3IvP8tq4tGa9m1AFqkRjCf8NLwZvKwOfAaGg"
        },
        {
            "kid": "1",
            "type": "recovery.key",
            "action": "key.add",
            "effective_from": 1597315919,
            "key": "8OKgkjZh73vqWbdq_wLlo307FwZVC8ld29B0nRIfCh8"
        }
    ]
}

An operation defines a sequence, which denotes the order that the operation appears in. This is an monotonically increasing number, starting from 0.

The previous field is used to specify the signature of the previous operation. For the first operation in the identites history, this will be set to -.

Every operation should include a unix timestamp of the time when the request was issued.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// TypeDeviceKey the type of key the action relates to
	TypeDeviceKey = "device.key"
	// TypeRecoveryKey the type of key the action relates to
	TypeRecoveryKey = "recovery.key"

	// ActionKeyAdd adds a key to the signature graph
	ActionKeyAdd = "key.add"
	// ActionKeyRevoke revokes a key from the signature graph
	ActionKeyRevoke = "key.revoke"
)
View Source
var (
	// ErrSequenceOutOfOrder returned when an operation's sequence number in the history log is out of order
	ErrSequenceOutOfOrder = errors.New("signature graph contains an operation sequence that is out of order")
	// ErrInvalidPreviousSignature returned when an operation specifies the signature of an invalid or non-existent previous operation
	ErrInvalidPreviousSignature = errors.New("signature graph contains an operation that specifies an invalid previous operatation signature")
	// ErrInvalidTimestamp returned when an operations timestamp has not increased from the previous operation
	ErrInvalidTimestamp = errors.New("signature graph contains an operation with a timestamp that is the same or before the previous operations timestamp")
	// ErrInvalidSigningKey returned when an operation is signed with a key that is invalid or does not exist
	ErrInvalidSigningKey = errors.New("signature graph contains an operation that has been signed with a key that cannot be found")
	// ErrInvalidOperationSignature returned when the signature of an operation was not signed with the specified key
	ErrInvalidOperationSignature = errors.New("signature graph contains an operation that has an invalid signature")
	// ErrOperationNOOP returned when an operation specifies no valid actions
	ErrOperationNOOP = errors.New("signature graph contains an operation with no valid actions")
	// ErrInvalidKeyEncoding returned when an operations action contains a key that has not been correctly encoded
	ErrInvalidKeyEncoding = errors.New("signature graph contains an operation action that specifies an badly encoded key")
	// ErrKeyDuplicate returned when more than one key is added with the same key identifier
	ErrKeyDuplicate = errors.New("signature graph contains an operation action that creates a key with the same identifier as an existing key")
	// ErrKeyMissing returned when an action references a key that does not exist
	ErrKeyMissing = errors.New("signature graph contains an operation action that references an existing key that does not exist")
	// ErrKeyAlreadyRevoked returned when an action attempts to revoke a key that has already been revoked
	ErrKeyAlreadyRevoked = errors.New("signature graph contains an operation action that revokes an already revoked key")
	// ErrInvalidKeyRevocation returned when the first operation in the history log attempts to revoke a key
	ErrInvalidKeyRevocation = errors.New("signature graph root operation contains an invalid key revocation")
	// ErrSignatureKeyRevoked returned when the operation was signed by a key that was either not created or revoked at the time the signature was made
	ErrSignatureKeyRevoked = errors.New("signature graph contains an operation that was signed with a key that was invalid for that time period")
	// ErrMultipleActiveDeviceKeys returned when an identity has more than one active key for a device
	ErrMultipleActiveDeviceKeys = errors.New("signature graph contains more than one active key for a given device")
	// ErrMultipleActiveRecoveryKeys returned when an identity has more than one active recovery keys
	ErrMultipleActiveRecoveryKeys = errors.New("signature graph contains more than one active recovery key")
	// ErrInvalidAccountRecoveryAction returned when the first action in an operation that is an account recovery does not revoke the existing recovery key
	ErrInvalidAccountRecoveryAction = errors.New("signature graph contains an account recovery operation that does not invalidate the existing recovery key")
	// ErrInvalidActionKeyID returned when an action does not contain a valid key identifier
	ErrInvalidActionKeyID = errors.New("action contains an invalid key identifier")
	// ErrUnknownActionType returned when an action is not of a known type
	ErrUnknownActionType = errors.New("action contains an invalid action type")
	// ErrUnknownAction returned when the specified action is not valid
	ErrUnknownAction = errors.New("action is not valid")
	// ErrInvalidActionKey returned when the action provides an invalid or empty key
	ErrInvalidActionKey = errors.New("action must specify a valid public key")
	// ErrInvalidActionDID returned when the action does not provide a valid device identifier
	ErrInvalidActionDID = errors.New("action must specify a valid device identifier")
	// ErrInvalidActionEffectiveFromTime returned when the unix timestamp for when the action takes effect is not provided
	ErrInvalidActionEffectiveFromTime = errors.New("action must specify when a time the action takes effect from")
	// ErrNoValidRecoveryKey returned when there are no valid recovery keys on the graph
	ErrNoValidRecoveryKey = errors.New("signature graph contains no active recovery keys")
	// ErrNoValidKeys returned when there are no valid or active keys on the graph
	ErrNoValidKeys = errors.New("signature graph contains no active or valid keys")
	// ErrInvalidPublicKeyEncoding is returned when the identities public key is not valid base64
	ErrInvalidPublicKeyEncoding = errors.New("identity public key is not a valid base64 url encoded string")
	// ErrInvalidPublicKeyLength is returned when a specfied public key's length is less than 32
	ErrInvalidPublicKeyLength = errors.New("specified public key length is invalid")
	// ErrInvalidOperationVersion is returned when an operation does not specify a valid version
	ErrInvalidOperationVersion = errors.New("signature graph contains an operation that does not contain a valid version")
	// ErrKeyNotFound returned when the caller asks for a key that cannot be found on the graph
	ErrKeyNotFound = errors.New("signature graph does not contain a key with the specified identifier")
	// ErrDeviceNotFound returned when the caller asks for a device that cannot be found on the graph
	ErrDeviceNotFound = errors.New("signature graph does not contain a device with the specified identifier")
	// ErrKeyRevoked returned when the caller asks for a key that has been revoked
	ErrKeyRevoked = errors.New("the specified key has been revoked")
	// ErrNotDeviceKey returned when the caller asks for a device ID by it's key identifier, but the key is not a device key
	ErrNotDeviceKey = errors.New("the specified key identifier is not a device key")
)

Functions

This section is empty.

Types

type Action

type Action struct {
	KID           string `json:"kid"`           // the unique id of the key the action relates to
	DID           string `json:"did,omitempty"` // the id of the device the key relates to
	Type          string `json:"type"`          // type of key [device.key, recovery.key]
	Action        string `json:"action"`        // action to perform [key.add, key.revoke]
	EffectiveFrom int64  `json:"from"`          // determines the time at which the action should be valid from. This could be set in the past when wishing to revoke a key from a given time onward
	Key           string `json:"key,omitempty"` // the ed25519 public key (base64 url encoded)
}

Action defines configuration for an action to perform on the identities signature graph

func (*Action) Validate

func (a *Action) Validate() error

Validate validates an actions parameters

type Header struct {
	Algorithm string `json:"alg"`
	KeyID     string `json:"kid"`
}

Header represents a jws header

type JWS

type JWS struct {
	Payload   string `json:"payload"`
	Protected string `json:"protected"`
	Signature string `json:"signature"`
}

JWS stores a single signature jws object

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node node

type Operation

type Operation struct {
	Sequence  int      `json:"sequence"`  // sequence id
	Previous  string   `json:"previous"`  // signature of the previous operation
	Version   string   `json:"version"`   // the version of operation
	Timestamp int64    `json:"timestamp"` // unix timestamp
	Actions   []Action `json:"actions"`   // list of actionable operations
	// contains filtered or unexported fields
}

Operation represents a set of actions to perform An operation can contain a number of actions that add and revoke keys of different types

func ParseOperation

func ParseOperation(operation json.RawMessage) (*Operation, error)

ParseOperation parses a jws object into an operation

func (*Operation) ActionByKID

func (o *Operation) ActionByKID(kid string) *Action

ActionByKID gets the action by its key identifier

func (*Operation) SignatureKeyID

func (o *Operation) SignatureKeyID() string

SignatureKeyID returns the key identifier for the key that signed the request

func (*Operation) Verify

func (o *Operation) Verify(key ed25519.PublicKey) error

Verify validates the signature of an operation with an ed25519 key

type SignatureGraph

type SignatureGraph struct {
	// contains filtered or unexported fields
}

SignatureGraph creates a signature graph

func New

func New(history []json.RawMessage) (*SignatureGraph, error)

New creates a new signature graph from an identities history

func (*SignatureGraph) ActiveDevice

func (s *SignatureGraph) ActiveDevice(did string) (ed25519.PublicKey, error)

ActiveDevice gets an active/valid key for a given device identifier. An error will be returned if the key has been revoked

func (*SignatureGraph) ActiveKey

func (s *SignatureGraph) ActiveKey(kid string) (ed25519.PublicKey, error)

ActiveKey gets an active/valid key by its identifier. An error will be returned if the key has been revoked

func (*SignatureGraph) CreatedAt

func (s *SignatureGraph) CreatedAt(kid string) (int64, error)

CreatedAt returns the time a key was created

func (*SignatureGraph) Devices

func (s *SignatureGraph) Devices() []string

Devices returns the ID of all devices, both active and revoked

func (*SignatureGraph) Execute

func (s *SignatureGraph) Execute(operation json.RawMessage) error

Execute executes an operation on the signature graph

func (*SignatureGraph) GetDeviceID

func (s *SignatureGraph) GetDeviceID(kid string) (string, error)

GetDeviceID gets a device ID from a key ID

func (*SignatureGraph) GetKeyID

func (s *SignatureGraph) GetKeyID(did string) (string, error)

GetKeyID gets a key ID from a device ID

func (*SignatureGraph) Graphviz

func (s *SignatureGraph) Graphviz() string

Graphviz outputs the signature graph in graphviz dot format

func (*SignatureGraph) IsKeyValid

func (s *SignatureGraph) IsKeyValid(kid string, at time.Time) bool

IsKeyValid checks if a key was valid for a given period of time

func (*SignatureGraph) Key

func (s *SignatureGraph) Key(kid string) (ed25519.PublicKey, error)

Key gets a device public key key by its identifier

func (*SignatureGraph) Keys

func (s *SignatureGraph) Keys() []string

Keys returns the ID of all keys, both active and revoked

func (*SignatureGraph) NextSequence

func (s *SignatureGraph) NextSequence() int

NextSequence returns the next sequence a new operation should specify

func (*SignatureGraph) PreviousSignature

func (s *SignatureGraph) PreviousSignature() string

PreviousSignature returns the signature of the last operation

func (*SignatureGraph) RevokedAt

func (s *SignatureGraph) RevokedAt(kid string) (int64, error)

RevokedAt returns the time a key was revoked. If the key has not been revoked, the returned timestamp will be 0

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL