Skip to content

Commit e41bcd2

Browse files
Stop having CHIPTool depend on in-framework key generation. (#18221)
Allows us to remove the in-framework key generation bits.
1 parent afb7ccb commit e41bcd2

14 files changed

+334
-405
lines changed

examples/chip-tool-darwin/commands/common/CHIPCommandBridge.mm

+1-2
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,9 @@
5555

5656
constexpr const char * identities[] = { kIdentityAlpha, kIdentityBeta, kIdentityGamma };
5757
for (size_t i = 0; i < ArraySize(identities); ++i) {
58-
auto controllerParams = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:nocSigner];
58+
auto controllerParams = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:nocSigner ipk:ipk];
5959
controllerParams.vendorId = chip::VendorId::TestVendor1;
6060
controllerParams.fabricId = i + 1;
61-
controllerParams.ipk = ipk;
6261

6362
// We're not sure whether we're creating a new fabric or using an
6463
// existing one, so just try both.

src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
2C21071525D1A8F200DDA4AD /* MultiAdminViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C21071325D1A8F200DDA4AD /* MultiAdminViewController.m */; };
1212
2C460C2425D7594B000512D6 /* DeviceSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C460C2325D7594B000512D6 /* DeviceSelector.m */; };
1313
2C460C3225D97CB3000512D6 /* UnpairDevicesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C460C3025D97CB3000512D6 /* UnpairDevicesViewController.m */; };
14+
51C8E3FB28261DCF00D47D00 /* FabricKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 51C8E3FA28261DCF00D47D00 /* FabricKeys.m */; };
1415
991DC091247747F500C13860 /* EnumerateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 991DC090247747F500C13860 /* EnumerateViewController.m */; };
1516
997A639C253F93F7005C64E6 /* CHIP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 997A639B253F93F7005C64E6 /* CHIP.framework */; };
1617
997A639D253F93F7005C64E6 /* CHIP.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 997A639B253F93F7005C64E6 /* CHIP.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -62,6 +63,8 @@
6263
2C460C2325D7594B000512D6 /* DeviceSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeviceSelector.m; sourceTree = "<group>"; };
6364
2C460C3025D97CB3000512D6 /* UnpairDevicesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UnpairDevicesViewController.m; sourceTree = "<group>"; };
6465
2C460C3125D97CB3000512D6 /* UnpairDevicesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnpairDevicesViewController.h; sourceTree = "<group>"; };
66+
51C8E3F928261DCF00D47D00 /* FabricKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FabricKeys.h; sourceTree = "<group>"; };
67+
51C8E3FA28261DCF00D47D00 /* FabricKeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FabricKeys.m; sourceTree = "<group>"; };
6568
991DC08F247747F500C13860 /* EnumerateViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnumerateViewController.h; sourceTree = "<group>"; };
6669
991DC090247747F500C13860 /* EnumerateViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EnumerateViewController.m; sourceTree = "<group>"; };
6770
997A639B253F93F7005C64E6 /* CHIP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CHIP.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -245,6 +248,8 @@
245248
B232D8C0251A0EE200792CB4 /* Framework Helpers */ = {
246249
isa = PBXGroup;
247250
children = (
251+
51C8E3F928261DCF00D47D00 /* FabricKeys.h */,
252+
51C8E3FA28261DCF00D47D00 /* FabricKeys.m */,
248253
B2946A9924C9A7BF005C87D0 /* DefaultsUtils.h */,
249254
B2946A9A24C9A7BF005C87D0 /* DefaultsUtils.m */,
250255
);
@@ -401,6 +406,7 @@
401406
B243A6692513A73600E56FEA /* RootViewController.m in Sources */,
402407
B204A632244E1D0700C7C0E1 /* main.m in Sources */,
403408
B204A624244E1D0600C7C0E1 /* SceneDelegate.m in Sources */,
409+
51C8E3FB28261DCF00D47D00 /* FabricKeys.m in Sources */,
404410
B2946A4224C99D53005C87D0 /* WiFiViewController.m in Sources */,
405411
0CA0E0CF248599BB009087B9 /* OnOffViewController.m in Sources */,
406412
);

src/darwin/CHIPTool/CHIPTool/Framework Helpers/DefaultsUtils.m

+14-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
#import "DefaultsUtils.h"
19+
#import "FabricKeys.h"
1920

2021
NSString * const kCHIPToolDefaultsDomain = @"com.apple.chiptool";
2122
NSString * const kNetworkSSIDDefaultsKey = @"networkSSID";
@@ -81,7 +82,12 @@ void CHIPSetNextAvailableDeviceID(uint64_t id)
8182
return;
8283
}
8384

84-
__auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:nil];
85+
__auto_type * keys = [[FabricKeys alloc] init];
86+
if (keys == nil) {
87+
return;
88+
}
89+
90+
__auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:keys ipk:keys.ipk];
8591
params.vendorId = kTestVendorId;
8692
params.fabricId = 1;
8793

@@ -98,11 +104,17 @@ void CHIPSetNextAvailableDeviceID(uint64_t id)
98104

99105
CHIPDeviceController * CHIPRestartController(CHIPDeviceController * controller)
100106
{
107+
__auto_type * keys = [[FabricKeys alloc] init];
108+
if (keys == nil) {
109+
NSLog(@"No keys, can't restart controller");
110+
return controller;
111+
}
112+
101113
NSLog(@"Shutting down the stack");
102114
[controller shutdown];
103115

104116
NSLog(@"Starting up the stack");
105-
__auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:nil];
117+
__auto_type * params = [[CHIPDeviceControllerStartupParams alloc] initWithKeypair:keys ipk:keys.ipk];
106118
params.vendorId = kTestVendorId;
107119
params.fabricId = 1;
108120

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright (c) 2022 Project CHIP Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#import <CHIP/CHIP.h>
20+
#import <Foundation/Foundation.h>
21+
22+
/**
23+
* Management of the CA key and IPK for our fabric.
24+
*/
25+
26+
NS_ASSUME_NONNULL_BEGIN
27+
28+
@interface FabricKeys : NSObject <CHIPKeypair>
29+
30+
@property (readonly, nonatomic, strong) NSData * ipk;
31+
32+
- (instancetype)init;
33+
@end
34+
35+
NS_ASSUME_NONNULL_END
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/**
2+
* Copyright (c) 2022 Project CHIP Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import "FabricKeys.h"
18+
19+
#import <Security/SecKey.h>
20+
21+
@interface FabricKeys ()
22+
@property (readonly) SecKeyRef privateKey;
23+
@property (readonly) SecKeyRef publicKey;
24+
@end
25+
26+
static const NSString * kCHIPIPKKeyChainLabel = @"matter-tool.nodeopcerts.IPK:0";
27+
static const NSString * kCHIPCAKeyChainLabel = @"matter-tool.nodeopcerts.CA:0";
28+
29+
@implementation FabricKeys
30+
31+
+ (NSDictionary *)ipkParams
32+
{
33+
return @{
34+
(__bridge NSString *) kSecClass : (__bridge NSString *) kSecClassKey,
35+
(__bridge NSString *) kSecAttrApplicationLabel : kCHIPIPKKeyChainLabel,
36+
(__bridge NSString *) kSecAttrKeyClass : (__bridge NSString *) kSecAttrKeyClassSymmetric,
37+
};
38+
}
39+
40+
+ (NSData *)loadIPK
41+
{
42+
NSMutableDictionary * query = [[NSMutableDictionary alloc] initWithDictionary:[FabricKeys ipkParams]];
43+
query[(__bridge NSString *) kSecReturnData] = @(YES);
44+
45+
// The CFDataRef we get from SecItemCopyMatching allocates its buffer in a
46+
// way that zeroes it when deallocated.
47+
CFDataRef keyDataRef;
48+
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, (CFTypeRef *) &keyDataRef);
49+
if (status != errSecSuccess || keyDataRef == nil) {
50+
NSLog(@"Did not find IPK in the keychain");
51+
return nil;
52+
}
53+
54+
NSLog(@"Found an existing IPK in the keychain");
55+
NSData * keyData = CFBridgingRelease(keyDataRef);
56+
57+
return [[NSData alloc] initWithBase64EncodedData:keyData options:0];
58+
}
59+
60+
+ (NSData *)generateIPK
61+
{
62+
NSMutableDictionary * query = [[NSMutableDictionary alloc] initWithDictionary:[FabricKeys ipkParams]];
63+
64+
// First, delete any existing item, since otherwise trying to add the new item
65+
// later will fail. Ignore delete failure, since we might not have had the
66+
// item at all.
67+
SecItemDelete((__bridge CFDictionaryRef) query);
68+
69+
// Generate an IPK. For now, hardcoded to 16 bytes until the
70+
// framework exposes this constant.
71+
const size_t ipk_size = 16;
72+
NSMutableData * ipkData = [NSMutableData dataWithLength:ipk_size];
73+
if (ipkData == nil) {
74+
return nil;
75+
}
76+
77+
int status = SecRandomCopyBytes(kSecRandomDefault, ipk_size, [ipkData mutableBytes]);
78+
if (status != errSecSuccess) {
79+
NSLog(@"Failed to generate IPK : %d", status);
80+
return nil;
81+
}
82+
83+
query[(__bridge NSString *) kSecValueData] = [ipkData base64EncodedDataWithOptions:0];
84+
85+
OSStatus addStatus = SecItemAdd((__bridge CFDictionaryRef) query, NULL);
86+
if (addStatus != errSecSuccess) {
87+
NSLog(@"Failed to store IPK : %d", addStatus);
88+
return nil;
89+
}
90+
91+
return ipkData;
92+
}
93+
94+
+ (NSDictionary *)privateKeyParams
95+
{
96+
return @{
97+
(__bridge NSString *) kSecClass : (__bridge NSString *) kSecClassKey,
98+
(__bridge NSString *) kSecAttrApplicationLabel : kCHIPCAKeyChainLabel,
99+
// We're storing a base-64 encoding of some opaque thing that represents
100+
// our keypair. It's not really a public or private key; claim it's a
101+
// symmetric key.
102+
(__bridge NSString *) kSecAttrKeyClass : (__bridge NSString *) kSecAttrKeyClassSymmetric,
103+
};
104+
}
105+
106+
+ (NSDictionary *)privateKeyCreationParams
107+
{
108+
// For now harcoded to 256 bits until the framework exposes this constant.
109+
const size_t keySizeInBits = 256;
110+
111+
return @{
112+
(__bridge NSString *) kSecAttrKeyClass : (__bridge NSString *) kSecAttrKeyClassPrivate,
113+
(__bridge NSString *) kSecAttrKeyType : (__bridge NSNumber *) kSecAttrKeyTypeECSECPrimeRandom,
114+
(__bridge NSString *) kSecAttrKeySizeInBits : @(keySizeInBits),
115+
(__bridge NSString *) kSecAttrIsPermanent : @(NO)
116+
};
117+
}
118+
119+
+ (SecKeyRef)loadCAPrivateKey
120+
{
121+
NSMutableDictionary * query = [[NSMutableDictionary alloc] initWithDictionary:[FabricKeys privateKeyParams]];
122+
query[(__bridge NSString *) kSecReturnData] = @(YES);
123+
124+
// The CFDataRef we get from SecItemCopyMatching allocates its buffer in a
125+
// way that zeroes it when deallocated.
126+
CFDataRef keyDataRef;
127+
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, (CFTypeRef *) &keyDataRef);
128+
if (status != errSecSuccess || keyDataRef == nil) {
129+
NSLog(@"Did not find CA key in the keychain");
130+
return NULL;
131+
}
132+
133+
NSLog(@"Found an existing CA key in the keychain");
134+
NSData * encodedKey = CFBridgingRelease(keyDataRef);
135+
136+
NSData * keyData = [[NSData alloc] initWithBase64EncodedData:encodedKey options:0];
137+
if (keyData == nil) {
138+
NSLog(@"Could not base64-decode CA key");
139+
return NULL;
140+
}
141+
142+
CFErrorRef error = NULL;
143+
SecKeyRef key = SecKeyCreateWithData(
144+
(__bridge CFDataRef) keyData, (__bridge CFDictionaryRef)[FabricKeys privateKeyCreationParams], &error);
145+
if (error) {
146+
NSLog(@"Could not reconstruct private key %@", (__bridge NSError *) error);
147+
return NULL;
148+
}
149+
150+
return key;
151+
}
152+
153+
+ (SecKeyRef)generateCAPrivateKey
154+
{
155+
NSMutableDictionary * query = [[NSMutableDictionary alloc] initWithDictionary:[FabricKeys privateKeyParams]];
156+
157+
// First, delete any existing item, since otherwise trying to add the new item
158+
// later will fail. Ignore delete failure, since we might not have had the
159+
// item at all.
160+
SecItemDelete((__bridge CFDictionaryRef) query);
161+
162+
CFErrorRef error = NULL;
163+
SecKeyRef key = SecKeyCreateRandomKey((__bridge CFDictionaryRef)[FabricKeys privateKeyCreationParams], &error);
164+
if (error) {
165+
NSLog(@"Could not generate private key: %@", (__bridge NSError *) error);
166+
return NULL;
167+
}
168+
169+
NSData * keyData = (__bridge_transfer NSData *) SecKeyCopyExternalRepresentation(key, &error);
170+
if (error) {
171+
NSLog(@"Could not get key external representation: %@", (__bridge NSError *) error);
172+
CFRelease(key);
173+
return NULL;
174+
}
175+
176+
query[(__bridge NSString *) kSecValueData] = [keyData base64EncodedDataWithOptions:0];
177+
178+
OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL);
179+
if (status != errSecSuccess) {
180+
NSLog(@"Failed to store private key : %d", status);
181+
CFRelease(key);
182+
return NULL;
183+
}
184+
185+
return key;
186+
}
187+
188+
- (instancetype)init
189+
{
190+
if (!(self = [super init])) {
191+
return nil;
192+
}
193+
194+
if (!(_ipk = [FabricKeys loadIPK])) {
195+
if (!(_ipk = [FabricKeys generateIPK])) {
196+
return nil;
197+
}
198+
}
199+
200+
if (!(_privateKey = [FabricKeys loadCAPrivateKey])) {
201+
if (!(_privateKey = [FabricKeys generateCAPrivateKey])) {
202+
return nil;
203+
}
204+
}
205+
206+
_publicKey = SecKeyCopyPublicKey(_privateKey);
207+
return self;
208+
}
209+
210+
- (NSData *)ECDSA_sign_hash:(NSData *)hash
211+
{
212+
CFErrorRef error = NULL;
213+
CFDataRef outData
214+
= SecKeyCreateSignature(_privateKey, kSecKeyAlgorithmECDSASignatureRFC4754, (__bridge CFDataRef) hash, &error);
215+
216+
if (error != noErr) {
217+
NSLog(@"Failed to sign cert: %@", (__bridge NSError *) error);
218+
}
219+
return (__bridge_transfer NSData *) outData;
220+
}
221+
222+
- (SecKeyRef)pubkey
223+
{
224+
return self.publicKey;
225+
}
226+
227+
- (void)dealloc
228+
{
229+
if (_publicKey) {
230+
CFRelease(_publicKey);
231+
}
232+
233+
if (_privateKey) {
234+
CFRelease(_privateKey);
235+
}
236+
}
237+
@end

src/darwin/Framework/CHIP/CHIPDeviceController.mm

+5-7
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,9 @@ - (BOOL)startup:(CHIPDeviceControllerStartupParams *)startupParams
168168
CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
169169

170170
// create a CHIPP256KeypairBridge here and pass it to the operationalCredentialsDelegate
171-
std::unique_ptr<chip::Crypto::CHIPP256KeypairNativeBridge> nativeBridge;
172-
if (startupParams.rootCAKeypair != nil) {
173-
_keypairBridge.Init(startupParams.rootCAKeypair);
174-
nativeBridge.reset(new chip::Crypto::CHIPP256KeypairNativeBridge(_keypairBridge));
175-
}
171+
_keypairBridge.Init(startupParams.rootCAKeypair);
172+
auto nativeBridge = std::make_unique<chip::Crypto::CHIPP256KeypairNativeBridge>(_keypairBridge);
173+
176174
errorCode
177175
= _operationalCredentialsDelegate->init(_factory.storageDelegateBridge, std::move(nativeBridge), startupParams.ipk);
178176
if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorOperationalCredentialsInit]) {
@@ -723,18 +721,18 @@ - (CHIP_ERROR)isRunningOnFabric:(chip::FabricInfo *)fabric isRunning:(BOOL *)isR
723721

724722
@implementation CHIPDeviceControllerStartupParams
725723

726-
- (instancetype)initWithKeypair:(_Nullable id<CHIPKeypair>)rootCAKeypair
724+
- (instancetype)initWithKeypair:(id<CHIPKeypair>)rootCAKeypair ipk:(NSData *)ipk
727725
{
728726
if (!(self = [super init])) {
729727
return nil;
730728
}
731729

732730
_rootCAKeypair = rootCAKeypair;
731+
_ipk = ipk;
733732

734733
// Set various invalid values.
735734
_vendorId = chip::VendorId::Common;
736735
_fabricId = chip::kUndefinedFabricId;
737-
_ipk = nil;
738736

739737
return self;
740738
}

0 commit comments

Comments
 (0)