Documentation
¶
Overview ¶
Package quorum verifies signatures returned by upstream providers when a client requests quorum reads (via quorum=N&quorum_required=n query params).
Each participating upstream returns a header in the strict form:
QR<N>-id-<request-id>: <provider-id>(<upstream-id>)_nonce_<nonce>_sig_<hex-signature>
All four components are required. The <provider-id> (before the parentheses) is used to look up the public key in provider_keys.yaml. The <upstream-id> (inside the parentheses) is the dshackle `source` and is what the signature is actually computed over. Any header whose value does not match this exact shape is rejected as malformed.
The signed message is produced with one of:
- SHA256withECDSA over NIST P-256 (signature is DER-encoded ASN.1), or
- SHA256withRSA / PKCS#1 v1.5 (signature is a fixed-size integer block)
over the string "DSHACKLESIG/<nonce>/<upstream-id>/<hex(sha256(result))>". The concrete algorithm is inferred from the type of the public key loaded from provider_keys.yaml.
Index ¶
- Variables
- func ToResponseError(err error) *protocol.ResponseError
- func WithParams(ctx context.Context, p Params) context.Context
- func WrapMessage(nonce uint64, source string, message []byte) []byte
- type InsufficientSignaturesError
- type InvalidSignatureError
- type MalformedHeaderError
- type NotSupportedError
- type Params
- type Registry
- func (r *Registry) Len() int
- func (r *Registry) Lookup(providerID string) (crypto.PublicKey, bool)
- func (r *Registry) Verify(providerID, upstreamID string, nonce uint64, signature, message []byte) error
- func (r *Registry) VerifyHeaders(headers http.Header, result []byte, expectedRequestID string, minRequired int) error
- type Signature
- type UnexpectedRequestIDError
- type UnknownProviderError
Constants ¶
This section is empty.
Variables ¶
var ( ErrMissingSignatures = errors.New("quorum: no QR signature headers present") ErrInsufficientSignatures = errors.New("quorum: not enough signatures returned") ErrUnknownProvider = errors.New("quorum: no public key for provider") ErrInvalidSignature = errors.New("quorum: signature verification failed") ErrMalformedHeader = errors.New("quorum: malformed QR header") ErrUnexpectedRequestID = errors.New("quorum: QR header request id does not match request") ErrNotSupported = errors.New("quorum: quorum is not supported for this request") )
Functions ¶
func ToResponseError ¶
func ToResponseError(err error) *protocol.ResponseError
func WrapMessage ¶
WrapMessage reproduces dshackle's ResponseSigner.wrapMessage: "DSHACKLESIG/<nonce>/<source>/<hex(sha256(message))>". `source` here is what dshackle passed as `source` — the upstream id (what's in parens in the QR header prefix).
Types ¶
type InsufficientSignaturesError ¶
InsufficientSignaturesError is returned when the upstream returned fewer valid signatures than the client required via `quorum_required`.
func (*InsufficientSignaturesError) Error ¶
func (e *InsufficientSignaturesError) Error() string
func (*InsufficientSignaturesError) Is ¶
func (e *InsufficientSignaturesError) Is(target error) bool
type InvalidSignatureError ¶
InvalidSignatureError is returned when a QR signature does not verify against the provider's public key and the response body.
func (*InvalidSignatureError) Error ¶
func (e *InvalidSignatureError) Error() string
func (*InvalidSignatureError) Is ¶
func (e *InvalidSignatureError) Is(target error) bool
func (*InvalidSignatureError) Unwrap ¶
func (e *InvalidSignatureError) Unwrap() error
type MalformedHeaderError ¶
MalformedHeaderError is returned when a QR* header does not match the strict `<providerID>(<upstreamID>)_nonce_<n>_sig_<hex>` shape.
func (*MalformedHeaderError) Error ¶
func (e *MalformedHeaderError) Error() string
func (*MalformedHeaderError) Is ¶
func (e *MalformedHeaderError) Is(target error) bool
func (*MalformedHeaderError) Unwrap ¶
func (e *MalformedHeaderError) Unwrap() error
type NotSupportedError ¶
type NotSupportedError struct {
Reason string
}
NotSupportedError is returned when the current request shape cannot be served with quorum reads (no DRPC upstreams, sticky-send method, response is a stream, etc.). Propagated as-is to the client.
func (*NotSupportedError) Error ¶
func (e *NotSupportedError) Error() string
func (*NotSupportedError) Is ¶
func (e *NotSupportedError) Is(target error) bool
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
func DefaultRegistry ¶
func LoadRegistry ¶
func (*Registry) Lookup ¶
Lookup resolves a public key by provider_id taken verbatim from the QR header. Provider ids are fully-qualified as "<name>@<region>#<idx>", where <idx> is the 0-based position of the node inside its region in the provider-config. provider_keys.yaml is keyed in the exact same shape.
func (*Registry) Verify ¶
func (r *Registry) Verify(providerID, upstreamID string, nonce uint64, signature, message []byte) error
Verify is a low-level helper mainly useful in tests: callers usually go through VerifyHeaders which handles header parsing and the source vs provider-id split. `upstreamID` is the string dshackle fed to its signer as `source` — i.e. what's in parens in the QR header prefix.
func (*Registry) VerifyHeaders ¶
func (r *Registry) VerifyHeaders(headers http.Header, result []byte, expectedRequestID string, minRequired int) error
VerifyHeaders requires `result` to be the exact raw JSON-RPC "result" bytes the provider signed. `minRequired` is the client-supplied `quorum_required=` value; fewer valid signatures than this is rejected. When `expectedRequestID` is non-empty it is cross-checked against the id encoded in every QR header to reject cross-request signature replays. Returns nil only when every QR header is present, matches the expected request id, and verifies against the provider's public key.
type Signature ¶
type UnexpectedRequestIDError ¶
UnexpectedRequestIDError is returned when the request-id embedded in the QR header name does not match the actual JSON-RPC request id the gateway sent. This prevents an upstream from replaying signatures across requests.
func (*UnexpectedRequestIDError) Error ¶
func (e *UnexpectedRequestIDError) Error() string
func (*UnexpectedRequestIDError) Is ¶
func (e *UnexpectedRequestIDError) Is(target error) bool
type UnknownProviderError ¶
UnknownProviderError is returned when a QR header references a provider that is not present in the local keys registry.
func (*UnknownProviderError) Error ¶
func (e *UnknownProviderError) Error() string
func (*UnknownProviderError) Is ¶
func (e *UnknownProviderError) Is(target error) bool