Add new API so it's possible to not leak a key (#36299)

* Initial checkin

* Fixing review feedback

* Adding braces

* Restyled by clang-format

* Fixing build

* Restyled by clang-format

* Fixing annotations

* Update src/darwin/Framework/CHIP/MTRKeypair.h

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* separate statements involving _mPublicKey to make compiler happy

* use `CFAutorelease` on CoreFoundation typed public key copies

* fix indent

* implement `copyPublicKey` for `MTRTestKeys`; add TODO note about optional method calls

* remove comment

it's a test; this is the best we can do with an optional protocol method

* consistent formatting for `copyPublicKey` calls

* reformat `copyPublicKey` in `MTRTestKeys`

remove comment - not this method's job to worry about other implementation's potential side-effects

* Update src/darwin/Framework/CHIP/MTRKeypair.h

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

---------

Co-authored-by: Restyled.io <commits@restyled.io>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
Co-authored-by: Kiel Oleson <kielo@apple.com>
diff --git a/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.h b/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.h
index f0ee3f8..58be7f2 100644
--- a/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.h
+++ b/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.h
@@ -22,7 +22,7 @@
 @interface CHIPToolKeypair : NSObject <MTRKeypair>
 - (BOOL)initialize;
 - (NSData *)signMessageECDSA_RAW:(NSData *)message;
-- (SecKeyRef)publicKey;
+- (SecKeyRef)copyPublicKey;
 - (CHIP_ERROR)Serialize:(chip::Crypto::P256SerializedKeypair &)output;
 - (CHIP_ERROR)Deserialize:(chip::Crypto::P256SerializedKeypair &)input;
 - (CHIP_ERROR)createOrLoadKeys:(id)storage;
diff --git a/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.mm b/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.mm
index ce0ef58..a09975d 100644
--- a/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.mm
+++ b/examples/darwin-framework-tool/commands/common/CHIPToolKeypair.mm
@@ -65,7 +65,7 @@
     return out_signature;
 }
 
-- (SecKeyRef)publicKey
+- (SecKeyRef)copyPublicKey
 {
     if (_mPublicKey == nil) {
         chip::Crypto::P256PublicKey publicKey = _mKeyPair.Pubkey();
@@ -79,7 +79,13 @@
         };
         _mPublicKey = SecKeyCreateWithData((__bridge CFDataRef) publicKeyNSData, (__bridge CFDictionaryRef) attributes, nullptr);
     }
-    return _mPublicKey;
+
+    if (_mPublicKey) {
+        CFRetain(_mPublicKey);
+        return _mPublicKey;
+    }
+
+    return NULL;
 }
 
 - (CHIP_ERROR)Deserialize:(chip::Crypto::P256SerializedKeypair &)input
diff --git a/src/darwin/Framework/CHIP/MTRCertificates.mm b/src/darwin/Framework/CHIP/MTRCertificates.mm
index b153cf4..7dcec96 100644
--- a/src/darwin/Framework/CHIP/MTRCertificates.mm
+++ b/src/darwin/Framework/CHIP/MTRCertificates.mm
@@ -152,7 +152,24 @@
 + (BOOL)keypair:(id<MTRKeypair>)keypair matchesCertificate:(NSData *)certificate
 {
     P256PublicKey keypairPubKey;
-    CHIP_ERROR err = MTRP256KeypairBridge::MatterPubKeyFromSecKeyRef(keypair.publicKey, &keypairPubKey);
+    SecKeyRef publicKey = NULL;
+
+    if ([keypair respondsToSelector:@selector(copyPublicKey)]) {
+        publicKey = [keypair copyPublicKey];
+    } else {
+        publicKey = [keypair publicKey];
+        if (publicKey) {
+            CFRetain(publicKey);
+        }
+    }
+
+    CHIP_ERROR err = MTRP256KeypairBridge::MatterPubKeyFromSecKeyRef(publicKey, &keypairPubKey);
+
+    if (publicKey != NULL) {
+        CFRelease(publicKey);
+        publicKey = NULL;
+    }
+
     if (err != CHIP_NO_ERROR) {
         MTR_LOG_ERROR("Can't extract public key from keypair: %s", ErrorStr(err));
         return NO;
diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
index 9de5143..e287ef0 100644
--- a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
+++ b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm
@@ -819,7 +819,24 @@
     } else {
         // No root certificate means the nocSigner is using the root keys, because
         // consumers must provide a root certificate whenever an ICA is used.
-        CHIP_ERROR err = MTRP256KeypairBridge::MatterPubKeyFromSecKeyRef(params.nocSigner.publicKey, &pubKey);
+        SecKeyRef publicKey = NULL;
+
+        if ([params.nocSigner respondsToSelector:@selector(copyPublicKey)]) {
+            publicKey = [params.nocSigner copyPublicKey];
+        } else {
+            publicKey = [params.nocSigner publicKey];
+            if (publicKey) {
+                CFRetain(publicKey);
+            }
+        }
+
+        CHIP_ERROR err = MTRP256KeypairBridge::MatterPubKeyFromSecKeyRef(publicKey, &pubKey);
+
+        if (publicKey != NULL) {
+            CFRelease(publicKey);
+            publicKey = NULL;
+        }
+
         if (err != CHIP_NO_ERROR) {
             MTR_LOG_ERROR("Can't extract public key from MTRKeypair: %s", ErrorStr(err));
             return NO;
diff --git a/src/darwin/Framework/CHIP/MTRKeypair.h b/src/darwin/Framework/CHIP/MTRKeypair.h
index a4e4521..d7381fe 100644
--- a/src/darwin/Framework/CHIP/MTRKeypair.h
+++ b/src/darwin/Framework/CHIP/MTRKeypair.h
@@ -16,6 +16,7 @@
  */
 
 #import <Foundation/Foundation.h>
+#import <Matter/Matter.h>
 #import <Security/Security.h>
 
 NS_ASSUME_NONNULL_BEGIN
@@ -31,14 +32,20 @@
  * framework APIs.
  */
 @protocol MTRKeypair <NSObject>
-@required
-/**
- * @brief Return public key for the keypair.
- */
-- (SecKeyRef)publicKey;
 
 @optional
 /**
+ * @brief Returns a copy of the public key for the keypair.
+ */
+- (SecKeyRef)copyPublicKey MTR_NEWLY_AVAILABLE;
+
+/**
+ * @brief Returns public key for the keypair without adding a reference. DEPRECATED - please use copyPublicKey, otherwise this will leak.
+ */
+
+- (SecKeyRef)publicKey MTR_DEPRECATED("Please implement copyPublicKey, this will leak otherwise", ios(16.1, 18.3), macos(13.0, 15.3), watchos(9.1, 11.3), tvos(16.1, 18.3));
+
+/**
  * @brief A function to sign a message using ECDSA
  *
  * @param message Message that needs to be signed
diff --git a/src/darwin/Framework/CHIPTests/MTRCertificateTests.m b/src/darwin/Framework/CHIPTests/MTRCertificateTests.m
index fb6cfb9..d5be54e 100644
--- a/src/darwin/Framework/CHIPTests/MTRCertificateTests.m
+++ b/src/darwin/Framework/CHIPTests/MTRCertificateTests.m
@@ -127,9 +127,13 @@
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
 
+    __auto_type * intermediatePublicKey = [intermediateKeys copyPublicKey];
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
+
     __auto_type * intermediateCert = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                     rootCertificate:rootCert
-                                                              intermediatePublicKey:intermediateKeys.publicKey
+                                                              intermediatePublicKey:intermediatePublicKey
                                                                            issuerID:nil
                                                                            fabricID:nil
                                                                               error:nil];
@@ -155,13 +159,16 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = intermediateKeys.copyPublicKey;
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * startDate = [MTRCertificateTests startDateWithTimeIntervalSinceNow:300];
     __auto_type * validityPeriod = [[NSDateInterval alloc] initWithStartDate:startDate duration:400];
 
     __auto_type * intermediateCert = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                     rootCertificate:rootCert
-                                                              intermediatePublicKey:intermediateKeys.publicKey
+                                                              intermediatePublicKey:intermediatePublicKey
                                                                            issuerID:nil
                                                                            fabricID:nil
                                                                      validityPeriod:validityPeriod
@@ -192,13 +199,16 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = intermediateKeys.copyPublicKey;
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * startDate = [MTRCertificateTests startDateWithTimeIntervalSinceNow:300];
     __auto_type * validityPeriod = [[NSDateInterval alloc] initWithStartDate:startDate endDate:[NSDate distantFuture]];
 
     __auto_type * intermediateCert = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                     rootCertificate:rootCert
-                                                              intermediatePublicKey:intermediateKeys.publicKey
+                                                              intermediatePublicKey:intermediatePublicKey
                                                                            issuerID:nil
                                                                            fabricID:nil
                                                                      validityPeriod:validityPeriod
@@ -229,6 +239,9 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * cats = [[NSMutableSet alloc] initWithCapacity:3];
     // High bits are identifier, low bits are version.
@@ -238,7 +251,7 @@
 
     __auto_type * operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                                signingCertificate:rootCert
-                                                             operationalPublicKey:operationalKeys.publicKey
+                                                             operationalPublicKey:operationalPublicKey
                                                                          fabricID:@1
                                                                            nodeID:@1
                                                             caseAuthenticatedTags:cats
@@ -265,6 +278,9 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * cats = [[NSMutableSet alloc] initWithCapacity:3];
     // High bits are identifier, low bits are version.
@@ -277,7 +293,7 @@
 
     __auto_type * operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                                signingCertificate:rootCert
-                                                             operationalPublicKey:operationalKeys.publicKey
+                                                             operationalPublicKey:operationalPublicKey
                                                                          fabricID:@1
                                                                            nodeID:@1
                                                             caseAuthenticatedTags:cats
@@ -309,6 +325,9 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * cats = [[NSMutableSet alloc] initWithCapacity:3];
     // High bits are identifier, low bits are version.
@@ -321,7 +340,7 @@
 
     __auto_type * operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                                signingCertificate:rootCert
-                                                             operationalPublicKey:operationalKeys.publicKey
+                                                             operationalPublicKey:operationalPublicKey
                                                                          fabricID:@1
                                                                            nodeID:@1
                                                             caseAuthenticatedTags:cats
@@ -353,10 +372,13 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = [intermediateKeys copyPublicKey];
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediateCert = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                     rootCertificate:rootCert
-                                                              intermediatePublicKey:intermediateKeys.publicKey
+                                                              intermediatePublicKey:intermediatePublicKey
                                                                            issuerID:nil
                                                                            fabricID:nil
                                                                               error:nil];
@@ -364,10 +386,13 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * operationalCert = [MTRCertificates createOperationalCertificate:intermediateKeys
                                                                signingCertificate:intermediateCert
-                                                             operationalPublicKey:operationalKeys.publicKey
+                                                             operationalPublicKey:operationalPublicKey
                                                                          fabricID:@1
                                                                            nodeID:@1
                                                             caseAuthenticatedTags:nil
@@ -394,6 +419,9 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * longCats = [[NSMutableSet alloc] initWithCapacity:4];
     [longCats addObject:@0x00010001];
@@ -415,7 +443,7 @@
     // Check basic case works
     __auto_type * operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                                signingCertificate:rootCert
-                                                             operationalPublicKey:operationalKeys.publicKey
+                                                             operationalPublicKey:operationalPublicKey
                                                                          fabricID:@1
                                                                            nodeID:@1
                                                             caseAuthenticatedTags:nil
@@ -425,7 +453,7 @@
     // CATs too long
     operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                  signingCertificate:rootCert
-                                               operationalPublicKey:operationalKeys.publicKey
+                                               operationalPublicKey:operationalPublicKey
                                                            fabricID:@1
                                                              nodeID:@1
                                               caseAuthenticatedTags:longCats
@@ -435,7 +463,7 @@
     // Multiple CATs with the same identifier but different versions
     operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                  signingCertificate:rootCert
-                                               operationalPublicKey:operationalKeys.publicKey
+                                               operationalPublicKey:operationalPublicKey
                                                            fabricID:@1
                                                              nodeID:@1
                                               caseAuthenticatedTags:catsWithSameIdentifier
@@ -445,7 +473,7 @@
     // CAT with invalid version
     operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                  signingCertificate:rootCert
-                                               operationalPublicKey:operationalKeys.publicKey
+                                               operationalPublicKey:operationalPublicKey
                                                            fabricID:@1
                                                              nodeID:@1
                                               caseAuthenticatedTags:catsWithInvalidVersion
@@ -455,7 +483,7 @@
     // Signing key mismatch
     operationalCert = [MTRCertificates createOperationalCertificate:operationalKeys
                                                  signingCertificate:rootCert
-                                               operationalPublicKey:operationalKeys.publicKey
+                                               operationalPublicKey:operationalPublicKey
                                                            fabricID:@1
                                                              nodeID:@1
                                               caseAuthenticatedTags:nil
@@ -465,7 +493,7 @@
     // Invalid fabric id
     operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                  signingCertificate:rootCert
-                                               operationalPublicKey:operationalKeys.publicKey
+                                               operationalPublicKey:operationalPublicKey
                                                            fabricID:@0
                                                              nodeID:@1
                                               caseAuthenticatedTags:nil
@@ -475,7 +503,7 @@
     // Undefined node id
     operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                  signingCertificate:rootCert
-                                               operationalPublicKey:operationalKeys.publicKey
+                                               operationalPublicKey:operationalPublicKey
                                                            fabricID:@1
                                                              nodeID:@0
                                               caseAuthenticatedTags:nil
@@ -485,7 +513,7 @@
     // Non-operational node id
     operationalCert = [MTRCertificates createOperationalCertificate:rootKeys
                                                  signingCertificate:rootCert
-                                               operationalPublicKey:operationalKeys.publicKey
+                                               operationalPublicKey:operationalPublicKey
                                                            fabricID:@1
                                                              nodeID:@(0xFFFFFFFFFFFFFFFFLLU)
                                               caseAuthenticatedTags:nil
diff --git a/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m b/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m
index ecc593e..719be07 100644
--- a/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m
+++ b/src/darwin/Framework/CHIPTests/MTRCertificateValidityTests.m
@@ -259,10 +259,13 @@
 
     __auto_type * controllerOperationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(controllerOperationalKeys);
+    __auto_type * controllerPublicKey = controllerOperationalKeys.copyPublicKey;
+    XCTAssert(controllerPublicKey != NULL);
+    CFAutorelease(controllerPublicKey);
 
     __auto_type * controllerOperationalCert =
         [certificateIssuer issueOperationalCertificateForNode:@(kControllerId)
-                                         operationalPublicKey:controllerOperationalKeys.publicKey];
+                                         operationalPublicKey:controllerPublicKey];
     XCTAssertNotNil(controllerOperationalCert);
 
     __auto_type * params = [[MTRDeviceControllerStartupParams alloc] initWithIPK:certificateIssuer.rootKey.ipk
diff --git a/src/darwin/Framework/CHIPTests/MTRControllerAdvertisingTests.m b/src/darwin/Framework/CHIPTests/MTRControllerAdvertisingTests.m
index 4092a38..bee6ee9 100644
--- a/src/darwin/Framework/CHIPTests/MTRControllerAdvertisingTests.m
+++ b/src/darwin/Framework/CHIPTests/MTRControllerAdvertisingTests.m
@@ -164,10 +164,13 @@
     __auto_type * root = [MTRCertificates createRootCertificate:rootKeys issuerID:@(1) fabricID:nil error:error];
     XCTAssertNil(*error);
     XCTAssertNotNil(root);
+    __auto_type * publicKey = operationalKeys.copyPublicKey;
+    XCTAssert(publicKey != NULL);
+    CFAutorelease(publicKey);
 
     __auto_type * operational = [MTRCertificates createOperationalCertificate:rootKeys
                                                            signingCertificate:root
-                                                         operationalPublicKey:operationalKeys.publicKey
+                                                         operationalPublicKey:publicKey
                                                                      fabricID:fabricID
                                                                        nodeID:nodeID
                                                         caseAuthenticatedTags:nil
diff --git a/src/darwin/Framework/CHIPTests/MTRControllerTests.m b/src/darwin/Framework/CHIPTests/MTRControllerTests.m
index 436a0df..afd755f 100644
--- a/src/darwin/Framework/CHIPTests/MTRControllerTests.m
+++ b/src/darwin/Framework/CHIPTests/MTRControllerTests.m
@@ -620,10 +620,13 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = [intermediateKeys copyPublicKey];
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                 rootCertificate:root
-                                                          intermediatePublicKey:intermediateKeys.publicKey
+                                                          intermediatePublicKey:intermediatePublicKey
                                                                        issuerID:nil
                                                                        fabricID:nil
                                                                           error:nil];
@@ -860,10 +863,12 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = intermediateKeys.copyPublicKey;
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                 rootCertificate:root
-                                                          intermediatePublicKey:intermediateKeys.publicKey
+                                                          intermediatePublicKey:intermediatePublicKey
                                                                        issuerID:nil
                                                                        fabricID:nil
                                                                           error:nil];
@@ -922,10 +927,13 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = [intermediateKeys copyPublicKey];
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                 rootCertificate:root
-                                                          intermediatePublicKey:intermediateKeys.publicKey
+                                                          intermediatePublicKey:intermediatePublicKey
                                                                        issuerID:nil
                                                                        fabricID:nil
                                                                           error:nil];
@@ -986,10 +994,13 @@
 
     __auto_type * intermediateKeys1 = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys1);
+    __auto_type * intermediate1PublicKey = [intermediateKeys1 copyPublicKey];
+    XCTAssert(intermediate1PublicKey != NULL);
+    CFAutorelease(intermediate1PublicKey);
 
     __auto_type * intermediate1 = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                  rootCertificate:root
-                                                           intermediatePublicKey:intermediateKeys1.publicKey
+                                                           intermediatePublicKey:intermediate1PublicKey
                                                                         issuerID:nil
                                                                         fabricID:nil
                                                                            error:nil];
@@ -997,10 +1008,13 @@
 
     __auto_type * intermediateKeys2 = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys2);
+    __auto_type * intermediate2PublicKey = [intermediateKeys2 copyPublicKey];
+    XCTAssert(intermediate2PublicKey != NULL);
+    CFAutorelease(intermediate2PublicKey);
 
     __auto_type * intermediate2 = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                  rootCertificate:root
-                                                           intermediatePublicKey:intermediateKeys2.publicKey
+                                                           intermediatePublicKey:intermediate2PublicKey
                                                                         issuerID:nil
                                                                         fabricID:nil
                                                                            error:nil];
@@ -1061,10 +1075,13 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = [intermediateKeys copyPublicKey];
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                 rootCertificate:root
-                                                          intermediatePublicKey:intermediateKeys.publicKey
+                                                          intermediatePublicKey:intermediatePublicKey
                                                                        issuerID:nil
                                                                        fabricID:nil
                                                                           error:nil];
@@ -1104,10 +1121,13 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = [intermediateKeys copyPublicKey];
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                 rootCertificate:root
-                                                          intermediatePublicKey:intermediateKeys.publicKey
+                                                          intermediatePublicKey:intermediatePublicKey
                                                                        issuerID:nil
                                                                        fabricID:nil
                                                                           error:nil];
@@ -1115,10 +1135,13 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * operational = [MTRCertificates createOperationalCertificate:intermediateKeys
                                                            signingCertificate:intermediate
-                                                         operationalPublicKey:operationalKeys.publicKey
+                                                         operationalPublicKey:operationalPublicKey
                                                                      fabricID:@123
                                                                        nodeID:@456
                                                         caseAuthenticatedTags:nil
@@ -1179,10 +1202,13 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * operational = [MTRCertificates createOperationalCertificate:rootKeys
                                                            signingCertificate:root
-                                                         operationalPublicKey:operationalKeys.publicKey
+                                                         operationalPublicKey:operationalPublicKey
                                                                      fabricID:@123
                                                                        nodeID:@456
                                                         caseAuthenticatedTags:nil
@@ -1229,10 +1255,13 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * operational = [MTRCertificates createOperationalCertificate:rootKeys
                                                            signingCertificate:root
-                                                         operationalPublicKey:operationalKeys.publicKey
+                                                         operationalPublicKey:operationalPublicKey
                                                                      fabricID:@123
                                                                        nodeID:@456
                                                         caseAuthenticatedTags:nil
@@ -1273,10 +1302,13 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = [intermediateKeys copyPublicKey];
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                 rootCertificate:root
-                                                          intermediatePublicKey:intermediateKeys.publicKey
+                                                          intermediatePublicKey:intermediatePublicKey
                                                                        issuerID:nil
                                                                        fabricID:@111
                                                                           error:nil];
@@ -1284,10 +1316,13 @@
 
     __auto_type * operationalKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(operationalKeys);
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
 
     __auto_type * operational = [MTRCertificates createOperationalCertificate:intermediateKeys
                                                            signingCertificate:intermediate
-                                                         operationalPublicKey:operationalKeys.publicKey
+                                                         operationalPublicKey:operationalPublicKey
                                                                      fabricID:@123
                                                                        nodeID:@456
                                                         caseAuthenticatedTags:nil
diff --git a/src/darwin/Framework/CHIPTests/MTRFabricInfoTests.m b/src/darwin/Framework/CHIPTests/MTRFabricInfoTests.m
index a980670..acdc0ea 100644
--- a/src/darwin/Framework/CHIPTests/MTRFabricInfoTests.m
+++ b/src/darwin/Framework/CHIPTests/MTRFabricInfoTests.m
@@ -157,10 +157,13 @@
 
     __auto_type * intermediateKeys = [[MTRTestKeys alloc] init];
     XCTAssertNotNil(intermediateKeys);
+    __auto_type * intermediatePublicKey = intermediateKeys.copyPublicKey;
+    XCTAssert(intermediatePublicKey != NULL);
+    CFAutorelease(intermediatePublicKey);
 
     __auto_type * intermediate = [MTRCertificates createIntermediateCertificate:rootKeys
                                                                 rootCertificate:root
-                                                          intermediatePublicKey:intermediateKeys.publicKey
+                                                          intermediatePublicKey:intermediatePublicKey
                                                                        issuerID:nil
                                                                        fabricID:nil
                                                                           error:nil];
diff --git a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m
index 1ead469..3aeadf0 100644
--- a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m
+++ b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m
@@ -403,9 +403,13 @@
     XCTAssertNil(*error);
     XCTAssertNotNil(root);
 
+    __auto_type * operationalPublicKey = [operationalKeys copyPublicKey];
+    XCTAssert(operationalPublicKey != NULL);
+    CFAutorelease(operationalPublicKey);
+
     __auto_type * operational = [MTRCertificates createOperationalCertificate:rootKeys
                                                            signingCertificate:root
-                                                         operationalPublicKey:operationalKeys.publicKey
+                                                         operationalPublicKey:operationalPublicKey
                                                                      fabricID:fabricID
                                                                        nodeID:nodeID
                                                         caseAuthenticatedTags:caseAuthenticatedTags
diff --git a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestKeys.m b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestKeys.m
index e6a74f2..090593a 100644
--- a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestKeys.m
+++ b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestKeys.m
@@ -31,6 +31,12 @@
     return (__bridge_transfer NSData *) SecKeyCopyExternalRepresentation([self publicKey], nil);
 }
 
+- (SecKeyRef)copyPublicKey
+{
+    CFRetain(_publicKey);
+    return _publicKey;
+}
+
 - (instancetype)init
 {
     if (!(self = [super init])) {