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);
+}