-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
1 parent
80012b2
commit 48b48c2
Showing
9 changed files
with
331 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
219 changes: 219 additions & 0 deletions
219
src/platform/android/CommissionableDataProviderImpl.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
/* | ||
* | ||
* Copyright (c) 2022 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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 "CommissionableDataProviderImpl.h" | ||
|
||
#include <cstdint> | ||
#include <string.h> | ||
|
||
#include <crypto/CHIPCryptoPAL.h> | ||
#include <lib/support/Base64.h> | ||
#include <lib/support/CodeUtils.h> | ||
#include <lib/support/JniTypeWrappers.h> | ||
#include <lib/support/Span.h> | ||
#include <lib/support/logging/CHIPLogging.h> | ||
#include <platform/CHIPDeviceConfig.h> | ||
|
||
using namespace chip; | ||
using namespace chip::Crypto; | ||
|
||
namespace { | ||
|
||
CHIP_ERROR GeneratePaseSalt(std::vector<uint8_t> & spake2pSaltVector) | ||
{ | ||
constexpr size_t kSaltLen = kSpake2p_Max_PBKDF_Salt_Length; | ||
spake2pSaltVector.resize(kSaltLen); | ||
return DRBG_get_bytes(spake2pSaltVector.data(), spake2pSaltVector.size()); | ||
} | ||
|
||
} // namespace | ||
|
||
CommissionableDataProviderImpl CommissionableDataProviderImpl::sInstance; | ||
|
||
CHIP_ERROR CommissionableDataProviderImpl::Update(JNIEnv * env, jstring spake2pVerifierBase64, jstring Spake2pSaltBase64, | ||
jint spake2pIterationCount, jlong setupPasscode, jint discriminator) | ||
{ | ||
VerifyOrReturnLogError(discriminator <= chip::kMaxDiscriminatorValue, CHIP_ERROR_INVALID_ARGUMENT); | ||
|
||
if (spake2pIterationCount == 0) | ||
{ | ||
spake2pIterationCount = CHIP_DEVICE_CONFIG_USE_TEST_SPAKE2P_ITERATION_COUNT; | ||
} | ||
VerifyOrReturnLogError(static_cast<uint32_t>(spake2pIterationCount) >= kSpake2p_Min_PBKDF_Iterations, | ||
CHIP_ERROR_INVALID_ARGUMENT); | ||
VerifyOrReturnLogError(static_cast<uint32_t>(spake2pIterationCount) <= kSpake2p_Max_PBKDF_Iterations, | ||
CHIP_ERROR_INVALID_ARGUMENT); | ||
|
||
const bool havePaseVerifier = (spake2pVerifierBase64 != nullptr); | ||
const bool havePaseSalt = (Spake2pSaltBase64 != nullptr); | ||
VerifyOrReturnLogError(!havePaseVerifier || (havePaseVerifier && havePaseSalt), CHIP_ERROR_INVALID_ARGUMENT); | ||
|
||
CHIP_ERROR err; | ||
// read verifier from paramter is have | ||
Spake2pVerifier providedVerifier; | ||
std::vector<uint8_t> serializedSpake2pVerifier(kSpake2p_VerifierSerialized_Length); | ||
if (havePaseVerifier) | ||
{ | ||
chip::JniUtfString utfSpake2pVerifierBase64(env, spake2pVerifierBase64); | ||
|
||
size_t maxBase64Size = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length); | ||
VerifyOrReturnLogError(static_cast<unsigned>(utfSpake2pVerifierBase64.size()) <= maxBase64Size, | ||
CHIP_ERROR_INVALID_ARGUMENT); | ||
|
||
size_t decodedLen = chip::Base64Decode32(utfSpake2pVerifierBase64.c_str(), utfSpake2pVerifierBase64.size(), | ||
reinterpret_cast<uint8_t *>(serializedSpake2pVerifier.data())); | ||
VerifyOrReturnLogError(decodedLen == chip::Crypto::kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT); | ||
|
||
chip::MutableByteSpan verifierSpan{ serializedSpake2pVerifier.data(), decodedLen }; | ||
err = providedVerifier.Deserialize(verifierSpan); | ||
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err); | ||
|
||
ChipLogProgress(Support, "Got externally provided verifier, using it."); | ||
} | ||
|
||
// read slat from paramter is have or generate one | ||
std::vector<uint8_t> spake2pSalt(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length); | ||
if (!havePaseSalt) | ||
{ | ||
ChipLogProgress(Support, "LinuxCommissionableDataProvider didn't get a PASE salt, generating one."); | ||
err = GeneratePaseSalt(spake2pSalt); | ||
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err); | ||
} | ||
else | ||
{ | ||
chip::JniUtfString utfSpake2pSaltBase64(env, Spake2pSaltBase64); | ||
|
||
size_t maxBase64Size = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length); | ||
VerifyOrReturnLogError(static_cast<unsigned>(utfSpake2pSaltBase64.size()) <= maxBase64Size, CHIP_ERROR_INVALID_ARGUMENT); | ||
|
||
size_t decodedLen = chip::Base64Decode32(utfSpake2pSaltBase64.c_str(), utfSpake2pSaltBase64.size(), | ||
reinterpret_cast<uint8_t *>(spake2pSalt.data())); | ||
VerifyOrReturnLogError(decodedLen >= chip::Crypto::kSpake2p_Min_PBKDF_Salt_Length && | ||
decodedLen <= chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length, | ||
CHIP_ERROR_INVALID_ARGUMENT); | ||
spake2pSalt.resize(decodedLen); | ||
} | ||
|
||
// generate verifier from passcode is have | ||
const bool havePasscode = (setupPasscode > kMinSetupPasscode && setupPasscode < kMaxSetupPasscode); | ||
Spake2pVerifier passcodeVerifier; | ||
std::vector<uint8_t> serializedPasscodeVerifier(kSpake2p_VerifierSerialized_Length); | ||
chip::MutableByteSpan saltSpan{ spake2pSalt.data(), spake2pSalt.size() }; | ||
if (havePasscode) | ||
{ | ||
uint32_t u32SetupPasscode = static_cast<uint32_t>(setupPasscode); | ||
err = passcodeVerifier.Generate(spake2pIterationCount, saltSpan, u32SetupPasscode); | ||
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err); | ||
|
||
chip::MutableByteSpan verifierSpan{ serializedPasscodeVerifier.data(), serializedPasscodeVerifier.size() }; | ||
err = passcodeVerifier.Serialize(verifierSpan); | ||
VerifyOrReturnLogError(err == CHIP_NO_ERROR, err); | ||
} | ||
|
||
// Make sure we actually have a verifier | ||
VerifyOrReturnLogError(havePasscode || havePaseVerifier, CHIP_ERROR_INVALID_ARGUMENT); | ||
|
||
// If both passcode and external verifier were provided, validate they match, otherwise | ||
// it's ambiguous. | ||
if (havePasscode && havePaseVerifier) | ||
{ | ||
VerifyOrReturnLogError(serializedPasscodeVerifier == serializedSpake2pVerifier, CHIP_ERROR_INVALID_ARGUMENT); | ||
ChipLogProgress(Support, "Validated externally provided passcode matches the one generated from provided passcode."); | ||
} | ||
|
||
// External PASE verifier takes precedence when present (even though it is identical to passcode-based | ||
// one when the latter is present). | ||
if (havePaseVerifier) | ||
{ | ||
mSerializedPaseVerifier = std::move(serializedSpake2pVerifier); | ||
} | ||
else | ||
{ | ||
mSerializedPaseVerifier = std::move(serializedPasscodeVerifier); | ||
} | ||
mDiscriminator = discriminator; | ||
mPaseSalt = std::move(spake2pSalt); | ||
mPaseIterationCount = spake2pIterationCount; | ||
if (havePasscode) | ||
{ | ||
mSetupPasscode.SetValue(setupPasscode); | ||
} | ||
|
||
// Set to global CommissionableDataProvider once success first time | ||
if (!mFirstUpdated) | ||
{ | ||
DeviceLayer::SetCommissionableDataProvider(this); | ||
} | ||
mFirstUpdated = true; | ||
|
||
return CHIP_NO_ERROR; | ||
} | ||
|
||
CHIP_ERROR CommissionableDataProviderImpl::GetSetupDiscriminator(uint16_t & setupDiscriminator) | ||
{ | ||
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE); | ||
setupDiscriminator = mDiscriminator; | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pIterationCount(uint32_t & iterationCount) | ||
{ | ||
VerifyOrReturnLogError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE); | ||
iterationCount = mPaseIterationCount; | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pSalt(chip::MutableByteSpan & saltBuf) | ||
{ | ||
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE); | ||
|
||
VerifyOrReturnError(saltBuf.size() >= kSpake2p_Max_PBKDF_Salt_Length, CHIP_ERROR_BUFFER_TOO_SMALL); | ||
memcpy(saltBuf.data(), mPaseSalt.data(), mPaseSalt.size()); | ||
saltBuf.reduce_size(mPaseSalt.size()); | ||
|
||
return CHIP_NO_ERROR; | ||
} | ||
|
||
CHIP_ERROR CommissionableDataProviderImpl::GetSpake2pVerifier(chip::MutableByteSpan & verifierBuf, size_t & outVerifierLen) | ||
{ | ||
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE); | ||
|
||
// By now, serialized verifier from Init should be correct size | ||
VerifyOrReturnError(mSerializedPaseVerifier.size() == kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INTERNAL); | ||
|
||
outVerifierLen = mSerializedPaseVerifier.size(); | ||
VerifyOrReturnError(verifierBuf.size() >= outVerifierLen, CHIP_ERROR_BUFFER_TOO_SMALL); | ||
memcpy(verifierBuf.data(), mSerializedPaseVerifier.data(), mSerializedPaseVerifier.size()); | ||
verifierBuf.reduce_size(mSerializedPaseVerifier.size()); | ||
|
||
return CHIP_NO_ERROR; | ||
} | ||
|
||
CHIP_ERROR CommissionableDataProviderImpl::GetSetupPasscode(uint32_t & setupPasscode) | ||
{ | ||
VerifyOrReturnError(mFirstUpdated, CHIP_ERROR_INCORRECT_STATE); | ||
|
||
// Pretend not implemented if we don't have a passcode value externally set | ||
if (!mSetupPasscode.HasValue()) | ||
{ | ||
return CHIP_ERROR_NOT_IMPLEMENTED; | ||
} | ||
|
||
setupPasscode = mSetupPasscode.Value(); | ||
return CHIP_NO_ERROR; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* | ||
* Copyright (c) 2022 Project CHIP Authors | ||
* All rights reserved. | ||
* | ||
* 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 <jni.h> | ||
#include <lib/core/CHIPError.h> | ||
#include <lib/core/Optional.h> | ||
#include <platform/CommissionableDataProvider.h> | ||
#include <stdint.h> | ||
#include <vector> | ||
|
||
class CommissionableDataProviderImpl : public chip::DeviceLayer::CommissionableDataProvider | ||
{ | ||
public: | ||
CHIP_ERROR Update(JNIEnv * env, jstring spake2pVerifierBase64, jstring Spake2pSaltBase64, jint spake2pIterationCount, | ||
jlong setupPasscode, jint discriminator); | ||
CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override; | ||
CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override | ||
{ | ||
// We don't support overriding the discriminator post-init (it is deprecated!) | ||
return CHIP_ERROR_NOT_IMPLEMENTED; | ||
} | ||
CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override; | ||
CHIP_ERROR GetSpake2pSalt(chip::MutableByteSpan & saltBuf) override; | ||
CHIP_ERROR GetSpake2pVerifier(chip::MutableByteSpan & verifierBuf, size_t & outVerifierLen) override; | ||
CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override; | ||
CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override | ||
{ | ||
// We don't support overriding the passcode post-init (it is deprecated!) | ||
return CHIP_ERROR_NOT_IMPLEMENTED; | ||
} | ||
|
||
private: | ||
friend CommissionableDataProviderImpl & CommissionableDataProviderMgrImpl(); | ||
static CommissionableDataProviderImpl sInstance; | ||
bool mFirstUpdated = false; | ||
std::vector<uint8_t> mSerializedPaseVerifier; | ||
std::vector<uint8_t> mPaseSalt; | ||
uint32_t mPaseIterationCount = 0; | ||
chip::Optional<uint32_t> mSetupPasscode; | ||
uint16_t mDiscriminator = 0; | ||
}; | ||
|
||
inline CommissionableDataProviderImpl & CommissionableDataProviderMgrImpl() | ||
{ | ||
return CommissionableDataProviderImpl::sInstance; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.