secure

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Apr 24, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package secure implements PASE (SPAKE2+ based) and CASE (SIGMA based) session establishment protocols for the Matter protocol.

Index

Constants

View Source
const (
	OpcodeSigma1 byte = 0x30
	OpcodeSigma2 byte = 0x31
	OpcodeSigma3 byte = 0x32
)

CASE (SIGMA) opcodes per Matter spec.

View Source
const (
	ProtocolIDSecureChannel uint16 = 0x0000

	OpcodePBKDFParamRequest  byte = 0x20
	OpcodePBKDFParamResponse byte = 0x21
	OpcodePASEPake1          byte = 0x22
	OpcodePASEPake2          byte = 0x23
	OpcodePASEPake3          byte = 0x24
	OpcodeStatusReport       byte = 0x40
)

Secure Channel protocol ID and PASE opcodes per Matter spec.

View Source
const (
	StatusSuccess        uint16 = 0x0000
	StatusFailure        uint16 = 0x0001
	StatusSessionEstReqd uint16 = 0x0004
	GeneralCodeSuccess   uint16 = 0x0000
	GeneralCodeFailure   uint16 = 0x0001
)

Status codes for PASE.

View Source
const AttestationChallengeLength = 16

AttestationChallengeLength is the length in bytes of the attestation challenge.

DerivedKeyMaterialLength is the total length of derived key material: I2RKey (16) + R2IKey (16) + AttestationChallenge (16) = 48.

View Source
const SessionKeyLength = 16

SessionKeyLength is the length in bytes of an individual session key (AES-128).

Variables

This section is empty.

Functions

func ComputeDestinationID

func ComputeDestinationID(ipk, initiatorRandom, rootPubKey []byte, fabricID, nodeID uint64) []byte

ComputeDestinationID computes the CASE destination identifier using HMAC-SHA256. This is exported for use by other packages that need to compute destination IDs.

Types

type CASEInitiator

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

CASEInitiator implements the commissioner (initiator) side of the CASE protocol.

func NewCASEInitiator

func NewCASEInitiator(cfg CASEInitiatorConfig) *CASEInitiator

NewCASEInitiator creates a new CASE initiator.

func (*CASEInitiator) GenerateSigma1

func (c *CASEInitiator) GenerateSigma1() ([]byte, error)

GenerateSigma1 creates the first CASE message (Sigma1).

func (*CASEInitiator) GenerateSigma3

func (c *CASEInitiator) GenerateSigma3() ([]byte, error)

GenerateSigma3 creates the third CASE message (Sigma3) and derives session keys.

func (*CASEInitiator) ProcessSigma2

func (c *CASEInitiator) ProcessSigma2(sigma2Bytes []byte) error

ProcessSigma2 handles the responder's Sigma2 message. It verifies the responder's identity and derives the Sigma2 decryption key.

func (*CASEInitiator) SessionKeys

func (c *CASEInitiator) SessionKeys() *SessionKeys

SessionKeys returns the derived session keys after a successful handshake.

type CASEInitiatorConfig

type CASEInitiatorConfig struct {
	SessionID  uint16
	NodeKey    *ecdsa.PrivateKey
	NOC        []byte
	ICAC       []byte
	IPK        []byte
	RootPubKey []byte
	FabricID   uint64
	PeerNodeID uint64
}

CASEInitiatorConfig holds configuration for creating a CASEInitiator.

type CASEResponder

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

CASEResponder implements the device (responder) side of the CASE protocol. This is provided for testing purposes.

func NewCASEResponder

func NewCASEResponder(cfg CASEResponderConfig) *CASEResponder

NewCASEResponder creates a new CASE responder.

func (*CASEResponder) ProcessSigma1

func (r *CASEResponder) ProcessSigma1(sigma1Bytes []byte) ([]byte, error)

ProcessSigma1 handles the initiator's Sigma1 message and produces the Sigma2 message.

func (*CASEResponder) ProcessSigma3

func (r *CASEResponder) ProcessSigma3(sigma3Bytes []byte) error

ProcessSigma3 handles the initiator's Sigma3 message and verifies the initiator's identity.

func (*CASEResponder) SessionKeys

func (r *CASEResponder) SessionKeys() *SessionKeys

SessionKeys returns the derived session keys after a successful handshake.

type CASEResponderConfig

type CASEResponderConfig struct {
	SessionID  uint16
	NodeKey    *ecdsa.PrivateKey
	NOC        []byte
	ICAC       []byte
	IPK        []byte
	RootPubKey []byte
	FabricID   uint64
	NodeID     uint64
}

CASEResponderConfig holds configuration for creating a CASEResponder.

type PAKE1

type PAKE1 struct {
	PA []byte `tlv:"1,octets"`
}

PAKE1 is the third message in the PASE handshake (initiator's SPAKE2+ public share).

type PAKE2

type PAKE2 struct {
	PB []byte `tlv:"1,octets"`
	CB []byte `tlv:"2,octets"`
}

PAKE2 is the fourth message in the PASE handshake (responder's public share and confirmation).

type PAKE3

type PAKE3 struct {
	CA []byte `tlv:"1,octets"`
}

PAKE3 is the fifth message in the PASE handshake (initiator's confirmation).

type PASEInitiator

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

PASEInitiator implements the commissioner (prover) side of the PASE protocol.

func NewPASEInitiator

func NewPASEInitiator(passcode uint32, sessionID uint16) *PASEInitiator

NewPASEInitiator creates a new PASE initiator (commissioner side) for the given passcode and local session ID.

func (*PASEInitiator) GeneratePBKDFParamRequest

func (p *PASEInitiator) GeneratePBKDFParamRequest() ([]byte, error)

GeneratePBKDFParamRequest creates the first PASE message (PBKDFParamRequest).

func (*PASEInitiator) ProcessPAKE2

func (p *PASEInitiator) ProcessPAKE2(pake2Bytes []byte) (pake3Bytes []byte, err error)

ProcessPAKE2 handles the responder's PAKE2 message and produces the PAKE3 message containing the initiator's confirmation value cA. It also derives the session keys.

func (*PASEInitiator) ProcessPBKDFParamResponse

func (p *PASEInitiator) ProcessPBKDFParamResponse(reqBytes, respBytes []byte) (pake1Bytes []byte, peerSessionID uint16, err error)

ProcessPBKDFParamResponse handles the responder's PBKDFParamResponse and produces the PAKE1 message containing the SPAKE2+ public share pA. It returns the PAKE1 TLV bytes and the peer session ID.

func (*PASEInitiator) SessionKeys

func (p *PASEInitiator) SessionKeys() *SessionKeys

SessionKeys returns the derived session keys after a successful handshake.

type PASEResponder

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

PASEResponder implements the device (verifier) side of the PASE protocol. This is provided for testing purposes and for devices that might be emulated.

func NewPASEResponder

func NewPASEResponder(passcode uint32, salt []byte, iterations uint32, sessionID uint16) *PASEResponder

NewPASEResponder creates a new PASE responder (device side) for the given passcode, salt, iterations, and local session ID.

func (*PASEResponder) ProcessPAKE1

func (r *PASEResponder) ProcessPAKE1(pake1Bytes []byte) (pake2Bytes []byte, err error)

ProcessPAKE1 handles the initiator's PAKE1 message and produces the PAKE2 message containing the responder's public share and confirmation.

func (*PASEResponder) ProcessPAKE3

func (r *PASEResponder) ProcessPAKE3(pake3Bytes []byte) error

ProcessPAKE3 verifies the initiator's confirmation from the PAKE3 message.

func (*PASEResponder) ProcessPBKDFParamRequest

func (r *PASEResponder) ProcessPBKDFParamRequest(reqBytes []byte) (respBytes []byte, err error)

ProcessPBKDFParamRequest handles the initiator's PBKDFParamRequest and produces the PBKDFParamResponse message.

func (*PASEResponder) SessionKeys

func (r *PASEResponder) SessionKeys() *SessionKeys

SessionKeys returns the derived session keys after a successful handshake.

type PBKDFParamRequest

type PBKDFParamRequest struct {
	InitiatorRandom    []byte `tlv:"1,octets"`
	InitiatorSessionID uint16 `tlv:"2,uint"`
	PasscodeID         uint16 `tlv:"3,uint"`
	HasPBKDFParameters bool   `tlv:"4,bool"`
}

PBKDFParamRequest is the first message in the PASE handshake, sent by the initiator (commissioner) to request PBKDF parameters.

type PBKDFParamResponse

type PBKDFParamResponse struct {
	InitiatorRandom    []byte      `tlv:"1,octets"`
	ResponderRandom    []byte      `tlv:"2,octets"`
	ResponderSessionID uint16      `tlv:"3,uint"`
	PBKDFParameters    PBKDFParams `tlv:"4,struct"`
}

PBKDFParamResponse is the second message in the PASE handshake, sent by the responder (device) with PBKDF parameters.

type PBKDFParams

type PBKDFParams struct {
	Iterations uint32 `tlv:"1,uint"`
	Salt       []byte `tlv:"2,octets"`
}

PBKDFParams contains the PBKDF2 parameters (iterations and salt).

type SessionKeys

type SessionKeys struct {
	// I2RKey is the Initiator-to-Responder encryption key (16 bytes).
	I2RKey []byte
	// R2IKey is the Responder-to-Initiator encryption key (16 bytes).
	R2IKey []byte
	// AttestationChallenge is the attestation challenge (16 bytes).
	AttestationChallenge []byte
}

SessionKeys holds the symmetric keys derived from a session establishment.

func DeriveSessionKeys

func DeriveSessionKeys(sharedSecret []byte) (*SessionKeys, error)

DeriveSessionKeys derives I2R, R2I, and AttestationChallenge keys from a shared secret using HKDF-SHA256 with no salt and info="SessionKeys".

func EstablishCASE

func EstablishCASE(ctx context.Context, exchange *protocol.Exchange, cfg CASEInitiatorConfig) (*SessionKeys, uint16, error)

EstablishCASE performs the full CASE handshake over a protocol Exchange. It acts as the initiator. On success, it returns the established session keys and the peer's session ID.

func EstablishPASE

func EstablishPASE(ctx context.Context, exchange *protocol.Exchange, passcode uint32, proposedSessionID uint16) (*SessionKeys, uint16, error)

EstablishPASE performs the full PASE handshake over a protocol Exchange. It acts as the initiator (commissioner). proposedSessionID is the session ID the initiator proposes for the new secure session. On success, it returns the established session keys and the peer's session ID.

type Sigma1

type Sigma1 struct {
	InitiatorRandom    []byte `tlv:"1,octets"`
	InitiatorSessionID uint16 `tlv:"2,uint"`
	DestinationID      []byte `tlv:"3,octets"`
	InitiatorEphPubKey []byte `tlv:"4,octets"`
}

Sigma1 is the first CASE message, sent by the initiator.

type Sigma2

type Sigma2 struct {
	ResponderRandom    []byte `tlv:"1,octets"`
	ResponderSessionID uint16 `tlv:"2,uint"`
	ResponderEphPubKey []byte `tlv:"3,octets"`
	Encrypted2         []byte `tlv:"4,octets"`
}

Sigma2 is the second CASE message, sent by the responder.

type Sigma2TBEData

type Sigma2TBEData struct {
	ResponderNOC  []byte `tlv:"1,octets"`
	ResponderICAC []byte `tlv:"2,octets"`
	Signature     []byte `tlv:"3,octets"`
	ResumptionID  []byte `tlv:"4,octets"`
}

Sigma2TBEData is the to-be-encrypted data for Sigma2.

type Sigma2TBSData

type Sigma2TBSData struct {
	ResponderNOC       []byte `tlv:"1,octets"`
	ResponderICAC      []byte `tlv:"2,octets"`
	ResponderEphPubKey []byte `tlv:"3,octets"`
	InitiatorEphPubKey []byte `tlv:"4,octets"`
}

Sigma2TBSData is the to-be-signed data for Sigma2.

type Sigma3

type Sigma3 struct {
	Encrypted3 []byte `tlv:"1,octets"`
}

Sigma3 is the third CASE message, sent by the initiator.

type Sigma3TBEData

type Sigma3TBEData struct {
	InitiatorNOC  []byte `tlv:"1,octets"`
	InitiatorICAC []byte `tlv:"2,octets"`
	Signature     []byte `tlv:"3,octets"`
}

Sigma3TBEData is the to-be-encrypted data for Sigma3.

type Sigma3TBSData

type Sigma3TBSData struct {
	InitiatorNOC       []byte `tlv:"1,octets"`
	InitiatorICAC      []byte `tlv:"2,octets"`
	InitiatorEphPubKey []byte `tlv:"3,octets"`
	ResponderEphPubKey []byte `tlv:"4,octets"`
}

Sigma3TBSData is the to-be-signed data for Sigma3.

type StatusReport

type StatusReport struct {
	GeneralCode  uint16
	ProtocolID   uint32
	ProtocolCode uint16
}

StatusReport is a general status message in the secure channel protocol.

Jump to

Keyboard shortcuts

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