authentication

package
v0.0.0-...-81a5b18 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2023 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Index

Examples

Constants

View Source
const SharedKeySizeBytes = 16

SharedKeySizeBytes is the length of the cryptographic key shared by a Signer and a Verifier.

Variables

View Source
var (
	// ErrInvalidPublicKey is an Error raised when a remote peer provides an invalid public key.
	ErrInvalidPublicKey = newError(errCodeBadParameter, "invalid public key")
	// ErrInvalidPrivateKey indicates the local peer tried to load an unsupported or malformed
	// private key.
	ErrInvalidPrivateKey = errors.New("invalid private key")
)
View Source
var (

	// ErrMetadataFieldTooLong indicates an authenticated field (such as a verifier name) is too
	// long to be compatible with the serialization format.
	ErrMetadataFieldTooLong = errors.New("metadata fields can't be more than 255 bytes long")
)

Functions

This section is empty.

Types

type Dispatcher

type Dispatcher struct {
	ECDHPrivateKey
}

Dispatcher facilitates creating connections to multiple vehicles using the same ECDHPrivateKey.

Example
const carCount = 10
const messagesPerCar = 5
var challenges [][]byte

// Create dispatcher
dispatcherPrivateKey, err := NewECDHPrivateKey(rand.Reader)
if err != nil {
	panic(fmt.Sprintf("Failed to generate dispatcher key: %s", err))
}
dispatcher := Dispatcher{dispatcherPrivateKey}
// Initialize cars, provision dispatcher public key
cars := make([]*Verifier, carCount)
for i := 0; i < carCount; i++ {
	vin := []byte(fmt.Sprintf("%d", i))
	VCSECKey, err := NewECDHPrivateKey(rand.Reader)
	var challenge [16]byte
	if _, err := rand.Read(challenge[:]); err != nil {
		panic(fmt.Sprintf("Failed to generate random challenge: %s", err))
	} else {
		challenges = append(challenges, challenge[:])
	}
	if err != nil {
		panic(fmt.Sprintf("Failed to generate car key: %s", err))
	}
	cars[i], err = NewVerifier(VCSECKey,
		vin, universal.Domain_DOMAIN_VEHICLE_SECURITY,
		dispatcherPrivateKey.PublicBytes())
	if err != nil {
		panic(fmt.Sprintf("Failed to initialize car: %s", err))
	}
}

message := &universal.RoutableMessage{
	ToDestination: &universal.Destination{
		SubDestination: &universal.Destination_Domain{Domain: universal.Domain_DOMAIN_VEHICLE_SECURITY},
	},
}
for i := 0; i < carCount; i++ {
	// Fetch session info from vehicle
	sessionInfo, tag, err := cars[i].SignedSessionInfo(challenges[i])
	if err != nil {
		panic(fmt.Sprintf("Error obtaining session info from car %d: %s", i, err))
	}
	// Give it to the signer (dispatcher). The UUID used to fetch the
	// session info can be used as the challenge.
	connection, err := dispatcher.ConnectAuthenticated(cars[i].verifierName, challenges[i], sessionInfo, tag)
	if err != nil {
		panic(fmt.Sprintf("Error creating authenticated connection to car %d: %s", i, err))
	}

	// Send several messages to vehicle using connection
	for j := 0; j < messagesPerCar; j++ {
		original := []byte(fmt.Sprintf("Message %d for car %d", j, i))
		message.Payload = &universal.RoutableMessage_ProtobufMessageAsBytes{ProtobufMessageAsBytes: original}
		if err := connection.Encrypt(message, time.Minute); err != nil {
			panic(fmt.Sprintf("Failed to encrypt message: %s", err))
		}

		// This won't happen if err above is nil, just here for illustrative purposes.
		if bytes.Equal(message.GetProtobufMessageAsBytes(), original) {
			panic("Message wasn't encrypted!")
		}

		if plaintext, err := cars[i].Verify(message); err != nil {
			panic(fmt.Sprintf("Decryption error :%s", err))
		} else if !bytes.Equal(plaintext, original) {
			panic("Failed to recover original plaintext")
		}
	}
}
Output:

func (*Dispatcher) Connect

func (d *Dispatcher) Connect(verifierId []byte, sessionInfo *signatures.SessionInfo) (*Signer, error)

func (*Dispatcher) ConnectAuthenticated

func (d *Dispatcher) ConnectAuthenticated(verifierId, challenge, encodedSessionInfo, tag []byte) (*Signer, error)

type ECDHPrivateKey

type ECDHPrivateKey interface {
	Exchange(remotePublicBytes []byte) (Session, error)
	PublicBytes() []byte
}

ECDHPrivateKey represents a local private key.

func LoadExternalECDHKey

func LoadExternalECDHKey(filename string) (ECDHPrivateKey, error)

func NewECDHPrivateKey

func NewECDHPrivateKey(rng io.Reader) (ECDHPrivateKey, error)

func UnmarshalECDHPrivateKey

func UnmarshalECDHPrivateKey(privateScalar []byte) ECDHPrivateKey

type Error

type Error struct {
	Code universal.MessageFault_E
	Info string
}

Error represents a protocol-layer error.

func (Error) Error

func (e Error) Error() string

type InvalidSignatureError

type InvalidSignatureError struct {
	Code        universal.MessageFault_E
	EncodedInfo []byte
	Tag         []byte
}

func (*InvalidSignatureError) Error

func (e *InvalidSignatureError) Error() string

type NativeECDHKey

type NativeECDHKey struct {
	*ecdsa.PrivateKey
}

func (*NativeECDHKey) Exchange

func (n *NativeECDHKey) Exchange(publicBytes []byte) (Session, error)

func (*NativeECDHKey) Public

func (n *NativeECDHKey) Public() *ecdsa.PublicKey

func (*NativeECDHKey) PublicBytes

func (n *NativeECDHKey) PublicBytes() []byte

type NativeSession

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

NativeSession implements the Session interface using native Go.

func (*NativeSession) Decrypt

func (b *NativeSession) Decrypt(nonce, ciphertext, associatedData, tag []byte) (plaintext []byte, err error)

func (*NativeSession) Encrypt

func (b *NativeSession) Encrypt(plaintext, associatedData []byte) (nonce, ciphertext, tag []byte, err error)

func (*NativeSession) LocalPublicBytes

func (b *NativeSession) LocalPublicBytes() []byte

func (*NativeSession) NewHMAC

func (b *NativeSession) NewHMAC(label string) hash.Hash

func (*NativeSession) SessionInfoHMAC

func (b *NativeSession) SessionInfoHMAC(id, challenge, encodedInfo []byte) ([]byte, error)

type Peer

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

A Peer is the parent type for Signer and Verifier.

type Session

type Session interface {
	// Returns the session info HMAC tag for encodedInfo. The challenge is a Signer-provided
	// anti-replay value.
	SessionInfoHMAC(id, challenge, encodedInfo []byte) ([]byte, error)
	// Encrypt plaintext and generate a tag that can be used to authenticate
	// the ciphertext and associated data. The tag and ciphertext are part of
	// the same slice, but returned separately for convenience.
	Encrypt(plaintext, associatedData []byte) (nonce, ciphertext, tag []byte, err error)
	// Authenticate a ciphertext and its associated data using the tag, then
	// decrypt it and return the plaintext.
	Decrypt(nonce, ciphertext, associatedData, tag []byte) (plaintext []byte, err error)
	// Return the encoded local public key.
	LocalPublicBytes() []byte
	// Returns a hash.Hash context that can be used as a KDF rooted in the shared secret.
	NewHMAC(label string) hash.Hash
}

A Session allows encrypting/decrypting/authenticating data using a shared ECDH secret.

type Signer

type Signer struct {
	Peer
	// contains filtered or unexported fields
}

Signers encrypt messages that are decrypted and verified by a designated Verifier. (Technically speaking, the name is a misnomer since Signers use symmetric-key operations following ECDH key agreement.)

func ImportSessionInfo

func ImportSessionInfo(private ECDHPrivateKey, verifierName, encodedInfo []byte, generatedAt time.Time) (*Signer, error)

ImportSessionInfo allows creation of a Signer with cached SessionInfo. This can be used to avoid a round trip with the Verifier.

func NewAuthenticatedSigner

func NewAuthenticatedSigner(private ECDHPrivateKey, verifierName, challenge, encodedInfo, tag []byte) (*Signer, error)

NewAuthenticatedSigner creates a Signer from encoded and cryptographically verified session info.

func NewSigner

func NewSigner(private ECDHPrivateKey, verifierName []byte, verifierInfo *signatures.SessionInfo) (*Signer, error)

NewSigner creates a Signer that sends authenticated messages to the Verifier named verifierName. In order to use this function, the client needs to obtain verifierInfo from the Verifier.

func (*Signer) AuthorizeHMAC

func (s *Signer) AuthorizeHMAC(message *universal.RoutableMessage, expiresIn time.Duration) error

AuthorizeHMAC adds an authentication tag to message.

This allows the recipient to verify the message has not been tampered with, but the payload is not encrypted. Unencrypted (but authenticated) messages are required for an HTTP API which relays messages to vehicles but needs to state in order to determine when a sequence of replies terminates. Sensitive data, such as live camera streams, is encrypted on the application layer.

func (*Signer) Encrypt

func (s *Signer) Encrypt(message *universal.RoutableMessage, expiresIn time.Duration) error

Encrypt message's payload in-place. This method adds (authenticated) metadata to the message as well, including the provided expiration time.

func (*Signer) ExportSessionInfo

func (s *Signer) ExportSessionInfo() ([]byte, error)

ExportSessionInfo can be used to write session state to disk, allowing for later resumption using ImportSessionInfo.

func (*Signer) RemotePublicKeyBytes

func (s *Signer) RemotePublicKeyBytes() []byte

RemotePublicKeyBytes returns the Verifer's public key encoded without point compression.

func (*Signer) UpdateSessionInfo

func (s *Signer) UpdateSessionInfo(info *signatures.SessionInfo) error

UpdateSessionInfo allows s to resync session state with a Verifier. A Verifier may include info in an authentication error message when the error may have resulted from a desync. The Signer can update its session info and then reattempt transmission.

func (*Signer) UpdateSignedSessionInfo

func (s *Signer) UpdateSignedSessionInfo(challenge, encodedInfo, tag []byte) error

UpdateSignedSessionInfo allows s to resync session state with a Verifier using cryptographically verified session state. See UpdateSessionInfo.

type Verifier

type Verifier struct {
	Peer
	// contains filtered or unexported fields
}

A Verifier checks the authenticity of commands sent by a Signer.

func NewVerifier

func NewVerifier(private ECDHPrivateKey, id []byte, domain universal.Domain, signerPublicBytes []byte) (*Verifier, error)

NewVerifier returns a Verifier. Set domain to universal.Domain_DOMAIN_BROADCAST if the Verifier shouldn't enforce domain checking. The Verifier's domain must be known in advance by the Signer.

func (*Verifier) SessionInfo

func (v *Verifier) SessionInfo() (*signatures.SessionInfo, error)

SessionInfo contains metadata used to prevent replay and similar attacks. A Signer must have the Verifier's SessionInfo on initialization.

func (*Verifier) SetSessionInfo

func (v *Verifier) SetSessionInfo(challenge []byte, message *universal.RoutableMessage) error

SetSessionInfo attaches up-to-date session info to a message. This is useful when v encounters an error while authenticating a message and wishes to include session info in the error response, thereby allowing the Signer to resync.

func (*Verifier) SignedSessionInfo

func (v *Verifier) SignedSessionInfo(challenge []byte) (encodedInfo, tag []byte, err error)

SignedSessionInfo returns a protobuf-encoded signatures.SessionInfo along with an authentication tag that a Signer may use to verify the info has not been tampered with.

func (*Verifier) Verify

func (v *Verifier) Verify(message *universal.RoutableMessage) (plaintext []byte, err error)

Verify message. If payload is encrypted, returns the plaintext. Otherwise extracts and returns the payload as-is.

Jump to

Keyboard shortcuts

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