examples/tv-casting-app: Allow setting DACCredentials on iOS and add retry mechanism for commissioner discovery (#23692)
* MatterTvCastingBridge.Framework: Add a way to provide DAC creds
* Android tv-casting lib: Implementing a retry mechanism for commissioner service resolution using NsdManager
diff --git a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java
index 0fda34f..5ff6126 100644
--- a/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java
+++ b/examples/tv-casting-app/android/App/app/src/main/java/com/chip/casting/app/CommissionerDiscoveryFragment.java
@@ -107,6 +107,18 @@
}
};
+ Button discoverButton = getView().findViewById(R.id.discoverButton);
+ discoverButton.setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Log.d(TAG, "Discovering on button click");
+ tvCastingApp.discoverVideoPlayerCommissioners(
+ DISCOVERY_DURATION_SECS, successCallback, failureCallback);
+ }
+ });
+
+ Log.d(TAG, "Auto discovering");
tvCastingApp.discoverVideoPlayerCommissioners(
DISCOVERY_DURATION_SECS, successCallback, failureCallback);
}
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java
index e58f639..b0644c4 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdDiscoveryListener.java
@@ -71,7 +71,8 @@
preCommissionedVideoPlayers,
successCallback,
failureCallback,
- nsdManagerResolverAvailState));
+ nsdManagerResolverAvailState,
+ 1));
} else {
Log.d(TAG, "Ignoring discovered service: " + service.toString());
}
diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java
index 3232ed8..1593ab1 100644
--- a/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java
+++ b/examples/tv-casting-app/android/App/app/src/main/jni/com/chip/casting/NsdResolveListener.java
@@ -22,17 +22,23 @@
import android.util.Log;
import chip.platform.NsdManagerServiceResolver;
import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
public class NsdResolveListener implements NsdManager.ResolveListener {
private static final String TAG = NsdResolveListener.class.getSimpleName();
+ private static final int MAX_RESOLUTION_ATTEMPTS = 5;
+ private static final int RESOLUTION_ATTEMPT_DELAY_SECS = 1;
+
private final NsdManager nsdManager;
private final List<Long> deviceTypeFilter;
private final List<VideoPlayer> preCommissionedVideoPlayers;
private final SuccessCallback<DiscoveredNodeData> successCallback;
private final FailureCallback failureCallback;
private final NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState;
+ private final int resolutionAttemptNumber;
public NsdResolveListener(
NsdManager nsdManager,
@@ -40,7 +46,8 @@
List<VideoPlayer> preCommissionedVideoPlayers,
SuccessCallback<DiscoveredNodeData> successCallback,
FailureCallback failureCallback,
- NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState) {
+ NsdManagerServiceResolver.NsdManagerResolverAvailState nsdManagerResolverAvailState,
+ int resolutionAttemptNumber) {
this.nsdManager = nsdManager;
this.deviceTypeFilter = deviceTypeFilter;
this.preCommissionedVideoPlayers = preCommissionedVideoPlayers;
@@ -52,6 +59,7 @@
this.successCallback = successCallback;
this.failureCallback = failureCallback;
this.nsdManagerResolverAvailState = nsdManagerResolverAvailState;
+ this.resolutionAttemptNumber = resolutionAttemptNumber;
}
@Override
@@ -77,15 +85,41 @@
@Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
if (nsdManagerResolverAvailState != null) {
- nsdManagerResolverAvailState.signalFree();
+ if (errorCode != NsdManager.FAILURE_ALREADY_ACTIVE
+ || resolutionAttemptNumber >= MAX_RESOLUTION_ATTEMPTS) {
+ nsdManagerResolverAvailState.signalFree();
+ }
}
switch (errorCode) {
case NsdManager.FAILURE_ALREADY_ACTIVE:
Log.e(TAG, "NsdResolveListener FAILURE_ALREADY_ACTIVE - Service: " + serviceInfo);
- failureCallback.handle(
- new MatterError(
- 3, "NsdResolveListener FAILURE_ALREADY_ACTIVE - Service: " + serviceInfo));
+ if (resolutionAttemptNumber < MAX_RESOLUTION_ATTEMPTS) {
+ Log.d(TAG, "NsdResolveListener Scheduling a retry to resolve service " + serviceInfo);
+ Executors.newSingleThreadScheduledExecutor()
+ .schedule(
+ new Runnable() {
+ @Override
+ public void run() {
+ nsdManager.resolveService(
+ serviceInfo,
+ new NsdResolveListener(
+ nsdManager,
+ deviceTypeFilter,
+ preCommissionedVideoPlayers,
+ successCallback,
+ failureCallback,
+ nsdManagerResolverAvailState,
+ resolutionAttemptNumber + 1));
+ }
+ },
+ RESOLUTION_ATTEMPT_DELAY_SECS,
+ TimeUnit.SECONDS);
+ } else { // giving up
+ failureCallback.handle(
+ new MatterError(
+ 3, "NsdResolveListener FAILURE_ALREADY_ACTIVE - Service: " + serviceInfo));
+ }
break;
case NsdManager.FAILURE_INTERNAL_ERROR:
Log.e(TAG, "NsdResolveListener FAILURE_INTERNAL_ERROR - Service: " + serviceInfo);
diff --git a/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_commissioner_discovery.xml b/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_commissioner_discovery.xml
index 58238b5..c65a647 100644
--- a/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_commissioner_discovery.xml
+++ b/examples/tv-casting-app/android/App/app/src/main/res/layout/fragment_commissioner_discovery.xml
@@ -20,6 +20,12 @@
android:layout_height="wrap_content"
android:text="Skip to manual commissioning >>" />
+ <Button
+ android:id="@+id/discoverButton"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Discover>" />
+
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
index 7736fef..d85d5a6 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge.xcodeproj/project.pbxproj
@@ -7,6 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
+ 3C26AC8C2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3C26AC8B2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp */; };
+ 3C26AC902927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C26AC8F2927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm */; };
+ 3C26AC9329282B8100BA6881 /* DeviceAttestationCredentialsHolder.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C26AC9229282B8100BA6881 /* DeviceAttestationCredentialsHolder.m */; };
3C4AE650286A7D4D005B52A4 /* OnboardingPayload.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C4AE64F286A7D4D005B52A4 /* OnboardingPayload.m */; };
3C4E53B028E4F28100F293E8 /* MediaPlaybackTypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C4E53AF28E4F28100F293E8 /* MediaPlaybackTypes.mm */; };
3C4E53B228E5184C00F293E8 /* TargetNavigatorTypes.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C4E53B128E5184C00F293E8 /* TargetNavigatorTypes.mm */; };
@@ -28,6 +31,10 @@
/* Begin PBXFileReference section */
3C0D9CDF2920A30C00D3332B /* CommissionableDataProviderImpl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = CommissionableDataProviderImpl.hpp; sourceTree = "<group>"; };
+ 3C26AC8B2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DeviceAttestationCredentialsProviderImpl.hpp; sourceTree = "<group>"; };
+ 3C26AC8F2927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DeviceAttestationCredentialsProviderImpl.mm; sourceTree = "<group>"; };
+ 3C26AC91292700AD00BA6881 /* DeviceAttestationCredentialsHolder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DeviceAttestationCredentialsHolder.h; sourceTree = "<group>"; };
+ 3C26AC9229282B8100BA6881 /* DeviceAttestationCredentialsHolder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DeviceAttestationCredentialsHolder.m; sourceTree = "<group>"; };
3C4AE64E286A7D40005B52A4 /* OnboardingPayload.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OnboardingPayload.h; sourceTree = "<group>"; };
3C4AE64F286A7D4D005B52A4 /* OnboardingPayload.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OnboardingPayload.m; sourceTree = "<group>"; };
3C4E53AF28E4F28100F293E8 /* MediaPlaybackTypes.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaPlaybackTypes.mm; sourceTree = "<group>"; };
@@ -113,6 +120,10 @@
3C4E53AF28E4F28100F293E8 /* MediaPlaybackTypes.mm */,
3C4E53B328E5185F00F293E8 /* TargetNavigatorTypes.h */,
3C4E53B128E5184C00F293E8 /* TargetNavigatorTypes.mm */,
+ 3C26AC91292700AD00BA6881 /* DeviceAttestationCredentialsHolder.h */,
+ 3C26AC9229282B8100BA6881 /* DeviceAttestationCredentialsHolder.m */,
+ 3C26AC8B2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp */,
+ 3C26AC8F2927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm */,
3C0D9CDF2920A30C00D3332B /* CommissionableDataProviderImpl.hpp */,
);
path = MatterTvCastingBridge;
@@ -125,6 +136,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ 3C26AC8C2926FE0C00BA6881 /* DeviceAttestationCredentialsProviderImpl.hpp in Headers */,
3CCB8740286A593700771BAD /* CastingServerBridge.h in Headers */,
3CCB8742286A593700771BAD /* ConversionUtils.hpp in Headers */,
3CCB8741286A593700771BAD /* DiscoveredNodeData.h in Headers */,
@@ -229,6 +241,8 @@
3CCB8744286A593700771BAD /* ConversionUtils.mm in Sources */,
3C4E53B028E4F28100F293E8 /* MediaPlaybackTypes.mm in Sources */,
3C66FBFC290327BB00B63FE7 /* AppParameters.mm in Sources */,
+ 3C26AC9329282B8100BA6881 /* DeviceAttestationCredentialsHolder.m in Sources */,
+ 3C26AC902927008900BA6881 /* DeviceAttestationCredentialsProviderImpl.mm in Sources */,
3CCB873F286A593700771BAD /* DiscoveredNodeData.mm in Sources */,
3C81C74C28F7A777001CB9D1 /* ContentApp.mm in Sources */,
3C4AE650286A7D4D005B52A4 /* OnboardingPayload.m in Sources */,
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h
index e1da8ce..9297223 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/AppParameters.h
@@ -17,6 +17,7 @@
#import <Foundation/Foundation.h>
+#import "DeviceAttestationCredentialsHolder.h"
#import "OnboardingPayload.h"
#ifndef AppParameters_h
@@ -34,6 +35,8 @@
@property NSData * spake2pVerifier;
+@property DeviceAttestationCredentialsHolder * deviceAttestationCredentials;
+
@end
#endif /* AppParameters_h */
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
index 86ed73b..d2620f6 100644
--- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm
@@ -20,6 +20,7 @@
#import "CommissionableDataProviderImpl.hpp"
#import "ConversionUtils.hpp"
+#import "DeviceAttestationCredentialsProviderImpl.hpp"
#import "MatterCallbacks.h"
#import "OnboardingPayload.h"
@@ -39,6 +40,8 @@
@property chip::DeviceLayer::CommissionableDataProviderImpl * commissionableDataProvider;
+@property chip::Credentials::DeviceAttestationCredentialsProvider * deviceAttestationCredentialsProvider;
+
// queue used to serialize all work performed by the CastingServerBridge
@property (atomic) dispatch_queue_t chipWorkQueue;
@@ -109,6 +112,7 @@
CHIP_ERROR err = CHIP_NO_ERROR;
_commissionableDataProvider = new chip::DeviceLayer::CommissionableDataProviderImpl();
+ _deviceAttestationCredentialsProvider = chip::Credentials::Examples::GetExampleDACProvider();
_appParameters = appParameters;
AppParams cppAppParams;
if (_appParameters != nil) {
@@ -137,16 +141,55 @@
_commissionableDataProvider->SetSetupDiscriminator(_appParameters.onboardingPayload.setupDiscriminator);
}
- uint32_t setupPasscode = 0;
- uint16_t setupDiscriminator = 0;
- _commissionableDataProvider->GetSetupPasscode(setupPasscode);
- _commissionableDataProvider->GetSetupDiscriminator(setupDiscriminator);
- _onboardingPayload = [[OnboardingPayload alloc] initWithSetupPasscode:setupPasscode setupDiscriminator:setupDiscriminator];
+ if (_appParameters.deviceAttestationCredentials != nil) {
+ NSData * certificationDeclarationNsData = _appParameters.deviceAttestationCredentials.getCertificationDeclaration;
+ chip::MutableByteSpan certificationDeclaration
+ = chip::MutableByteSpan(const_cast<uint8_t *>(static_cast<const uint8_t *>(certificationDeclarationNsData.bytes)),
+ certificationDeclarationNsData.length);
+
+ NSData * firmwareInformationNsData = _appParameters.deviceAttestationCredentials.getFirmwareInformation;
+ chip::MutableByteSpan firmwareInformation
+ = chip::MutableByteSpan(const_cast<uint8_t *>(static_cast<const uint8_t *>(firmwareInformationNsData.bytes)),
+ firmwareInformationNsData.length);
+
+ NSData * deviceAttestationCertNsData = _appParameters.deviceAttestationCredentials.getDeviceAttestationCert;
+ chip::MutableByteSpan deviceAttestationCert
+ = chip::MutableByteSpan(const_cast<uint8_t *>(static_cast<const uint8_t *>(deviceAttestationCertNsData.bytes)),
+ deviceAttestationCertNsData.length);
+
+ NSData * productAttestationIntermediateCertNsData
+ = _appParameters.deviceAttestationCredentials.getProductAttestationIntermediateCert;
+ chip::MutableByteSpan productAttestationIntermediateCert = chip::MutableByteSpan(
+ const_cast<uint8_t *>(static_cast<const uint8_t *>(productAttestationIntermediateCertNsData.bytes)),
+ productAttestationIntermediateCertNsData.length);
+
+ NSData * deviceAttestationCertPrivateKeyNsData
+ = _appParameters.deviceAttestationCredentials.getDeviceAttestationCertPrivateKey;
+ chip::MutableByteSpan deviceAttestationCertPrivateKey = chip::MutableByteSpan(
+ const_cast<uint8_t *>(static_cast<const uint8_t *>(deviceAttestationCertPrivateKeyNsData.bytes)),
+ deviceAttestationCertPrivateKeyNsData.length);
+
+ NSData * deviceAttestationCertPublicKeyKeyNsData
+ = _appParameters.deviceAttestationCredentials.getDeviceAttestationCertPublicKeyKey;
+ chip::MutableByteSpan deviceAttestationCertPublicKeyKey = chip::MutableByteSpan(
+ const_cast<uint8_t *>(static_cast<const uint8_t *>(deviceAttestationCertPublicKeyKeyNsData.bytes)),
+ deviceAttestationCertPublicKeyKeyNsData.length);
+
+ _deviceAttestationCredentialsProvider = new DeviceAttestationCredentialsProviderImpl(&certificationDeclaration,
+ &firmwareInformation, &deviceAttestationCert, &productAttestationIntermediateCert, &deviceAttestationCertPrivateKey,
+ &deviceAttestationCertPublicKeyKey);
+ }
}
chip::DeviceLayer::SetCommissionableDataProvider(_commissionableDataProvider);
+ uint32_t setupPasscode = 0;
+ uint16_t setupDiscriminator = 0;
+ _commissionableDataProvider->GetSetupPasscode(setupPasscode);
+ _commissionableDataProvider->GetSetupDiscriminator(setupDiscriminator);
+ _onboardingPayload = [[OnboardingPayload alloc] initWithSetupPasscode:setupPasscode setupDiscriminator:setupDiscriminator];
+
// Initialize device attestation config
- SetDeviceAttestationCredentialsProvider(chip::Credentials::Examples::GetExampleDACProvider());
+ SetDeviceAttestationCredentialsProvider(_deviceAttestationCredentialsProvider);
// Initialize device attestation verifier from a constant version
{
@@ -176,7 +219,7 @@
dispatch_async(_chipWorkQueue, ^{
CHIP_ERROR err = CHIP_NO_ERROR;
AppParams appParam;
- if (appParameters != nil) {
+ if (appParameters == nil) {
err = CastingServer::GetInstance()->Init();
} else if ((err = [ConversionUtils convertToCppAppParamsInfoFrom:appParameters outAppParams:appParam]) == CHIP_NO_ERROR) {
err = CastingServer::GetInstance()->Init(&appParam);
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.h b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.h
new file mode 100644
index 0000000..b8d8ea4
--- /dev/null
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.h
@@ -0,0 +1,47 @@
+/**
+ *
+ * Copyright (c) 2020-2022 Project CHIP Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+#ifndef DeviceAttestationCredentialsHolder_h
+#define DeviceAttestationCredentialsHolder_h
+
+@interface DeviceAttestationCredentialsHolder : NSObject
+
+- (DeviceAttestationCredentialsHolder * _Nonnull)
+ initWithCertificationDeclaration:(NSData * _Nonnull)certificationDeclaration
+ firmwareInformation:(NSData * _Nonnull)firmwareInformation
+ deviceAttestationCert:(NSData * _Nonnull)deviceAttestationCert
+ productAttestationIntermediateCert:(NSData * _Nonnull)productAttestationIntermediateCert
+ deviceAttestationCertPrivateKey:(NSData * _Nonnull)deviceAttestationCertPrivateKey
+ deviceAttestationCertPublicKeyKey:(NSData * _Nonnull)deviceAttestationCertPublicKeyKey;
+
+- (NSData * _Nonnull)getCertificationDeclaration;
+
+- (NSData * _Nonnull)getFirmwareInformation;
+
+- (NSData * _Nonnull)getDeviceAttestationCert;
+
+- (NSData * _Nonnull)getProductAttestationIntermediateCert;
+
+- (NSData * _Nonnull)getDeviceAttestationCertPrivateKey;
+
+- (NSData * _Nonnull)getDeviceAttestationCertPublicKeyKey;
+
+@end
+
+#endif /* DeviceAttestationCredentialsHolder_h */
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.m b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.m
new file mode 100644
index 0000000..54e19d5
--- /dev/null
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsHolder.m
@@ -0,0 +1,89 @@
+/**
+ *
+ * Copyright (c) 2020-2022 Project CHIP Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "DeviceAttestationCredentialsHolder.h"
+
+#import <Foundation/Foundation.h>
+
+@interface DeviceAttestationCredentialsHolder ()
+
+@property NSData * certificationDeclaration;
+
+@property NSData * firmwareInformation;
+
+@property NSData * deviceAttestationCert;
+
+@property NSData * productAttestationIntermediateCert;
+
+@property NSData * deviceAttestationCertPrivateKey;
+
+@property NSData * deviceAttestationCertPublicKeyKey;
+
+@end
+
+@implementation DeviceAttestationCredentialsHolder
+
+- (DeviceAttestationCredentialsHolder * _Nonnull)
+ initWithCertificationDeclaration:(NSData * _Nonnull)certificationDeclaration
+ firmwareInformation:(NSData * _Nonnull)firmwareInformation
+ deviceAttestationCert:(NSData * _Nonnull)deviceAttestationCert
+ productAttestationIntermediateCert:(NSData * _Nonnull)productAttestationIntermediateCert
+ deviceAttestationCertPrivateKey:(NSData * _Nonnull)deviceAttestationCertPrivateKey
+ deviceAttestationCertPublicKeyKey:(NSData * _Nonnull)deviceAttestationCertPublicKeyKey
+{
+ self = [super init];
+ if (self) {
+ _certificationDeclaration = certificationDeclaration;
+ _firmwareInformation = firmwareInformation;
+ _deviceAttestationCert = deviceAttestationCert;
+ _productAttestationIntermediateCert = productAttestationIntermediateCert;
+ _deviceAttestationCertPrivateKey = deviceAttestationCertPrivateKey;
+ _deviceAttestationCertPublicKeyKey = deviceAttestationCertPublicKeyKey;
+ }
+ return self;
+}
+
+- (NSData * _Nonnull)getCertificationDeclaration
+{
+ return _certificationDeclaration;
+}
+
+- (NSData * _Nonnull)getFirmwareInformation;
+{
+ return _firmwareInformation;
+}
+
+- (NSData * _Nonnull)getDeviceAttestationCert;
+{
+ return _deviceAttestationCert;
+}
+
+- (NSData * _Nonnull)getProductAttestationIntermediateCert;
+{
+ return _productAttestationIntermediateCert;
+}
+
+- (NSData * _Nonnull)getDeviceAttestationCertPrivateKey;
+{
+ return _deviceAttestationCertPrivateKey;
+}
+
+- (NSData * _Nonnull)getDeviceAttestationCertPublicKeyKey;
+{
+ return _deviceAttestationCertPublicKeyKey;
+}
+@end
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.hpp b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.hpp
new file mode 100644
index 0000000..ba3558f
--- /dev/null
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.hpp
@@ -0,0 +1,57 @@
+/**
+ *
+ * Copyright (c) 2020-2022 Project CHIP Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <credentials/DeviceAttestationCredsProvider.h>
+#include <crypto/CHIPCryptoPAL.h>
+#include <lib/support/logging/CHIPLogging.h>
+
+class DeviceAttestationCredentialsProviderImpl : public chip::Credentials::DeviceAttestationCredentialsProvider
+{
+public:
+ DeviceAttestationCredentialsProviderImpl(chip::MutableByteSpan * certificationDeclaration,
+ chip::MutableByteSpan * firmwareInformation,
+ chip::MutableByteSpan * deviceAttestationCert,
+ chip::MutableByteSpan * productAttestationIntermediateCert,
+ chip::MutableByteSpan * deviceAttestationCertPrivateKey,
+ chip::MutableByteSpan * deviceAttestationCertPublicKeyKey);
+
+ CHIP_ERROR GetCertificationDeclaration(chip::MutableByteSpan & outCertificationDeclaration) override;
+ CHIP_ERROR GetFirmwareInformation(chip::MutableByteSpan & outFirmwareInformation) override;
+ CHIP_ERROR GetDeviceAttestationCert(chip::MutableByteSpan & outDeviceAttestationCert) override;
+ CHIP_ERROR GetProductAttestationIntermediateCert(chip::MutableByteSpan & outProductAttestationIntermediateCert) override;
+ CHIP_ERROR SignWithDeviceAttestationKey(const chip::ByteSpan & messageToSign,
+ chip::MutableByteSpan & outSignatureBuffer) override;
+
+private:
+ chip::MutableByteSpan mCertificationDeclaration;
+ chip::MutableByteSpan mFirmwareInformation;
+ chip::MutableByteSpan mDeviceAttestationCert;
+ chip::MutableByteSpan mProductAttestationIntermediateCert;
+ chip::MutableByteSpan mDeviceAttestationCertPrivateKey;
+ chip::MutableByteSpan mDeviceAttestationCertPublicKeyKey;
+
+ CHIP_ERROR LoadKeypairFromRaw(chip::ByteSpan privateKey, chip::ByteSpan publicKey, chip::Crypto::P256Keypair & keypair)
+ {
+ chip::Crypto::P256SerializedKeypair serialized_keypair;
+ ReturnErrorOnFailure(serialized_keypair.SetLength(privateKey.size() + publicKey.size()));
+ memcpy(serialized_keypair.Bytes(), publicKey.data(), publicKey.size());
+ memcpy(serialized_keypair.Bytes() + publicKey.size(), privateKey.data(), privateKey.size());
+ return keypair.Deserialize(serialized_keypair);
+ }
+};
diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.mm
new file mode 100644
index 0000000..59a0a70
--- /dev/null
+++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/DeviceAttestationCredentialsProviderImpl.mm
@@ -0,0 +1,137 @@
+/**
+ *
+ * Copyright (c) 2020-2022 Project CHIP Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DeviceAttestationCredentialsProviderImpl.hpp"
+
+#import <Foundation/Foundation.h>
+
+DeviceAttestationCredentialsProviderImpl::DeviceAttestationCredentialsProviderImpl(chip::MutableByteSpan * certificationDeclaration,
+ chip::MutableByteSpan * firmwareInformation, chip::MutableByteSpan * deviceAttestationCert,
+ chip::MutableByteSpan * productAttestationIntermediateCert, chip::MutableByteSpan * deviceAttestationCertPrivateKey,
+ chip::MutableByteSpan * deviceAttestationCertPublicKeyKey)
+{
+ if (certificationDeclaration != nullptr) {
+ mCertificationDeclaration
+ = chip::MutableByteSpan(new uint8_t[certificationDeclaration->size()], certificationDeclaration->size());
+ memcpy(mCertificationDeclaration.data(), certificationDeclaration->data(), certificationDeclaration->size());
+ }
+
+ if (firmwareInformation != nullptr) {
+ mFirmwareInformation = chip::MutableByteSpan(new uint8_t[firmwareInformation->size()], firmwareInformation->size());
+ memcpy(mFirmwareInformation.data(), firmwareInformation->data(), firmwareInformation->size());
+ }
+
+ if (deviceAttestationCert != nullptr) {
+ mDeviceAttestationCert = chip::MutableByteSpan(new uint8_t[deviceAttestationCert->size()], deviceAttestationCert->size());
+ memcpy(mDeviceAttestationCert.data(), deviceAttestationCert->data(), deviceAttestationCert->size());
+ }
+
+ if (productAttestationIntermediateCert != nullptr) {
+ mProductAttestationIntermediateCert = chip::MutableByteSpan(
+ new uint8_t[productAttestationIntermediateCert->size()], productAttestationIntermediateCert->size());
+ memcpy(mProductAttestationIntermediateCert.data(), productAttestationIntermediateCert->data(),
+ productAttestationIntermediateCert->size());
+ }
+
+ if (deviceAttestationCertPrivateKey != nullptr) {
+ mDeviceAttestationCertPrivateKey
+ = chip::MutableByteSpan(new uint8_t[deviceAttestationCertPrivateKey->size()], deviceAttestationCertPrivateKey->size());
+ memcpy(mDeviceAttestationCertPrivateKey.data(), deviceAttestationCertPrivateKey->data(),
+ deviceAttestationCertPrivateKey->size());
+ }
+
+ if (deviceAttestationCertPublicKeyKey != nullptr) {
+ mDeviceAttestationCertPublicKeyKey = chip::MutableByteSpan(
+ new uint8_t[deviceAttestationCertPublicKeyKey->size()], deviceAttestationCertPublicKeyKey->size());
+ memcpy(mDeviceAttestationCertPublicKeyKey.data(), deviceAttestationCertPublicKeyKey->data(),
+ deviceAttestationCertPublicKeyKey->size());
+ }
+}
+
+CHIP_ERROR DeviceAttestationCredentialsProviderImpl::GetCertificationDeclaration(
+ chip::MutableByteSpan & outCertificationDeclaration)
+{
+ if (mCertificationDeclaration.size() > 0) {
+ if (outCertificationDeclaration.size() >= mCertificationDeclaration.size()) {
+ memcpy(outCertificationDeclaration.data(), mCertificationDeclaration.data(), mCertificationDeclaration.size());
+ outCertificationDeclaration.reduce_size(mCertificationDeclaration.size());
+ } else {
+ return CHIP_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+ return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR DeviceAttestationCredentialsProviderImpl::GetFirmwareInformation(chip::MutableByteSpan & outFirmwareInformation)
+{
+ if (mFirmwareInformation.size() > 0) {
+ if (outFirmwareInformation.size() >= mFirmwareInformation.size()) {
+ memcpy(outFirmwareInformation.data(), mFirmwareInformation.data(), mFirmwareInformation.size());
+ outFirmwareInformation.reduce_size(mFirmwareInformation.size());
+ } else {
+ return CHIP_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+ return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR DeviceAttestationCredentialsProviderImpl::GetDeviceAttestationCert(chip::MutableByteSpan & outDeviceAttestationCert)
+{
+ if (mDeviceAttestationCert.size() > 0) {
+ if (outDeviceAttestationCert.size() >= mDeviceAttestationCert.size()) {
+ memcpy(outDeviceAttestationCert.data(), mDeviceAttestationCert.data(), mDeviceAttestationCert.size());
+ outDeviceAttestationCert.reduce_size(mDeviceAttestationCert.size());
+ } else {
+ return CHIP_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+ return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR DeviceAttestationCredentialsProviderImpl::GetProductAttestationIntermediateCert(
+ chip::MutableByteSpan & outProductAttestationIntermediateCert)
+{
+ if (mProductAttestationIntermediateCert.size() > 0) {
+ if (outProductAttestationIntermediateCert.size() >= mProductAttestationIntermediateCert.size()) {
+ memcpy(outProductAttestationIntermediateCert.data(), mProductAttestationIntermediateCert.data(),
+ mProductAttestationIntermediateCert.size());
+ outProductAttestationIntermediateCert.reduce_size(mProductAttestationIntermediateCert.size());
+ } else {
+ return CHIP_ERROR_BUFFER_TOO_SMALL;
+ }
+ }
+ return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR DeviceAttestationCredentialsProviderImpl::SignWithDeviceAttestationKey(
+ const chip::ByteSpan & messageToSign, chip::MutableByteSpan & outSignatureBuffer)
+{
+ ChipLogProgress(AppServer, "DeviceAttestationCredentialsProviderImpl::SignWithDeviceAttestationKey called");
+ chip::Crypto::P256ECDSASignature signature;
+ chip::Crypto::P256Keypair keypair;
+
+ VerifyOrReturnError(IsSpanUsable(outSignatureBuffer), CHIP_ERROR_INVALID_ARGUMENT);
+ VerifyOrReturnError(IsSpanUsable(messageToSign), CHIP_ERROR_INVALID_ARGUMENT);
+ VerifyOrReturnError(outSignatureBuffer.size() >= signature.Capacity(), CHIP_ERROR_BUFFER_TOO_SMALL);
+
+ // In a non-exemplary implementation, the public key is not needed here. It is used here merely because
+ // Crypto::P256Keypair is only (currently) constructable from raw keys if both private/public keys are present.
+ ReturnErrorOnFailure(LoadKeypairFromRaw(mDeviceAttestationCertPrivateKey, mDeviceAttestationCertPublicKeyKey, keypair));
+ ReturnErrorOnFailure(keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature));
+
+ return CopySpanToMutableSpan(chip::ByteSpan { signature.ConstBytes(), signature.Length() }, outSignatureBuffer);
+}