Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/ids_and_codes/ERROR_CODES.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ This file was **AUTOMATICALLY** generated by
| 187 | 0xBB | `CHIP_ERROR_MAXIMUM_PATHS_PER_INVOKE_EXCEEDED` |
| 188 | 0xBC | `CHIP_ERROR_PEER_NODE_NOT_FOUND` |
| 189 | 0xBD | `CHIP_ERROR_HSM` |
| 190 | 0xBE | `CHIP_ERROR_DNS_SD_NXDOMAIN` |
| 191 | 0xBF | `CHIP_ERROR_REAL_TIME_NOT_SYNCED` |
| 192 | 0xC0 | `CHIP_ERROR_UNEXPECTED_EVENT` |
| 193 | 0xC1 | `CHIP_ERROR_ENDPOINT_POOL_FULL` |
Expand All @@ -146,6 +147,7 @@ This file was **AUTOMATICALLY** generated by
| 196 | 0xC4 | `CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED` |
| 197 | 0xC5 | `CHIP_ERROR_INVALID_PUBLIC_KEY` |
| 198 | 0xC6 | `CHIP_ERROR_FABRIC_MISMATCH_ON_ICA` |
| 199 | 0xC7 | `CHIP_ERROR_DNS_SD_SERVICE_NOT_RUNNING` |
| 201 | 0xC9 | `CHIP_ERROR_NO_SHARED_TRUSTED_ROOT` |
| 202 | 0xCA | `CHIP_ERROR_IM_STATUS_CODE_RECEIVED` |
| 215 | 0xD7 | `CHIP_ERROR_IM_MALFORMED_DATA_VERSION_FILTER_IB` |
Expand Down
24 changes: 19 additions & 5 deletions src/darwin/Framework/CHIP/MTRDeviceAttestationDelegateBridge.mm
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@

void * deviceHandle = device;

// TODO: Consider exposing the actual attestation verification result in MTRDeviceAttestationDeviceInfo; need to
// figure out how best to do that.

dispatch_async(mQueue, ^{
// Hide things that are not passed to us by value, so we don't use them by accident.
mtr_hide(deviceCommissioner);
Expand All @@ -75,6 +72,19 @@

mResult = attestationResult;

// Surface the AttestationVerificationResult enum and the VID/PID the device asserts in
// its BasicInformation cluster, in NSError userInfo, so callers can disambiguate the
// 40+ distinct attestation-failure modes that previously all collapsed to a single
// MTRErrorCodeIntegrityCheckFailed. The BasicInformation VID/PID may not match the IDs
// in the device's certification declaration — VID/PID mismatch is itself one of the
// attestation-failure modes — so the userInfo keys are named to reflect that these are
// the device-asserted values, not certified identity.
NSDictionary<NSErrorUserInfoKey, id> * attestationUserInfo = @{
MTRAttestationVerificationResultKey : @(chip::to_underlying(attestationResult)),
MTRDeviceBasicInformationVendorIDKey : basicInformationVendorID,
MTRDeviceBasicInformationProductIDKey : basicInformationProductID,
};

id<MTRDeviceAttestationDelegate> strongDelegate = mDeviceAttestationDelegate;
if ([strongDelegate respondsToSelector:@selector(deviceAttestationCompletedForController:opaqueDeviceHandle:attestationDeviceInfo:error:)]
|| [strongDelegate respondsToSelector:@selector(deviceAttestation:completedForDevice:attestationDeviceInfo:error:)]) {
Expand All @@ -92,7 +102,9 @@
basicInformationProductID:basicInformationProductID];
NSError * error = (attestationResult == chip::Credentials::AttestationVerificationResult::kSuccess)
? nil
: [MTRError errorForCHIPErrorCode:CHIP_ERROR_INTEGRITY_CHECK_FAILED];
: [MTRError errorForCHIPErrorCode:CHIP_ERROR_INTEGRITY_CHECK_FAILED
logContext:nil
additionalUserInfo:attestationUserInfo];
if ([strongDelegate respondsToSelector:@selector(deviceAttestationCompletedForController:opaqueDeviceHandle:attestationDeviceInfo:error:)]) {
[strongDelegate deviceAttestationCompletedForController:mDeviceController
opaqueDeviceHandle:deviceHandle
Expand All @@ -111,7 +123,9 @@

MTRDeviceController * strongController = mDeviceController;
if (strongController) {
NSError * error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INTEGRITY_CHECK_FAILED];
NSError * error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INTEGRITY_CHECK_FAILED
logContext:nil
additionalUserInfo:attestationUserInfo];
if ([strongDelegate respondsToSelector:@selector(deviceAttestationFailedForController:opaqueDeviceHandle:error:)]) {
[strongDelegate deviceAttestationFailedForController:mDeviceController opaqueDeviceHandle:deviceHandle error:error];
} else {
Expand Down
176 changes: 133 additions & 43 deletions src/darwin/Framework/CHIP/MTRError.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,53 @@ NS_ASSUME_NONNULL_BEGIN
MTR_EXTERN NSErrorDomain const MTRErrorDomain MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1));
MTR_EXTERN NSErrorDomain const MTRInteractionErrorDomain MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1));

/**
* NSNumber userInfo key carrying the numeric attestation-verification result for an
* MTRErrorCodeIntegrityCheckFailed error emitted from device-attestation verification.
* Lets callers distinguish, e.g., attestation-nonce mismatch (502) from PAA-not-found
* (101) without otherwise being collapsed to a single integrity-check failure.
*
* The integer values match the underlying Matter SDK attestation-verification-result enum
* and are intended for triage / structured discrimination; specific numeric values are not
* stable across releases.
*/
MTR_EXTERN NSErrorUserInfoKey const MTRAttestationVerificationResultKey MTR_PROVISIONALLY_AVAILABLE;

/**
* NSNumber userInfo keys carrying the vendor ID and product ID the device asserts in its
* BasicInformation cluster, captured at the time of attestation verification. Present in
* NSError userInfo for attestation-related failures so callers can identify which device's
* chain failed validation without walking the attestation-device-info struct themselves.
*
* These values are exactly what the device claims in its BasicInformation cluster — there
* is no guarantee the device is certified. In fact, one of the possible attestation-failure
* modes is that these BasicInformation values do not match the IDs in the device's
* certification declaration. Useful for triage and incident correlation, but should not
* be trusted as authoritative identity until attestation succeeds.
*/
MTR_EXTERN NSErrorUserInfoKey const MTRDeviceBasicInformationVendorIDKey MTR_PROVISIONALLY_AVAILABLE;
MTR_EXTERN NSErrorUserInfoKey const MTRDeviceBasicInformationProductIDKey MTR_PROVISIONALLY_AVAILABLE;

/**
* NSNumber userInfo key carrying the raw 32-bit underlying-error integer backing this NSError
* when it was bridged from an underlying Matter SDK error. Present on every error in
* MTRErrorDomain produced by the error bridge.
*
* The string value associated with this constant — i.e. the literal NSString returned by
* this NSErrorUserInfoKey when used as a dictionary key — is @"errorCode". That is the
* same literal key documented for MTRErrorCodeGeneralError below, so a caller reading
* userInfo[MTRUnderlyingErrorCodeKey] sees exactly the same NSNumber as a caller reading
* userInfo[@"errorCode"].
*
* This value is always populated by the bridge when an NSError in MTRErrorDomain is produced
* from a Matter SDK error, and is not overridable by internal callers — it is the
* authoritative integer underlying the bridged NSError.
*
* Intended for triage and log correlation; specific integer values are not stable across
* releases.
*/
MTR_EXTERN NSErrorUserInfoKey const MTRUnderlyingErrorCodeKey MTR_PROVISIONALLY_AVAILABLE;

/**
* MTRErrorDomain contains errors caused by data processing the framework
* itself is performing. These can be caused by invalid values provided to a
Expand All @@ -35,26 +82,33 @@ MTR_EXTERN NSErrorDomain const MTRInteractionErrorDomain MTR_AVAILABLE(ios(16.1)
* Errors reported by the server side of a Matter interaction via the normal
* Matter error-reporting mechanisms use MTRInteractionErrorDomain instead.
*/
typedef NS_ERROR_ENUM(MTRErrorDomain, MTRErrorCode){
typedef NS_ERROR_ENUM(MTRErrorDomain, MTRErrorCode) {
/**
* MTRErrorCodeGeneralError represents a generic Matter error with no
* further categorization.
*
* The userInfo will have a key named @"errorCode" whose value will be an
* integer representing the underlying Matter error code. These integer
* values should not be assumed to be stable across releases, but may be
* useful in logging and debugging.
* The userInfo will have MTRUnderlyingErrorCodeKey (string value
* @"errorCode") populated, whose value will be an NSNumber representing
* the underlying Matter error code. These integer values should not be
* assumed to be stable across releases, but may be useful in logging and
* debugging.
*
* Note: as of this release, MTRUnderlyingErrorCodeKey is present on
* EVERY error in MTRErrorDomain produced by the bridge, not just
* MTRErrorCodeGeneralError. Do not use the presence of this key as a
* discriminator for GeneralError; check error.code ==
* MTRErrorCodeGeneralError instead.
*/
MTRErrorCodeGeneralError = 1,
MTRErrorCodeInvalidStringLength = 2,
MTRErrorCodeInvalidIntegerValue = 3,
MTRErrorCodeInvalidArgument = 4,
MTRErrorCodeGeneralError = 1,
MTRErrorCodeInvalidStringLength = 2,
MTRErrorCodeInvalidIntegerValue = 3,
MTRErrorCodeInvalidArgument = 4,
MTRErrorCodeInvalidMessageLength = 5,
MTRErrorCodeInvalidState = 6,
MTRErrorCodeWrongAddressType = 7,
MTRErrorCodeInvalidState = 6,
MTRErrorCodeWrongAddressType = 7,
MTRErrorCodeIntegrityCheckFailed = 8,
MTRErrorCodeTimeout = 9,
MTRErrorCodeBufferTooSmall = 10,
MTRErrorCodeTimeout = 9,
MTRErrorCodeBufferTooSmall = 10,

/**
* MTRErrorCodeFabricExists is returned when trying to commission a device
Expand Down Expand Up @@ -125,39 +179,75 @@ typedef NS_ERROR_ENUM(MTRErrorDomain, MTRErrorCode){
* was reported. This key will be absent if there was no cluster-specific
* status.
*/
typedef NS_ERROR_ENUM(MTRInteractionErrorDomain, MTRInteractionErrorCode){
typedef NS_ERROR_ENUM(MTRInteractionErrorDomain, MTRInteractionErrorCode) {
// These values come from the general status code table in the Matter
// Interaction Model specification.
MTRInteractionErrorCodeFailure = 0x01,
MTRInteractionErrorCodeInvalidSubscription = 0x7d,
MTRInteractionErrorCodeUnsupportedAccess = 0x7e,
MTRInteractionErrorCodeUnsupportedEndpoint = 0x7f,
MTRInteractionErrorCodeInvalidAction = 0x80,
MTRInteractionErrorCodeUnsupportedCommand = 0x81,
MTRInteractionErrorCodeInvalidCommand = 0x85,
MTRInteractionErrorCodeUnsupportedAttribute = 0x86,
MTRInteractionErrorCodeConstraintError = 0x87,
MTRInteractionErrorCodeUnsupportedWrite = 0x88,
MTRInteractionErrorCodeResourceExhausted = 0x89,
MTRInteractionErrorCodeNotFound = 0x8b,
MTRInteractionErrorCodeUnreportableAttribute = 0x8c,
MTRInteractionErrorCodeInvalidDataType = 0x8d,
MTRInteractionErrorCodeUnsupportedRead = 0x8f,
MTRInteractionErrorCodeDataVersionMismatch = 0x92,
MTRInteractionErrorCodeTimeout = 0x94,
MTRInteractionErrorCodeBusy = 0x9c,
MTRInteractionErrorCodeAccessRestricted MTR_AVAILABLE(ios(26.0), macos(26.0), watchos(26.0), tvos(26.0)) = 0x9d,
MTRInteractionErrorCodeUnsupportedCluster = 0xc3,
MTRInteractionErrorCodeNoUpstreamSubscription = 0xc5,
MTRInteractionErrorCodeNeedsTimedInteraction = 0xc6,
MTRInteractionErrorCodeUnsupportedEvent = 0xc7,
MTRInteractionErrorCodePathsExhausted = 0xc8,
MTRInteractionErrorCodeTimedRequestMismatch = 0xc9,
MTRInteractionErrorCodeFailsafeRequired = 0xca,
MTRInteractionErrorCodeInvalidInState MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0xcb,
MTRInteractionErrorCodeFailure = 0x01,
MTRInteractionErrorCodeInvalidSubscription = 0x7d,
MTRInteractionErrorCodeUnsupportedAccess = 0x7e,
MTRInteractionErrorCodeUnsupportedEndpoint = 0x7f,
MTRInteractionErrorCodeInvalidAction = 0x80,
MTRInteractionErrorCodeUnsupportedCommand = 0x81,
MTRInteractionErrorCodeInvalidCommand = 0x85,
MTRInteractionErrorCodeUnsupportedAttribute = 0x86,
MTRInteractionErrorCodeConstraintError = 0x87,
MTRInteractionErrorCodeUnsupportedWrite = 0x88,
MTRInteractionErrorCodeResourceExhausted = 0x89,
MTRInteractionErrorCodeNotFound = 0x8b,
MTRInteractionErrorCodeUnreportableAttribute = 0x8c,
MTRInteractionErrorCodeInvalidDataType = 0x8d,
MTRInteractionErrorCodeUnsupportedRead = 0x8f,
MTRInteractionErrorCodeDataVersionMismatch = 0x92,
MTRInteractionErrorCodeTimeout = 0x94,
MTRInteractionErrorCodeBusy = 0x9c,
MTRInteractionErrorCodeAccessRestricted MTR_AVAILABLE(ios(26.0), macos(26.0), watchos(26.0), tvos(26.0)) = 0x9d,
MTRInteractionErrorCodeUnsupportedCluster = 0xc3,
MTRInteractionErrorCodeNoUpstreamSubscription = 0xc5,
MTRInteractionErrorCodeNeedsTimedInteraction = 0xc6,
MTRInteractionErrorCodeUnsupportedEvent = 0xc7,
MTRInteractionErrorCodePathsExhausted = 0xc8,
MTRInteractionErrorCodeTimedRequestMismatch = 0xc9,
MTRInteractionErrorCodeFailsafeRequired = 0xca,
MTRInteractionErrorCodeInvalidInState MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0xcb,
MTRInteractionErrorCodeNoCommandResponse MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) = 0xcc,
MTRInteractionErrorCodeDynamicConstraintError MTR_PROVISIONALLY_AVAILABLE = 0xcf,
MTRInteractionErrorCodeInvalidTransportType MTR_PROVISIONALLY_AVAILABLE = 0xd1,
MTRInteractionErrorCodeDynamicConstraintError MTR_PROVISIONALLY_AVAILABLE = 0xcf,
MTRInteractionErrorCodeInvalidTransportType MTR_PROVISIONALLY_AVAILABLE = 0xd1,
} MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1));

/**
* Accessors for source-location information that may be attached to NSError objects
* bridged from the underlying Matter error type. The information is available when the
* underlying SDK was built to record source locations; otherwise the accessors return
* nil / 0.
*
* Lifetime caveat: these accessors are backed by an associated object attached to the
* NSError instance at bridge time. Associated objects are not preserved by NSCoding or
* NSCopying — if the NSError is archived, unarchived, or copied through any mechanism
* that does not propagate associated objects (NSKeyedArchiver, [error copy], crossing
* an XPC boundary, etc.), these accessors will return nil / 0 on the resulting object
* even when the original would have returned a value.
*
* For MTRInteractionErrorDomain errors the source location reflects the StatusIB
* encoding site inside the Matter SDK, not the device-reported origin of the status.
*/
@interface NSError (Matter)

/**
* The source-file basename where the underlying Matter error was originally created.
* Returns nil when the SDK did not record a source location, when the error was not
* bridged from a Matter error, or when no source string was captured.
*
* Only the basename is exposed — the full path is intentionally elided to avoid leaking
* build-host paths. Intended for triage; not stable across releases.
*/
@property (nonatomic, readonly, nullable) NSString * mtr_underlyingMatterErrorSourceFile MTR_PROVISIONALLY_AVAILABLE;

/**
* The source-line where the underlying Matter error was originally created. Returns 0
* when not available.
*/
@property (nonatomic, readonly) NSUInteger mtr_underlyingMatterErrorSourceLine MTR_PROVISIONALLY_AVAILABLE;

@end

NS_ASSUME_NONNULL_END
Loading
Loading