modules/woz_matter/include/matter_pase_sm.h
openaliro/openaliro
Module

matter_pase_sm.h

PASE responder: the device side of the five messages.

modules/woz_matter/include/matter_pase_sm.h3 documented symbols

Overview

PASE responder: the device side of the five messages. matter_pase.h is the codec and matter_spake2p.h is the arithmetic; this is what drives them. A commissioner opens with PBKDFParamRequest and this answers, receives Pake1, answers Pake2, receives Pake3, and ends with a StatusReport. What comes out the far side is a session key schedule. -> PBKDFParamRequest <- PBKDFParamResponse (context hash fixed here) -> Pake1 (pA) <- Pake2 (pB, cB) -> Pake3 (cA) <- StatusReport(success) The device never holds the setup passcode. It holds the SPAKE2+ verifier -- w0 and L -- which is derived from the passcode somewhere else and provisioned in. That is the whole point of the augmented form: someone who reads the device's flash cannot impersonate a commissioner to it. No time and no randomness are taken from the environment. Retransmission is MRP's job (matter_mrp.h), and the two random values PASE needs are arguments, so the host suite runs the real state machine against a recorded exchange rather than against whatever entropy it happened to get.

depends on matter_crypto.h matter_pase.h matter_spake2p.h matter_status.h  ·  used by matter_pase_sm.c

API

Cstruct matter_pase_verifier

modules/woz_matter/include/matter_pase_sm.h:99

The provisioned SPAKE2+ verifier, plus the PBKDF parameters that produced it. All four travel together because they have to agree: w0 and L are what PBKDF2(passcode, salt, iterations) yields, and the salt and iteration count go out in PBKDFParamResponse so the commissioner can repeat the derivation. A verifier stored without the parameters that made it is unusable. Deriving this needs a scalar multiply against the P-256 base point to get L = w1*G, which is not one of the four operations nrf_oberon exposes here, so it is generated off-device and provisioned -- which is how Matter intends it anyway (the passcode is on the label, the verifier is in the flash).

Cstruct matter_pase_responder

modules/woz_matter/include/matter_pase_sm.h:124

PASE responder state machine: tracks the verifier, session IDs, ephemeral scalar y, random nonce, SPAKE2+ context, expected commitment cA, shared secret ke, derived session keys, and the 534-byte transcript live only during Pake1 handling.

Fmatter_pase_responder_state

modules/woz_matter/include/matter_pase_sm.h:204
returns
the current state; MATTER_PASE_ST_DONE means keys are usable.

##define MATTER_SC_OP_STATUS_REPORT 0x40u

modules/woz_matter/include/matter_pase_sm.h:62

Secure Channel StatusReport, 0x40. Not a PASE opcode; PASE ends with one.

##define MATTER_SC_STATUS_LEN 8u

modules/woz_matter/include/matter_pase_sm.h:64

u16 general code, u32 protocol id, u16 protocol code (StatusReport.cpp).

##define MATTER_SC_GENERAL_SUCCESS 0u

modules/woz_matter/include/matter_pase_sm.h:67

GeneralStatusCode, Constants.h:116-138. Only the two PASE can produce.

##define MATTER_SC_GENERAL_FAILURE 1u

modules/woz_matter/include/matter_pase_sm.h:68

##define MATTER_SC_CODE_SUCCESS 0x0000u

modules/woz_matter/include/matter_pase_sm.h:71

Constants.h:79-84.

##define MATTER_SC_CODE_INVALID_PARAM 0x0002u

modules/woz_matter/include/matter_pase_sm.h:72

##define MATTER_PASE_REPLY_MAX 128u

modules/woz_matter/include/matter_pase_sm.h:81

Largest reply this produces. PBKDFParamResponse is the big one: two 32-byte randoms with their headers, a session id, and the pbkdfParameters structure carrying a 32-byte salt, which comes to 120 bytes. Pake2 is 105 and a StatusReport is 8.

##define MATTER_PASE_Y_ENTROPY_LEN MATTER_SPAKE_WS_LEN

modules/woz_matter/include/matter_pase_sm.h:84

Random bytes the caller supplies for the ephemeral scalar, before reduction.

Cenum matter_pase_state

modules/woz_matter/include/matter_pase_sm.h:108

Fint matter_pase_responder_init(struct matter_pase_responder *r, const struct matter_pase_verifier *v, uint16_t local_session_id, const uint8_t responder_random[MATTER_PASE_RANDOM_LEN], const uint8_t y_entropy[MATTER_PASE_Y_ENTROPY_LEN])

modules/woz_matter/include/matter_pase_sm.h:170

Prepare a responder for one commissioning attempt. @param local_session_id the session id this device wants the commissioner to use when addressing it. Announced in PBKDFParamResponse. @param responder_random 32 fresh random bytes. Goes on the wire, and into the context hash, so it is what stops a recorded exchange being replayed. @param y_entropy MATTER_PASE_Y_ENTROPY_LEN fresh random bytes, reduced here rather than by the caller: taking 40 bytes and reducing them mod the group order is uniform to within 2^-64, whereas a caller handing over 32 bytes it generated itself may or may not be in range at all. @return MATTER_OK, or MATTER_E_INVAL for a null argument or a verifier whose salt length or iteration count is outside what PASE permits.

Fint matter_pase_responder_recv(struct matter_pase_responder *r, uint8_t opcode, const uint8_t *payload, size_t len, uint8_t *out, size_t cap, size_t *out_len, uint8_t *out_opcode)

modules/woz_matter/include/matter_pase_sm.h:199

Feed one received Secure Channel message and collect the reply. @param opcode the Secure Channel opcode, 0x20..0x24. @param payload the decrypted message payload: PASE runs unencrypted, so this is the TLV structure with no header in front of it. @param out receives the reply, up to MATTER_PASE_REPLY_MAX bytes. @param out_opcode receives the reply's opcode. @return MATTER_OK when the exchange advanced. On a negative return the responder is in MATTER_PASE_ST_FAILED and stays there -- but out may still hold a StatusReport, so the caller should send whatever out_len describes BEFORE acting on the return code. That is the only way the commissioner learns it failed rather than timing out: rc = matter_pase_responder_recv(...); if (out_len > 0) { send(out_opcode, out, out_len); } if (rc != MATTER_OK) { drop_session(); } MATTER_E_STATE for a message that does not fit the current state, MATTER_E_INVAL for a value the peer should not have sent, MATTER_E_TYPE when cA does not verify, MATTER_E_NOSPACE if cap is under MATTER_PASE_REPLY_MAX, or whatever the codec returned.

Fint matter_sc_status_report(uint16_t protocol_code, uint8_t *out, size_t cap, size_t *out_len)

modules/woz_matter/include/matter_pase_sm.h:220

Encode a Secure Channel StatusReport. Exposed because it is not PASE's alone: CASE ends the same way, and a node that cannot answer at all still owes the peer one of these. @param protocol_code MATTER_SC_CODE_*. The general code is derived from it, success for 0x0000 and failure otherwise, which is the rule PairingSession.h:147-149 applies.