Documentation
¶
Overview ¶
Package secure implements PASE (SPAKE2+ based) and CASE (SIGMA based) session establishment protocols for the Matter protocol.
Index ¶
- Constants
- func ComputeDestinationID(ipk, initiatorRandom, rootPubKey []byte, fabricID, nodeID uint64) []byte
- type CASEInitiator
- type CASEInitiatorConfig
- type CASEResponder
- type CASEResponderConfig
- type PAKE1
- type PAKE2
- type PAKE3
- type PASEInitiator
- func (p *PASEInitiator) GeneratePBKDFParamRequest() ([]byte, error)
- func (p *PASEInitiator) ProcessPAKE2(pake2Bytes []byte) (pake3Bytes []byte, err error)
- func (p *PASEInitiator) ProcessPBKDFParamResponse(reqBytes, respBytes []byte) (pake1Bytes []byte, peerSessionID uint16, err error)
- func (p *PASEInitiator) SessionKeys() *SessionKeys
- type PASEResponder
- type PBKDFParamRequest
- type PBKDFParamResponse
- type PBKDFParams
- type SessionKeys
- func DeriveSessionKeys(sharedSecret []byte) (*SessionKeys, error)
- func EstablishCASE(ctx context.Context, exchange *protocol.Exchange, cfg CASEInitiatorConfig) (*SessionKeys, uint16, error)
- func EstablishPASE(ctx context.Context, exchange *protocol.Exchange, passcode uint32, ...) (*SessionKeys, uint16, error)
- type Sigma1
- type Sigma2
- type Sigma2TBEData
- type Sigma2TBSData
- type Sigma3
- type Sigma3TBEData
- type Sigma3TBSData
- type StatusReport
Constants ¶
const ( OpcodeSigma1 byte = 0x30 OpcodeSigma2 byte = 0x31 OpcodeSigma3 byte = 0x32 )
CASE (SIGMA) opcodes per Matter spec.
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.
const ( StatusSuccess uint16 = 0x0000 StatusFailure uint16 = 0x0001 StatusSessionEstReqd uint16 = 0x0004 GeneralCodeSuccess uint16 = 0x0000 GeneralCodeFailure uint16 = 0x0001 )
Status codes for PASE.
const AttestationChallengeLength = 16
AttestationChallengeLength is the length in bytes of the attestation challenge.
const DerivedKeyMaterialLength = SessionKeyLength + SessionKeyLength + AttestationChallengeLength
DerivedKeyMaterialLength is the total length of derived key material: I2RKey (16) + R2IKey (16) + AttestationChallenge (16) = 48.
const SessionKeyLength = 16
SessionKeyLength is the length in bytes of an individual session key (AES-128).
Variables ¶
This section is empty.
Functions ¶
func ComputeDestinationID ¶
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 ¶
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 ¶
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 ¶
StatusReport is a general status message in the secure channel protocol.