Skip to content

Commit 77d90bc

Browse files
xylophone21pull[bot]
authored andcommitted
add CommissionableDataProvider on android platform (#16475)
* add CommissionableDataProvider on android platform * fix restyled-io and ci errors * remove commented * fix restyled-io and ci errors * fix PR comment * fix restyled-io and ci errors * fix PR comment * fix restyled-io and ci errors * fix restyled-io and ci errors
1 parent ac7a1e5 commit 77d90bc

File tree

9 files changed

+331
-7
lines changed

9 files changed

+331
-7
lines changed

examples/tv-app/android/App/app/src/main/java/com/tcl/chip/chiptvserver/service/MatterServant.java

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040

4141
public class MatterServant {
4242

43+
public int testSetupPasscode = 20202021;
44+
public int testDiscriminator = 0xF00;
45+
4346
private ChipAppServer chipAppServer;
4447

4548
private MatterServant() {}
@@ -97,6 +100,9 @@ public void init(@NonNull Context context) {
97100
new ChipMdnsCallbackImpl(),
98101
new DiagnosticDataProviderImpl(applicationContext));
99102

103+
chipPlatform.updateCommissionableDataProviderData(
104+
null, null, 0, testSetupPasscode, testDiscriminator);
105+
100106
tvApp.postInit();
101107

102108
chipAppServer = new ChipAppServer();

src/include/platform/CommissionableDataProvider.h

+3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ namespace chip {
2424
// The largest value of the 12-bit Payload discriminator
2525
constexpr uint16_t kMaxDiscriminatorValue = 0xFFF;
2626

27+
constexpr uint32_t kMinSetupPasscode = 1;
28+
constexpr uint32_t kMaxSetupPasscode = 0x5F5E0FE;
29+
2730
namespace DeviceLayer {
2831

2932
class CommissionableDataProvider

src/platform/BUILD.gn

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ if (chip_device_platform != "none") {
5757
# === FOR TRANSITION UNTIL ALL EXAMPLES PROVIDE THEIR OWN ===
5858
# Linux platform has already transitioned.
5959
chip_use_transitional_commissionable_data_provider =
60-
chip_device_platform != "linux"
60+
chip_device_platform != "linux" && chip_device_platform != "android"
6161

6262
# lock tracking: none/log/fatal or auto for a platform-dependent choice
6363
chip_stack_lock_tracking = "auto"

src/platform/android/AndroidChipPlatform-JNI.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
* Implementation of JNI bridge for CHIP Device Controller for Android apps
2222
*
2323
*/
24+
#include <jni.h>
2425
#include <lib/core/CHIPError.h>
2526
#include <lib/support/CHIPJNIError.h>
2627
#include <lib/support/CHIPMem.h>
@@ -35,6 +36,7 @@
3536

3637
#include "AndroidChipPlatform-JNI.h"
3738
#include "BLEManagerImpl.h"
39+
#include "CommissionableDataProviderImpl.h"
3840
#include "DiagnosticDataProviderImpl.h"
3941
#include "DnssdImpl.h"
4042

@@ -255,3 +257,20 @@ static bool JavaBytesToUUID(JNIEnv * env, jbyteArray value, chip::Ble::ChipBleUU
255257
return result;
256258
}
257259
#endif
260+
261+
// for CommissionableDataProvider
262+
JNI_METHOD(jboolean, updateCommissionableDataProviderData)
263+
(JNIEnv * env, jclass self, jstring spake2pVerifierBase64, jstring Spake2pSaltBase64, jint spake2pIterationCount,
264+
jlong setupPasscode, jint discriminator)
265+
{
266+
chip::DeviceLayer::StackLock lock;
267+
CHIP_ERROR err = CommissionableDataProviderMgrImpl().Update(env, spake2pVerifierBase64, Spake2pSaltBase64,
268+
spake2pIterationCount, setupPasscode, discriminator);
269+
if (err != CHIP_NO_ERROR)
270+
{
271+
ChipLogError(DeviceLayer, "Failed to update commissionable data provider data: %s", ErrorStr(err));
272+
return false;
273+
}
274+
275+
return true;
276+
}

src/platform/android/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ static_library("android") {
3636
"BLEManagerImpl.h",
3737
"BlePlatformConfig.h",
3838
"CHIPDevicePlatformEvent.h",
39+
"CommissionableDataProviderImpl.cpp",
40+
"CommissionableDataProviderImpl.h",
3941
"ConfigurationManagerImpl.cpp",
4042
"ConfigurationManagerImpl.h",
4143
"ConnectivityManagerImpl.cpp",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
*
3+
* Copyright (c) 2022 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#include "CommissionableDataProviderImpl.h"
20+
21+
#include <cstdint>
22+
#include <string.h>
23+
24+
#include <crypto/CHIPCryptoPAL.h>
25+
#include <lib/support/Base64.h>
26+
#include <lib/support/CodeUtils.h>
27+
#include <lib/support/JniTypeWrappers.h>
28+
#include <lib/support/Span.h>
29+
#include <lib/support/logging/CHIPLogging.h>
30+
#include <platform/CHIPDeviceConfig.h>
31+
32+
using namespace chip;
33+
using namespace chip::Crypto;
34+
35+
namespace {
36+
37+
CHIP_ERROR GeneratePaseSalt(std::vector<uint8_t> & spake2pSaltVector)
38+
{
39+
constexpr size_t kSaltLen = kSpake2p_Max_PBKDF_Salt_Length;
40+
spake2pSaltVector.resize(kSaltLen);
41+
return DRBG_get_bytes(spake2pSaltVector.data(), spake2pSaltVector.size());
42+
}
43+
44+
} // namespace
45+
46+
CommissionableDataProviderImpl CommissionableDataProviderImpl::sInstance;
47+
48+
CHIP_ERROR CommissionableDataProviderImpl::Update(JNIEnv * env, jstring spake2pVerifierBase64, jstring Spake2pSaltBase64,
49+
jint spake2pIterationCount, jlong setupPasscode, jint discriminator)
50+
{
51+
VerifyOrReturnLogError(discriminator <= chip::kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT);
52+
53+
if (spake2pIterationCount == 0)
54+
{
55+
spake2pIterationCount = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT;
56+
}
57+
VerifyOrReturnLogError(static_cast<uint32_t>(spake2pIterationCount) >= kSpake2p_Min_PBKDF_Iterations,
58+
CHIP_ERROR_INVALID_ARGUMENT);
59+
VerifyOrReturnLogError(static_cast<uint32_t>(spake2pIterationCount) <= kSpake2p_Max_PBKDF_Iterations,
60+
CHIP_ERROR_INVALID_ARGUMENT);
61+
62+
const bool havePaseVerifier = (spake2pVerifierBase64 != nullptr);
63+
const bool havePaseSalt = (Spake2pSaltBase64 != nullptr);
64+
VerifyOrReturnLogError(!havePaseVerifier || (havePaseVerifier && havePaseSalt), CHIP_ERROR_INVALID_ARGUMENT);
65+
66+
CHIP_ERROR err;
67+
// read verifier from paramter is have
68+
Spake2pVerifier providedVerifier;
69+
std::vector<uint8_t> serializedSpake2pVerifier(kSpake2p_VerifierSerialized_Length);
70+
if (havePaseVerifier)
71+
{
72+
chip::JniUtfString utfSpake2pVerifierBase64(env, spake2pVerifierBase64);
73+
74+
size_t maxBase64Size = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length);
75+
VerifyOrReturnLogError(static_cast<unsigned>(utfSpake2pVerifierBase64.size()) <= maxBase64Size,
76+
CHIP_ERROR_INVALID_ARGUMENT);
77+
78+
size_t decodedLen = chip::Base64Decode32(utfSpake2pVerifierBase64.c_str(), utfSpake2pVerifierBase64.size(),
79+
reinterpret_cast<uint8_t *>(serializedSpake2pVerifier.data()));
80+
VerifyOrReturnLogError(decodedLen == chip::Crypto::kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT);
81+
82+
chip::MutableByteSpan verifierSpan{ serializedSpake2pVerifier.data(), decodedLen };
83+
err = providedVerifier.Deserialize(verifierSpan);
84+
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
85+
86+
ChipLogProgress(Support, "Got externally provided verifier, using it.");
87+
}
88+
89+
// read slat from paramter is have or generate one
90+
std::vector<uint8_t> spake2pSalt(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
91+
if (!havePaseSalt)
92+
{
93+
ChipLogProgress(Support, "LinuxCommissionableDataProvider didn't get a PASE salt, generating one.");
94+
err = GeneratePaseSalt(spake2pSalt);
95+
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
96+
}
97+
else
98+
{
99+
chip::JniUtfString utfSpake2pSaltBase64(env, Spake2pSaltBase64);
100+
101+
size_t maxBase64Size = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length);
102+
VerifyOrReturnLogError(static_cast<unsigned>(utfSpake2pSaltBase64.size()) <= maxBase64Size, CHIP_ERROR_INVALID_ARGUMENT);
103+
104+
size_t decodedLen = chip::Base64Decode32(utfSpake2pSaltBase64.c_str(), utfSpake2pSaltBase64.size(),
105+
reinterpret_cast<uint8_t *>(spake2pSalt.data()));
106+
VerifyOrReturnLogError(decodedLen >= chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length &&
107+
decodedLen <= chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length,
108+
CHIP_ERROR_INVALID_ARGUMENT);
109+
spake2pSalt.resize(decodedLen);
110+
}
111+
112+
// generate verifier from passcode is have
113+
const bool havePasscode = (setupPasscode > kMinSetupPasscode && setupPasscode < kMaxSetupPasscode);
114+
Spake2pVerifier passcodeVerifier;
115+
std::vector<uint8_t> serializedPasscodeVerifier(kSpake2p_VerifierSerialized_Length);
116+
chip::MutableByteSpan saltSpan{ spake2pSalt.data(), spake2pSalt.size() };
117+
if (havePasscode)
118+
{
119+
uint32_t u32SetupPasscode = static_cast<uint32_t>(setupPasscode);
120+
err = passcodeVerifier.Generate(spake2pIterationCount, saltSpan, u32SetupPasscode);
121+
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
122+
123+
chip::MutableByteSpan verifierSpan{ serializedPasscodeVerifier.data(), serializedPasscodeVerifier.size() };
124+
err = passcodeVerifier.Serialize(verifierSpan);
125+
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err);
126+
}
127+
128+
// Make sure we actually have a verifier
129+
VerifyOrReturnLogError(havePasscode || havePaseVerifier, CHIP_ERROR_INVALID_ARGUMENT);
130+
131+
// If both passcode and external verifier were provided, validate they match, otherwise
132+
// it's ambiguous.
133+
if (havePasscode && havePaseVerifier)
134+
{
135+
VerifyOrReturnLogError(serializedPasscodeVerifier == serializedSpake2pVerifier, CHIP_ERROR_INVALID_ARGUMENT);
136+
ChipLogProgress(Support, "Validated externally provided passcode matches the one generated from provided passcode.");
137+
}
138+
139+
// External PASE verifier takes precedence when present (even though it is identical to passcode-based
140+
// one when the latter is present).
141+
if (havePaseVerifier)
142+
{
143+
mSerializedPaseVerifier = std::move(serializedSpake2pVerifier);
144+
}
145+
else
146+
{
147+
mSerializedPaseVerifier = std::move(serializedPasscodeVerifier);
148+
}
149+
mDiscriminator = discriminator;
150+
mPaseSalt = std::move(spake2pSalt);
151+
mPaseIterationCount = spake2pIterationCount;
152+
if (havePasscode)
153+
{
154+
mSetupPasscode.SetValue(setupPasscode);
155+
}
156+
157+
// Set to global CommissionableDataProvider once success first time
158+
if (!mFirstUpdated)
159+
{
160+
DeviceLayer::SetCommissionableDataProvider(this);
161+
}
162+
mFirstUpdated = true;
163+
164+
return CHIP_NO_ERROR;
165+
}
166+
167+
CHIP_ERROR CommissionableDataProviderImpl::GetSetupDiscriminator(uint16_t & setupDiscriminator)
168+
{
169+
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
170+
setupDiscriminator = mDiscriminator;
171+
return CHIP_NO_ERROR;
172+
}
173+
174+
CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pIterationCount(uint32_t & iterationCount)
175+
{
176+
VerifyOrReturnLogError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
177+
iterationCount = mPaseIterationCount;
178+
return CHIP_NO_ERROR;
179+
}
180+
181+
CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pSalt(chip::MutableByteSpan & saltBuf)
182+
{
183+
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
184+
185+
VerifyOrReturnError(saltBuf.size() >= kSpake2p_Max_PBKDF_Salt_Length, CHIP_ERROR_BUFFER_TOO_SMALL);
186+
memcpy(saltBuf.data(), mPaseSalt.data(), mPaseSalt.size());
187+
saltBuf.reduce_size(mPaseSalt.size());
188+
189+
return CHIP_NO_ERROR;
190+
}
191+
192+
CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pVerifier(chip::MutableByteSpan & verifierBuf, size_t & outVerifierLen)
193+
{
194+
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
195+
196+
// By now, serialized verifier from Init should be correct size
197+
VerifyOrReturnError(mSerializedPaseVerifier.size() == kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INTERNAL);
198+
199+
outVerifierLen = mSerializedPaseVerifier.size();
200+
VerifyOrReturnError(verifierBuf.size() >= outVerifierLen, CHIP_ERROR_BUFFER_TOO_SMALL);
201+
memcpy(verifierBuf.data(), mSerializedPaseVerifier.data(), mSerializedPaseVerifier.size());
202+
verifierBuf.reduce_size(mSerializedPaseVerifier.size());
203+
204+
return CHIP_NO_ERROR;
205+
}
206+
207+
CHIP_ERROR CommissionableDataProviderImpl::GetSetupPasscode(uint32_t & setupPasscode)
208+
{
209+
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE);
210+
211+
// Pretend not implemented if we don't have a passcode value externally set
212+
if (!mSetupPasscode.HasValue())
213+
{
214+
return CHIP_ERROR_NOT_IMPLEMENTED;
215+
}
216+
217+
setupPasscode = mSetupPasscode.Value();
218+
return CHIP_NO_ERROR;
219+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
*
3+
* Copyright (c) 2022 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <jni.h>
22+
#include <lib/core/CHIPError.h>
23+
#include <lib/core/Optional.h>
24+
#include <platform/CommissionableDataProvider.h>
25+
#include <stdint.h>
26+
#include <vector>
27+
28+
class CommissionableDataProviderImpl : public chip::DeviceLayer::CommissionableDataProvider
29+
{
30+
public:
31+
CHIP_ERROR Update(JNIEnv * env, jstring spake2pVerifierBase64, jstring Spake2pSaltBase64, jint spake2pIterationCount,
32+
jlong setupPasscode, jint discriminator);
33+
CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override;
34+
CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override
35+
{
36+
// We don't support overriding the discriminator post-init (it is deprecated!)
37+
return CHIP_ERROR_NOT_IMPLEMENTED;
38+
}
39+
CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override;
40+
CHIP_ERROR GetSpake2pSalt(chip::MutableByteSpan & saltBuf) override;
41+
CHIP_ERROR GetSpake2pVerifier(chip::MutableByteSpan & verifierBuf, size_t & outVerifierLen) override;
42+
CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override;
43+
CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override
44+
{
45+
// We don't support overriding the passcode post-init (it is deprecated!)
46+
return CHIP_ERROR_NOT_IMPLEMENTED;
47+
}
48+
49+
private:
50+
friend CommissionableDataProviderImpl & CommissionableDataProviderMgrImpl();
51+
static CommissionableDataProviderImpl sInstance;
52+
bool mFirstUpdated = false;
53+
std::vector<uint8_t> mSerializedPaseVerifier;
54+
std::vector<uint8_t> mPaseSalt;
55+
uint32_t mPaseIterationCount = 0;
56+
chip::Optional<uint32_t> mSetupPasscode;
57+
uint16_t mDiscriminator = 0;
58+
};
59+
60+
inline CommissionableDataProviderImpl & CommissionableDataProviderMgrImpl()
61+
{
62+
return CommissionableDataProviderImpl::sInstance;
63+
}

src/platform/android/java/chip/platform/AndroidChipPlatform.java

+18
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,22 @@ private native void nativeSetServiceResolver(
9191
ServiceResolver resolver, ChipMdnsCallback chipMdnsCallback);
9292

9393
private native void setDiagnosticDataProviderManager(DiagnosticDataProvider dataProviderCallback);
94+
95+
/**
96+
* update commission info
97+
*
98+
* @param spake2pVerifierBase64 base64 encoded spake2p verifier, ref
99+
* CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_VERIFIER. using null to generate it from passcode.
100+
* @param Spake2pSaltBase64 base64 encoded spake2p salt, ref
101+
* CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_SALT. using null to generate a random one.
102+
* @param spake2pIterationCount Spake2p iteration count, or 0 to use
103+
* CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT
104+
* @return true on success of false on failed
105+
*/
106+
public native boolean updateCommissionableDataProviderData(
107+
String spake2pVerifierBase64,
108+
String Spake2pSaltBase64,
109+
int spake2pIterationCount,
110+
long setupPasscode,
111+
int discriminator);
94112
}

0 commit comments

Comments
 (0)