pub struct PaseVerifier { /* private fields */ }Expand description
Device-side PASE state machine.
Drives the SPAKE2+ handshake from the device’s (responder’s) perspective. Sans-IO: the caller is responsible for transmitting and receiving bytes.
§Construction
PaseVerifier::new— production path; device stores pre-computedw0andL(never the PIN after provisioning).PaseVerifier::new_from_pin— test/convenience path; derivesw0andLfrom the PIN via PBKDF2.
§Driving the handshake
- Feed the inbound
PBKDFParamRequestbytes intohandle_pbkdf_request(negotiation path), or skip to step 3 (known-params path). - Call
next_messageto emitPBKDFParamResponse. - Feed the inbound
Pake1bytes intohandle_pake1. - Call
next_messageto emit Pake2. - Feed the inbound
Pake3bytes intohandle_pake3. - Call
finishto retrieve thePaseSessionKeys.
Use expected_inbound at any point to query
which message type the machine is currently waiting for.
Implementations§
Source§impl PaseVerifier
impl PaseVerifier
Sourcepub fn new(
w0: [u8; 32],
l: [u8; 65],
params: PasePbkdfParams,
responder_session_id: u16,
) -> Result<Self>
pub fn new( w0: [u8; 32], l: [u8; 65], params: PasePbkdfParams, responder_session_id: u16, ) -> Result<Self>
Production constructor: device stores pre-computed verification values.
In production the PIN is hashed to w0 and L once at provisioning
time and the raw PIN is discarded. Pass those stored values here.
Validates params against Matter spec §3.10.3 bounds before accepting.
§Parameters
w0: 32-byte big-endian P-256 scalar derived from the PIN.l: 65-byte uncompressed P-256 pointL = w1·P.params: PBKDF2 parameters used whenw0/Lwere derived.responder_session_id: the non-zero secured-session id this device advertises (inPBKDFParamResponse) for the peer to address it by.
§Errors
Error::PbkdfIterationsTooLowifparams.iterations < 1000.Error::PbkdfSaltLengthInvalidifparams.salt.len()∉ [16, 32].Error::InvalidScalarif the CSPRNG is broken and a non-zero scalar cannot be sampled after 16 attempts (practically impossible).Error::PinDerivationFailedif the nonce fill fails.
Sourcepub fn new_from_pin(
pin: u32,
params: PasePbkdfParams,
responder_session_id: u16,
) -> Result<Self>
pub fn new_from_pin( pin: u32, params: PasePbkdfParams, responder_session_id: u16, ) -> Result<Self>
Test/convenience constructor: derive w0 and L from the PIN.
In production a device never stores the PIN after provisioning —
it stores w0 and L instead. This constructor is provided for
tests and development use where deriving from a PIN is convenient.
§Parameters
responder_session_id: the non-zero secured-session id this device advertises (inPBKDFParamResponse) for the peer to address it by.
§Errors
Error::PbkdfIterationsTooLow/Error::PbkdfSaltLengthInvalidifparamsare out of spec.Error::PinDerivationFailedif PBKDF2 fails.Error::InvalidScalarif the CSPRNG is broken.
Sourcepub fn expected_inbound(&self) -> Option<PaseMessageKind>
pub fn expected_inbound(&self) -> Option<PaseMessageKind>
Returns the message kind the state machine is currently waiting to
receive, or None if the machine is in an outbound-only or completed
state.
Useful for routing inbound messages in a dispatcher.
Sourcepub fn handle_pbkdf_request(&mut self, bytes: &[u8]) -> Result<()>
pub fn handle_pbkdf_request(&mut self, bytes: &[u8]) -> Result<()>
Process an inbound PBKDFParamRequest message (negotiation path).
Decodes the request, captures the raw bytes for transcript composition,
and transitions to ReadyToSendPbkdfResponse. After this call,
next_message emits PBKDFParamResponse.
§Errors
Error::UnexpectedMessageif called from any state other thanAwaitingFirstMessage.Error::Codecon TLV decoding failure.Error::InvalidParameterif the request is malformed.
Sourcepub fn handle_pake1(&mut self, bytes: &[u8]) -> Result<()>
pub fn handle_pake1(&mut self, bytes: &[u8]) -> Result<()>
Process an inbound Pake1 message.
Valid in two states:
AwaitingFirstMessage— commissioner skipped param negotiation (known-params path); context =SHA-256(SPAKE_CONTEXT).AwaitingPake1— negotiation complete; context already computed.
After this call, next_message emits Pake2.
§Cryptography
- Decode X from Pake1 TLV.
- Compute
Y = y·P + w0·N(verifier’s SPAKE2+ share). - Compute
Z = y·(X − w0·M)andV = y·L(shared secrets). - Compute the SPAKE2+ transcript hash
TT_HASH. - Split
Ka(first 16 bytes) andKe(last 16 bytes) fromTT_HASH. - Derive confirmation keys
KcA/KcBfromKa. - Compute
cB = HMAC-SHA256(KcB, X)(our confirmation tag to send). - Compute
cA_expected = HMAC-SHA256(KcA, Y)(to verify in Pake3). - Derive session keys from
Ke.
§Errors
Error::UnexpectedMessageif called from the wrong state.Error::Codecon TLV decoding failure.Error::InvalidParameterif X is not a valid P-256 point.Error::PinDerivationFailedon HKDF failure.
Sourcepub fn handle_pake3(&mut self, bytes: &[u8]) -> Result<()>
pub fn handle_pake3(&mut self, bytes: &[u8]) -> Result<()>
Process an inbound Pake3 message.
Verifies the commissioner’s confirmation tag cA using constant-time
comparison (subtle::ConstantTimeEq). If verification succeeds the
state machine transitions to Complete and finish
may be called.
§Security
Tag comparison MUST be constant-time. This is enforced by routing
through verify_tag (in pase::spake2plus) which uses
subtle::ConstantTimeEq.
§Errors
Error::UnexpectedMessageif called before Pake2 was sent.Error::ConfirmationTagMismatchifcAfails constant-time verification (wrong PIN on the commissioner’s side).Error::Codecon TLV decoding failure.
Sourcepub fn next_message(&mut self) -> Result<Vec<u8>>
pub fn next_message(&mut self) -> Result<Vec<u8>>
Produce the next outbound message.
- After
handle_pbkdf_request: emitsPBKDFParamResponse(TLV bytes). - After
handle_pake1: emits Pake2 (TLV bytes).
Calling from any other state returns Error::UnexpectedMessage.
§Errors
Error::UnexpectedMessageif called from the wrong state.Error::Codecon TLV encoding failure.
Sourcepub fn finish(self) -> Result<PaseSessionKeys>
pub fn finish(self) -> Result<PaseSessionKeys>
Finalise the session and retrieve the derived session keys.
May only be called after handle_pake3 has
successfully verified cA (i.e., the state machine is in Complete).
§Errors
Error::HandshakeIncompleteif called before the handshake has completed all phases.