class Matter::Fabric

Overview

Fabric represents a unique administrative domain in Matter

A fabric is a logical grouping of Matter nodes that share a common trust root and can communicate securely. Each fabric has:

Matter devices can be members of multiple fabrics simultaneously (multi-admin). Each fabric gets a local Fabric Index (1-254) on the device.

Specification: Matter 1.4 § 4.13 (Fabrics)

Defined in:

matter/fabric.cr

Constructors

Instance Method Summary

Constructor Detail

def self.from_h(data : Hash(String, String | UInt64 | UInt16 | UInt8 | Int64)) : Fabric #

Deserialize fabric from hash


[View source]
def self.new(fabric_id : UInt64, fabric_index : UInt8, node_id : UInt64, root_public_key : Bytes, operational_cert : Bytes, operational_key : Crypto::Key, ipk : Bytes, vendor_id : UInt16 = 65521_u16, label : String = "", intermediate_cert : Bytes | Nil = nil, root_cert : Bytes | Nil = nil, created_at : Int64 = Time.utc.to_unix, last_used_at : Int64 = Time.utc.to_unix, cats : Array(DataType::CaseAuthenticatedTag) = [] of DataType::CaseAuthenticatedTag) #

[View source]

Instance Method Detail

def cat_node_ids : Array(UInt64) #

Get CATs as NodeId-encoded values for access control matching Each CAT is encoded as a NodeId with prefix 0xFFFFFFFD

This is used during CASE session establishment to provide the subjects that should be checked against access control entries.


[View source]
def cats : Array(DataType::CaseAuthenticatedTag) #

Case Authenticated Tags (CATs) extracted from NOC certificate CATs provide additional identity attributes for access control. Up to 3 CATs can be specified in the NOC subject field. Specification: Matter 1.4 § 6.6.2.1.1 (Case Authenticated Tag Subject)


[View source]
def cats=(cats : Array(DataType::CaseAuthenticatedTag)) #

Case Authenticated Tags (CATs) extracted from NOC certificate CATs provide additional identity attributes for access control. Up to 3 CATs can be specified in the NOC subject field. Specification: Matter 1.4 § 6.6.2.1.1 (Case Authenticated Tag Subject)


[View source]
def compressed_fabric_id : Bytes #

Get the compressed fabric identifier using HKDF This is used in various Matter protocols, especially mDNS service discovery

The compressed fabric ID is an 8-byte value derived from:

  • Key: root public key (excluding first byte which is 0x04 format indicator)
  • Salt: fabric_id (8 bytes, little-endian)
  • Info: "CompressedFabric"
  • Length: 8 bytes

Specification: Matter 1.4 § 4.13.2.4.2 (Compressed Fabric Identifier)


[View source]
def compute_destination_id(initiator_random : Bytes) : Bytes #

Compute the expected destination_id for CASE Sigma1 matching

The destination_id helps identify which fabric is being targeted in a CASE session. It's computed as: destination_id = HMAC-SHA256(key=IPK, data=initiatorRandom || rootPublicKey || fabricId || nodeId)

This method computes what the destination_id should be for this fabric given an initiator_random.

@param initiator_random The 32-byte random value from CASE Sigma1 @return 32-byte destination_id that should match the one in Sigma1 if this fabric is the target

Note: fabricId and nodeId are encoded in Little Endian format per matter.js implementation. This differs from some other Matter protocol encodings that use Big Endian.


[View source]
def created_at : Int64 #

Timestamp when this fabric was created (Unix epoch seconds)


[View source]
def created_at=(created_at : Int64) #

Timestamp when this fabric was created (Unix epoch seconds)


[View source]
def derived_ipk : Bytes #

Derive the Identity Protection Key (IPK) for CASE authentication

The IPK is derived from the epoch key (ipk_value from AddNOC) using HKDF. This derived key is what's actually used in the CASE Sigma2 salt.

Formula: IPK = HKDF-SHA-256(InputKey=epoch_key, Salt=CompressedFabricId, Info="GroupKey v1.0", Length=16)

Note: The info string "GroupKey v1.0" matches matter.js implementation. Specification: Matter 1.4 § 4.16.2.5.2 (Group Key Derivation)


[View source]
def expired?(threshold_seconds : Int64 = 31536000) : Bool #

Check if this fabric is expired (unused for more than 1 year)


[View source]
def fabric_id : UInt64 #

Unique 64-bit identifier for this fabric (globally unique)


[View source]
def fabric_id=(fabric_id : UInt64) #

Unique 64-bit identifier for this fabric (globally unique)


[View source]
def fabric_index : UInt8 #

Local index on the device (1-254, 0 is reserved) This is device-specific and may differ across devices


[View source]
def fabric_index=(fabric_index : UInt8) #

Local index on the device (1-254, 0 is reserved) This is device-specific and may differ across devices


[View source]
def has_cats? : Bool #

Check if this fabric has any CATs


[View source]
def intermediate_cert : Bytes | Nil #

Intermediate CA certificate (optional) If present, forms a chain: Root CA -> ICA -> NOC


[View source]
def intermediate_cert=(intermediate_cert : Bytes | Nil) #

Intermediate CA certificate (optional) If present, forms a chain: Root CA -> ICA -> NOC


[View source]
def ipk : Bytes #

Identity Protection Key (IPK) - 16 bytes Used to encrypt node IDs in operational discovery for privacy


[View source]
def ipk=(ipk : Bytes) #

Identity Protection Key (IPK) - 16 bytes Used to encrypt node IDs in operational discovery for privacy


[View source]
def label : String #

User-friendly label for this fabric (max 32 UTF-8 characters)


[View source]
def label=(label : String) #

User-friendly label for this fabric (max 32 UTF-8 characters)


[View source]
def last_used_at : Int64 #

Timestamp when this fabric was last used (Unix epoch seconds)


[View source]
def last_used_at=(last_used_at : Int64) #

Timestamp when this fabric was last used (Unix epoch seconds)


[View source]
def mark_used #

Update the last used timestamp


[View source]
def matches_destination_id?(destination_id : Bytes, initiator_random : Bytes) : Bool #

Check if this fabric matches the given destination_id from CASE Sigma1

@param destination_id The 32-byte destination_id from Sigma1 @param initiator_random The 32-byte initiator_random from Sigma1 @return true if this fabric matches the destination_id


[View source]
def matches_id?(id : UInt64) : Bool #

Helper to check if a given fabric_id matches


[View source]
def matches_index?(index : UInt8) : Bool #

Helper to check if a given fabric_index matches


[View source]
def node_id : UInt64 #

Our Node ID within this fabric (64-bit) Combined with fabric_id forms a globally unique identifier


[View source]
def node_id=(node_id : UInt64) #

Our Node ID within this fabric (64-bit) Combined with fabric_id forms a globally unique identifier


[View source]
def operational_cert : Bytes #

Node Operational Certificate (NOC) - our identity certificate TLV-encoded Matter certificate


[View source]
def operational_cert=(operational_cert : Bytes) #

Node Operational Certificate (NOC) - our identity certificate TLV-encoded Matter certificate


[View source]
def operational_key : Crypto::Key #

Private key corresponding to the public key in our NOC


[View source]
def operational_key=(operational_key : Crypto::Key) #

Private key corresponding to the public key in our NOC


[View source]
def root_cert : Bytes | Nil #

Root CA certificate (RCAC) - the trust anchor certificate This is the full TLV-encoded certificate, not just the public key


[View source]
def root_cert=(root_cert : Bytes | Nil) #

Root CA certificate (RCAC) - the trust anchor certificate This is the full TLV-encoded certificate, not just the public key


[View source]
def root_public_key : Bytes #

Trusted Root Certificate Authority public key This is the trust anchor for certificate validation


[View source]
def root_public_key=(root_public_key : Bytes) #

Trusted Root Certificate Authority public key This is the trust anchor for certificate validation


[View source]
def scoped_node_id : UInt64 #

Get scoped node ID (used in CASE for peer identification)


[View source]
def to_h : Hash(String, String | UInt64 | UInt16 | UInt8 | Int64) #

Serialize fabric to hash for storage


[View source]
def to_s(io : IO) #

String representation for debugging


[View source]
def vendor_id : UInt16 #

Vendor ID for this fabric (identifies the admin/commissioner)


[View source]
def vendor_id=(vendor_id : UInt16) #

Vendor ID for this fabric (identifies the admin/commissioner)


[View source]