protocol

package
v0.0.0-...-f4f6315 Latest Latest
Warning

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

Go to latest
Published: Apr 5, 2018 License: BSD-3-Clause Imports: 10 Imported by: 0

Documentation

Overview

Package protocol is a library for building compatible CONIKS clients and servers.

protocol implements the server- and client-side components of the CONIKS key management and verification protocols. More specifically, protocol provides an API for maintaining an auditable, privacy-preserving key directory on a server, as well as an API for checking the consistency of the directory at the client.

Consistency Checks

This module implements all consistency checks performed by a CONIKS client on directory proofs received from a CONIKS server. These operations include the verification of username-to-key bindings (authentication paths), and non-equivocation checks (signed tree roots).

Directory

This module implements a CONIKS key directory that a CONIKS key server maintains. A directory is a publicly auditable, tamper-evident, privacy-preserving data structure that contains mappings from usernames to public keys. It currently supports registration of new mappings, latest-version key lookups, historical key lookups, and monitoring of mappings.

Error

This module defines the constants representing the types of errors that a CONIKS server may return to a client, and the results of a consistency check or a cryptographic verification that a CONIKS client performs.

Message

This module defines the message format of the CONIKS client requests and corresponding CONIKS server responses for each CONIKS protocol. It also provides constructors for the response messages for each protocol.

Policy

This module defines the directory's current CONIKS security/privacy policies, which include the public part of the VRF key used to generate private indices, the cryptographic algorithms in use, as well as the protocol version number.

Temporary Binding

This module implements a temporary binding, which serves both as a proof of registration with a directory and as a signed promise by a CONIKS server to include the corresponding name-to-key binding in the next directory snapshot. As such, TBs allow clients to begin using a newly registered name-to-key binding for encryption/signing immediately without having to wait for the binding's inclusion in the next snapshot. However, clients must still check in the next epoch that the binding has been included in the snapshot to ensure that the server has not equivocated about it.

Index

Constants

View Source
const (
	RegistrationType = iota
	KeyLookupType
	KeyLookupInEpochType
	MonitoringType
)

The types of requests CONIKS clients send during the CONIKS protocols.

View Source
const (
	// Version indicates the current protocol version.
	Version = "0.3"
)

Variables

Errors contains codes indicating the client should skip the consistency checks. These errors indicate that either a client request could not be processed due to a malformed client request, an internal server error or due to a malformed server response.

Functions

func NewKeyLookupInEpochProof

func NewKeyLookupInEpochProof(ap *m.AuthenticationPath,
	str []*DirSTR, e ErrorCode) (*Response, ErrorCode)

NewKeyLookupInEpochProof creates the response message a CONIKS directory sends to a client upon a KeyLookupRequest, and returns a Response containing a DirectoryProofs struct. directory.KeyLookupInEpoch() passes an authentication path ap and error code e according to the result of the lookup, and a list of signed tree roots for the requested range of epochs str.

See directory.KeyLookupInEpoch() for details on the contents of the created DirectoryProofs.

func NewKeyLookupProof

func NewKeyLookupProof(ap *m.AuthenticationPath, str *DirSTR,
	tb *TemporaryBinding, e ErrorCode) (*Response, ErrorCode)

NewKeyLookupProof creates the response message a CONIKS directory sends to a client upon a KeyLookupRequest, and returns a Response containing a DirectoryProof struct. directory.KeyLookup() passes an authentication path ap, temporary binding tb and error code e according to the result of the key lookup, and the signed tree root for the latest epoch str.

See directory.KeyLookup() for details on the contents of the created DirectoryProof.

func NewMonitoringProof

func NewMonitoringProof(ap []*m.AuthenticationPath,
	str []*DirSTR) (*Response, ErrorCode)

NewMonitoringProof creates the response message a CONIKS directory sends to a client upon a MonitoringRequest, and returns a Response containing a DirectoryProofs struct. directory.Monitor() passes a list of authentication paths ap and a list of signed tree roots for the requested range of epochs str.

See directory.Monitor() for details on the contents of the created DirectoryProofs.

func NewRegistrationProof

func NewRegistrationProof(ap *m.AuthenticationPath, str *DirSTR,
	tb *TemporaryBinding, e ErrorCode) (*Response, ErrorCode)

NewRegistrationProof creates the response message a CONIKS directory sends to a client upon a RegistrationRequest, and returns a Response containing a DirectoryProof struct. directory.Register() passes an authentication path ap, temporary binding tb and error code e according to the result of the registration, and the signed tree root for the latest epoch str.

See directory.Register() for details on the contents of the created DirectoryProof.

Types

type ConiksDirectory

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

A ConiksDirectory maintains the underlying persistent authenticated dictionary (PAD) and its policies (i.e. epoch deadline, VRF public key, etc.).

The current implementation of ConiksDirectory also keeps track of temporary bindings (TBs). This feature may be split into a separate protocol extension in a future release.

func NewDirectory

func NewDirectory(epDeadline Timestamp, vrfKey vrf.PrivateKey,
	signKey sign.PrivateKey, dirSize uint64, useTBs bool) *ConiksDirectory

NewDirectory constructs a new ConiksDirectory given the key server's PAD policies (i.e. epDeadline, vrfKey).

signKey is the private key the key server uses to generate signed tree roots (STRs) and TBs. dirSize indicates the number of PAD snapshots the server keeps in memory. useTBs indicates whether the key server returns TBs upon a successful registration.

func NewTestDirectory

func NewTestDirectory(t *testing.T, useTBs bool) (
	*ConiksDirectory, sign.PublicKey)

NewTestDirectory creates a ConiksDirectory used for testing server-side CONIKS operations.

func (*ConiksDirectory) EpochDeadline

func (d *ConiksDirectory) EpochDeadline() Timestamp

EpochDeadline returns this ConiksDirectory's latest epoch deadline as a timestamp.

func (*ConiksDirectory) KeyLookup

func (d *ConiksDirectory) KeyLookup(req *KeyLookupRequest) (
	*Response, ErrorCode)

KeyLookup gets the public key for the username indicated in the KeyLookupRequest req received from a CONIKS client from the latest snapshot of this ConiksDirectory, and returns a tuple of the form (response, error). The response (which also includes the error code) is supposed to be sent back to the client. The returned error is used by the key server for logging purposes.

A request without a username is considered malformed, and causes KeyLookup() to return a message.NewErrorResponse(ErrMalformedClientMessage) tuple. If the username doesn't have an entry in the latest directory snapshot and also isn't pending registration (i.e. has a corresponding TB), KeyLookup() returns a message.NewKeyLookupProof(ap=proof of absence, str, nil, ReqNameNotFound) tuple. Otherwise, KeyLookup() returns a message.NewKeyLookupProof(ap=proof of absence, str, tb, ReqSuccess) tuple if there is a corresponding TB for the username, but there isn't an entry in the directory yet, and a a message.NewKeyLookupProof(ap=proof of inclusion, str, nil, ReqSuccess) if there is. In any case, str is the signed tree root for the latest epoch. If KeyLookup() encounters an internal error at any point, it returns a message.NewErrorResponse(ErrDirectory) tuple.

func (*ConiksDirectory) KeyLookupInEpoch

func (d *ConiksDirectory) KeyLookupInEpoch(req *KeyLookupInEpochRequest) (
	*Response, ErrorCode)

KeyLookupInEpoch gets the public key for the username for a prior epoch in the directory history indicated in the KeyLookupInEpochRequest req received from a CONIKS client, and returns a tuple of the form (response, error). The response (which also includes the error code) is supposed to be sent back to the client. The returned error is used by the key server for logging purposes.

A request without a username or with an epoch greater than the latest epoch of this directory is considered malformed, and causes KeyLookupInEpoch() to return a message.NewErrorResponse(ErrMalformedClientMessage) tuple. If the username doesn't have an entry in the directory snapshot for the indicated epoch, KeyLookupInEpoch() returns a message.NewKeyLookupInEpochProof(ap=proof of absence, str, ReqNameNotFound) tuple. Otherwise, KeyLookupInEpoch() returns a message.NewKeyLookupInEpochProof(ap=proof of inclusion, str, ReqSuccess) tuple. In either case, str is a list of STRs for the epoch range [ep, d.LatestSTR().Epoch], where ep is the past epoch for which the client has requested the user's key. KeyLookupInEpoch() proofs do not include temporary bindings since the TB corresponding to a registered binding is discarded at the time the binding is included in a directory snapshot. If KeyLookupInEpoch() encounters an internal error at any point, it returns a message.NewErrorResponse(ErrDirectory) tuple.

func (*ConiksDirectory) LatestSTR

func (d *ConiksDirectory) LatestSTR() *DirSTR

LatestSTR returns this ConiksDirectory's latest STR.

func (*ConiksDirectory) Monitor

func (d *ConiksDirectory) Monitor(req *MonitoringRequest) (
	*Response, ErrorCode)

Monitor gets the directory proofs for the username for the range of epochs indicated in the MonitoringRequest req received from a CONIKS client, and returns a tuple of the form (response, error). The response (which also includes the error code) is supposed to be sent back to the client. The returned error is used by the key server for logging purposes.

A request without a username, with a start epoch greater than the latest epoch of this directory, or a start epoch greater than the end epoch is considered malformed, and causes Monitor() to return a message.NewErrorResponse(ErrMalformedClientMessage) tuple. Monitor() returns a message.NewMonitoringProof(ap, str) tuple. ap is a list of proofs of inclusion, and str is a list of STRs for the epoch range [startEpoch, endEpoch], where startEpoch and endEpoch are the epoch range endpoints indicated in the client's request. If req.endEpoch is greater than d.LatestSTR().Epoch, the end of the range will be set to d.LatestSTR().Epoch. If Monitor() encounters an internal error at any point, it returns a message.NewErrorResponse(ErrDirectory) tuple.

func (*ConiksDirectory) NewTB

func (d *ConiksDirectory) NewTB(name string, key []byte) *TemporaryBinding

NewTB creates a new temporary binding for the given name-to-key mapping. NewTB() computes the private index for the name, and digitally signs the (index, key, latest STR signature) tuple.

func (*ConiksDirectory) Register

func (d *ConiksDirectory) Register(req *RegistrationRequest) (
	*Response, ErrorCode)

Register inserts the username-to-key mapping contained in a RegistrationRequest req received from a CONIKS client into this ConiksDirectory, and returns a tuple of the form (response, error). The response (which also includes the error code) is supposed to be sent back to the client. The returned error is used by the key server for logging purposes.

A request without a username or without a public key is considered malformed, and causes Register() to return a message.NewErrorResponse(ErrMalformedClientMessage) tuple. Register() inserts the new mapping in req into a pending version of the directory so it can be included in the snapshot taken at the end of the latest epoch, and returns a message.NewRegistrationProof(ap=proof of absence, str, tb, ReqSuccess) tuple if this operation succeeds. Otherwise, if the username already exists, Register() returns a message.NewRegistrationProof(ap=proof of inclusion, str, nil, ReqNameExisted) tuple. ap will be a proof of absence with a non-nil TB, if the username is still pending inclusion in the next directory snapshot. In any case, str is the signed tree root for the latest epoch. If Register() encounters an internal error at any point, it returns a message.NewErrorResponse(ErrDirectory) tuple.

func (*ConiksDirectory) SetPolicies

func (d *ConiksDirectory) SetPolicies(epDeadline Timestamp)

SetPolicies sets this ConiksDirectory's epoch deadline, which will be used in the next epoch.

func (*ConiksDirectory) Update

func (d *ConiksDirectory) Update()

Update creates a new PAD snapshot updating this ConiksDirectory. Update() is called at the end of a CONIKS epoch. This implementation also deletes all issued TBs for the ending epoch as their corresponding mappings will have been inserted into the PAD.

type ConsistencyChecks

type ConsistencyChecks struct {
	// SavedSTR stores the latest verified signed tree root.
	SavedSTR *DirSTR
	Bindings map[string][]byte

	TBs map[string]*TemporaryBinding
	// contains filtered or unexported fields
}

ConsistencyChecks stores the latest consistency check state of a CONIKS client. This includes the latest SignedTreeRoot, all the verified name-to-key bindings of the client, as well as a directory's policies (e.g., whether the TemporaryBinding extension is being used).

The client should create a new ConsistencyChecks instance only once, when it registers its user's binding with a ConiksDirectory. This ConsistencyChecks instance will then be used to verify subsequent responses from the ConiksDirectory to any client request.

func NewCC

func NewCC(savedSTR *DirSTR, useTBs bool, signKey sign.PublicKey) *ConsistencyChecks

NewCC creates an instance of ConsistencyChecks using a CONIKS directory's pinned STR at epoch 0, or the consistency state read from persistent storage.

func (*ConsistencyChecks) HandleResponse

func (cc *ConsistencyChecks) HandleResponse(requestType int, msg *Response,
	uname string, key []byte) ErrorCode

HandleResponse verifies the directory's response for a request. It first verifies the directory's returned status code of the request. If the status code is not in the Errors array, it means the directory has successfully handled the request. The verifier will then check the consistency (i.e. binding validity and non-equivocation) of the response.

HandleResponse() will panic if it is called with an int that isn't a valid/known request type.

Note that the consistency state will be updated regardless of whether the checks pass / fail, since a response message contains cryptographic proof of having been issued nonetheless.

type DirSTR

type DirSTR struct {
	*merkletree.SignedTreeRoot
	Policies *Policies
}

DirSTR disambiguates merkletree.SignedTreeRoot's AssocData interface, for the purpose of exporting and unmarshalling.

func NewDirSTR

func NewDirSTR(str *merkletree.SignedTreeRoot) *DirSTR

NewDirSTR constructs a new DirSTR from a merkletree.SignedTreeRoot

func (*DirSTR) Serialize

func (str *DirSTR) Serialize() []byte

Serialize overrides merkletree.SignedTreeRoot.Serialize

func (*DirSTR) VerifyHashChain

func (str *DirSTR) VerifyHashChain(savedSTR *DirSTR) bool

VerifyHashChain wraps merkletree.SignedTreeRoot.VerifyHashChain

type DirectoryProof

type DirectoryProof struct {
	AP  *m.AuthenticationPath
	STR *DirSTR
	TB  *TemporaryBinding `json:",omitempty"`
}

A DirectoryProof response includes an authentication path AP for a given username-to-key binding in the directory, a signed tree root STR, and optionally a temporary binding for the given binding for a single epoch. A CONIKS directory returns this DirectoryResponse type upon a RegistrationRequest or a KeyLookupRequest.

type DirectoryProofs

type DirectoryProofs struct {
	AP  []*m.AuthenticationPath
	STR []*DirSTR
}

A DirectoryProofs response includes a list of authentication paths AP for a given username-to-key binding in the directory and a list of signed tree roots STR for a range of epochs. A CONIKS directory returns this DirectoryResponse type upon a KeyLookupInEpochRequest or a MonitoringRequest.

type DirectoryResponse

type DirectoryResponse interface{}

A DirectoryResponse is a message that includes cryptographic proofs about the key directory that a CONIKS key directory returns to a CONIKS client.

type ErrorCode

type ErrorCode int

An ErrorCode implements the built-in error interface type.

const (
	ReqSuccess ErrorCode = iota + 100
	ReqNameExisted
	ReqNameNotFound

	ErrDirectory
	ErrMalformedClientMessage
	ErrMalformedDirectoryMessage
)

These codes indicate the status of a client-server message exchange. Codes prefixed by "Req" indicate different client request results. Codes prefixed by "Err" indicate an internal server error or a malformed message.

const (
	CheckPassed ErrorCode = iota + 200
	CheckBadSignature
	CheckBadVRFProof
	CheckBindingsDiffer
	CheckBadCommitment
	CheckBadLookupIndex
	CheckBadAuthPath
	CheckBadSTR
	CheckBadPromise
	CheckBrokenPromise
)

These codes indicate the result of a consistency check or cryptographic verification. These codes are prefixed by "Check".

func (ErrorCode) Error

func (e ErrorCode) Error() string

Error returns the error message corresponding to the error code e.

type KeyLookupInEpochRequest

type KeyLookupInEpochRequest struct {
	Username string
	Epoch    uint64
}

A KeyLookupInEpochRequest is a message with a username as a string and an epoch as a uint64 that a CONIKS client sends to the directory to retrieve the public key bound to the username in the given epoch. The client sends this request type when it needs to obtain a user's key for a past epoch. The client can send a KeyLookupRequest if it needs to look up a user's key for the latest epoch.

The response to a successful request is a DirectoryProofs with an AP of length 1 containing the auth path for the requested Epoch, and a list of STRs covering the epoch range [Epoch, d.LatestSTR().Epoch].

type KeyLookupRequest

type KeyLookupRequest struct {
	Username string
}

A KeyLookupRequest is a message with a username as a string that a CONIKS client sends to a CONIKS directory to retrieve the public key bound to the given username at the latest epoch. If the client needs to look up a username's key for a prior epoch, it must send a KeyLookupInEpochRequest.

The response to a successful request is a DirectoryProof with a TB if the requested username was registered during the latest epoch (i.e. the new binding hasn't been committed to the directory).

type MonitoringRequest

type MonitoringRequest struct {
	Username   string
	StartEpoch uint64
	EndEpoch   uint64
}

A MonitoringRequest is a message with a username as a string and the start and end epochs of an epoch range as two uint64 that a CONIKS client sends to the directory to monitor the given user's key in a CONIKS key directory, i.e. to ensure that the key bound to the username hasn't changed unexpectedly.

If the client needs to check the consistency of a user's binding for a range of epochs (e.g. if the client went offline for several epochs and was unable to monitor its user's binding during that period), it indicates the beginning of the range with the start epoch, and the end of the range with the end epoch. An end epoch with a value greater than the key directory's latest epoch sets the end of the epoch range at the directory's latest epoch.

Specifically, there are two cases for doing monitoring: prior history verification which can be used to verify the absence of the binding before registration, and name-to-key binding monitoring which can be used to verify the inclusion of the binding after registration.

type Policies

type Policies struct {
	Version       string
	HashID        string
	VrfPublicKey  vrf.PublicKey
	EpochDeadline Timestamp
}

Policies is a summary of the directory's current CONIKS security/privacy policies. This includes the public part of the VRF key used to generate private indices, the cryptographic algorithms in use, as well as the protocol version number.

func GetPolicies

func GetPolicies(str *merkletree.SignedTreeRoot) *Policies

GetPolicies returns the set of policies included in the STR.

func NewPolicies

func NewPolicies(epDeadline Timestamp, vrfPublicKey vrf.PublicKey) *Policies

NewPolicies returns a new Policies with the given epoch deadline and public VRF key.

func (*Policies) Serialize

func (p *Policies) Serialize() []byte

Serialize serializes the policies for signing the tree root. Default policies serialization includes the library version (see version.go), the cryptographic algorithms in use (i.e., the hashing algorithm), the epoch deadline and the public part of the VRF key.

type RegistrationRequest

type RegistrationRequest struct {
	Username               string
	Key                    []byte
	AllowUnsignedKeychange bool `json:",omitempty"`
	AllowPublicLookup      bool `json:",omitempty"`
}

A RegistrationRequest is a message with a username as a string and a public key as bytes that a CONIKS client sends to a CONIKS directory to register a new entry (i.e. name-to-key binding). Optionally, the client can include the user's key change and visibility policies as boolean values in the request. These flags are currently unused by the CONIKS protocols.

The response to a successful request is a DirectoryProof with a TB for the requested username and public key.

type Request

type Request struct {
	Type    int
	Request interface{}
}

A Request message defines the data a CONIKS client must send to a CONIKS directory for a particular request.

type Response

type Response struct {
	Error             ErrorCode
	DirectoryResponse `json:",omitempty"`
}

A Response message indicates the result of a CONIKS client request with an appropriate error code, and defines the set of cryptographic proofs a CONIKS directory must return as part of its response.

func NewErrorResponse

func NewErrorResponse(e ErrorCode) *Response

NewErrorResponse creates a new response message indicating the error that occurred while a CONIKS directory was processing a client request.

func (*Response) GetKey

func (msg *Response) GetKey() ([]byte, error)

GetKey returns the key extracted from a validated CONIKS directory's response.

If the response contains a single authentication path, the key is obtained from that authentication path or the temporary binding, depending on the returned proof type.

If the response contains a range of authentication paths, the key is obtained from the authentication path corresponding to the most recent signed tree root.

type TemporaryBinding

type TemporaryBinding struct {
	Index     []byte
	Value     []byte
	Signature []byte
}

A TemporaryBinding consists of the private Index for a username, the Value (i.e. public key etc.) mapped to this index in a key directory, and a digital Signature of these fields.

A TB serves as a proof of registration and as a signed promise by a CONIKS server to include the corresponding name-to-key binding in the next directory snapshot. As such, TBs allow clients to begin using the contained name-to-key binding for encryption/signing without having to wait for the binding's inclusion in the next snapshot.

func (*TemporaryBinding) Serialize

func (tb *TemporaryBinding) Serialize(strSig []byte) []byte

Serialize serializes the temporary binding into a specified format.

type Timestamp

type Timestamp uint64

Timestamp is used for defining a CONIKS server's epoch deadline.

Jump to

Keyboard shortcuts

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