Skip to content

Commit 770fb8c

Browse files
add custom cert support for java controller
1 parent 36c76e6 commit 770fb8c

6 files changed

+255
-14
lines changed

src/controller/java/AndroidDeviceControllerWrapper.cpp

+1-7
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@
4040
#include <lib/support/TestGroupData.h>
4141
#include <lib/support/ThreadOperationalDataset.h>
4242
#include <platform/KeyValueStoreManager.h>
43-
#ifndef JAVA_MATTER_CONTROLLER_TEST
44-
#include <platform/android/CHIPP256KeypairBridge.h>
45-
#endif // JAVA_MATTER_CONTROLLER_TEST
43+
4644
using namespace chip;
4745
using namespace chip::Controller;
4846
using namespace chip::Credentials;
@@ -52,13 +50,11 @@ AndroidDeviceControllerWrapper::~AndroidDeviceControllerWrapper()
5250
{
5351
mController->Shutdown();
5452

55-
#ifndef JAVA_MATTER_CONTROLLER_TEST
5653
if (mKeypairBridge != nullptr)
5754
{
5855
chip::Platform::Delete(mKeypairBridge);
5956
mKeypairBridge = nullptr;
6057
}
61-
#endif // JAVA_MATTER_CONTROLLER_TEST
6258

6359
if (mDeviceAttestationDelegateBridge != nullptr)
6460
{
@@ -296,7 +292,6 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
296292

297293
// The lifetime of the ephemeralKey variable must be kept until SetupParams is saved.
298294
Crypto::P256Keypair ephemeralKey;
299-
#ifndef JAVA_MATTER_CONTROLLER_TEST
300295
if (rootCertificate != nullptr && nodeOperationalCertificate != nullptr && keypairDelegate != nullptr)
301296
{
302297
CHIPP256KeypairBridge * nativeKeypairBridge = wrapper->GetP256KeypairBridge();
@@ -333,7 +328,6 @@ AndroidDeviceControllerWrapper * AndroidDeviceControllerWrapper::AllocateNew(
333328
setupParams.controllerNOC = chip::ByteSpan(wrapper->mNocCertificate.data(), wrapper->mNocCertificate.size());
334329
}
335330
else
336-
#endif // JAVA_MATTER_CONTROLLER_TEST
337331
{
338332
ChipLogProgress(Controller,
339333
"No existing credentials provided: generating ephemeral local NOC chain with OperationalCredentialsIssuer");

src/controller/java/AndroidDeviceControllerWrapper.h

+2-5
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,12 @@
3434
#include <crypto/RawKeySessionKeystore.h>
3535
#include <lib/support/TimeUtils.h>
3636
#include <platform/internal/DeviceNetworkInfo.h>
37-
37+
#include <controller/java/CHIPP256KeypairBridge.h>
3838
#ifdef JAVA_MATTER_CONTROLLER_TEST
3939
#include <controller/ExampleOperationalCredentialsIssuer.h>
4040
#include <controller/ExamplePersistentStorage.h>
4141
#else
4242
#include <platform/android/AndroidChipPlatform-JNI.h>
43-
#include <platform/android/CHIPP256KeypairBridge.h>
4443
#endif // JAVA_MATTER_CONTROLLER_TEST
4544

4645
#include "AndroidCheckInDelegate.h"
@@ -71,7 +70,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
7170
jobject JavaObjectRef() { return mJavaObjectRef.ObjectRef(); }
7271
jlong ToJNIHandle();
7372

74-
#ifndef JAVA_MATTER_CONTROLLER_TEST
7573
/**
7674
* Returns a CHIPP256KeypairBridge which can be used to delegate signing operations
7775
* to a KeypairDelegate in the Java layer. Note that this will always return a pointer
@@ -85,7 +83,6 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
8583
}
8684
return mKeypairBridge;
8785
}
88-
#endif // JAVA_MATTER_CONTROLLER_TEST
8986

9087
void CallJavaIntMethod(const char * methodName, jint argument);
9188
void CallJavaLongMethod(const char * methodName, jlong argument);
@@ -231,12 +228,12 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel
231228

232229
JavaVM * mJavaVM = nullptr;
233230
chip::JniGlobalReference mJavaObjectRef;
231+
CHIPP256KeypairBridge * mKeypairBridge = nullptr;
234232
#ifdef JAVA_MATTER_CONTROLLER_TEST
235233
ExampleOperationalCredentialsIssuerPtr mOpCredsIssuer;
236234
PersistentStorage mExampleStorage;
237235
#else
238236
AndroidOperationalCredentialsIssuerPtr mOpCredsIssuer;
239-
CHIPP256KeypairBridge * mKeypairBridge = nullptr;
240237
#endif // JAVA_MATTER_CONTROLLER_TEST
241238

242239
// These fields allow us to release the string/byte array memory later.

src/controller/java/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ shared_library("jni") {
120120
check_includes = false
121121

122122
sources = [
123+
"CHIPP256KeypairBridge.cpp",
124+
"CHIPP256KeypairBridge.h",
123125
"AndroidCheckInDelegate.cpp",
124126
"AndroidCheckInDelegate.h",
125127
"AndroidClusterExceptions.cpp",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/**
2+
*
3+
* Copyright (c) 2021 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "CHIPP256KeypairBridge.h"
19+
#include "lib/core/CHIPError.h"
20+
#include "lib/support/CHIPJNIError.h"
21+
#include "lib/support/JniReferences.h"
22+
#include "lib/support/JniTypeWrappers.h"
23+
#include "lib/support/SafeInt.h"
24+
25+
#include <array>
26+
#include <cstdint>
27+
#include <cstdlib>
28+
#include <jni.h>
29+
#include <string.h>
30+
#include <type_traits>
31+
32+
using namespace chip;
33+
using namespace chip::Crypto;
34+
35+
CHIPP256KeypairBridge::~CHIPP256KeypairBridge() {}
36+
37+
CHIP_ERROR CHIPP256KeypairBridge::SetDelegate(jobject delegate)
38+
{
39+
CHIP_ERROR err = CHIP_NO_ERROR;
40+
41+
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
42+
VerifyOrExit(env != nullptr, err = CHIP_JNI_ERROR_NO_ENV);
43+
ReturnErrorOnFailure(mDelegate.Init(delegate));
44+
jclass keypairDelegateClass;
45+
err = JniReferences::GetInstance().GetLocalClassRef(env, "chip/devicecontroller/KeypairDelegate", keypairDelegateClass);
46+
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed to find class for KeypairDelegate."));
47+
SuccessOrExit(err = mKeypairDelegateClass.Init(static_cast<jobject>(keypairDelegateClass)));
48+
err = JniReferences::GetInstance().FindMethod(env, delegate, "createCertificateSigningRequest", "()[B",
49+
&mCreateCertificateSigningRequestMethod);
50+
VerifyOrExit(err == CHIP_NO_ERROR,
51+
ChipLogError(Controller, "Failed to find KeypairDelegate.createCertificateSigningRequest() method."));
52+
53+
err = JniReferences::GetInstance().FindMethod(env, delegate, "getPublicKey", "()[B", &mGetPublicKeyMethod);
54+
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed to find KeypairDelegate.getPublicKey() method."));
55+
56+
err = JniReferences::GetInstance().FindMethod(env, delegate, "ecdsaSignMessage", "([B)[B", &mEcdsaSignMessageMethod);
57+
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed to find KeypairDelegate.ecdsaSignMessage() method."));
58+
59+
exit:
60+
return err;
61+
}
62+
63+
CHIP_ERROR CHIPP256KeypairBridge::Initialize(ECPKeyTarget key_target)
64+
{
65+
if (HasKeypair())
66+
{
67+
SetPubkey();
68+
}
69+
return CHIP_NO_ERROR;
70+
}
71+
72+
CHIP_ERROR CHIPP256KeypairBridge::Serialize(P256SerializedKeypair & output) const
73+
{
74+
if (!HasKeypair())
75+
{
76+
return CHIP_ERROR_INCORRECT_STATE;
77+
}
78+
79+
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
80+
}
81+
82+
CHIP_ERROR CHIPP256KeypairBridge::Deserialize(P256SerializedKeypair & input)
83+
{
84+
if (!HasKeypair())
85+
{
86+
return CHIP_ERROR_INCORRECT_STATE;
87+
}
88+
89+
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
90+
}
91+
92+
CHIP_ERROR CHIPP256KeypairBridge::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const
93+
{
94+
if (!HasKeypair())
95+
{
96+
return CHIP_ERROR_INCORRECT_STATE;
97+
}
98+
99+
// Not supported for use from within the CHIP SDK. We provide our own
100+
// implementation that is JVM-specific.
101+
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
102+
}
103+
104+
CHIP_ERROR CHIPP256KeypairBridge::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) const
105+
{
106+
if (!HasKeypair())
107+
{
108+
return CHIP_ERROR_INCORRECT_STATE;
109+
}
110+
111+
VerifyOrReturnError(CanCastTo<uint32_t>(msg_length), CHIP_ERROR_INVALID_ARGUMENT);
112+
113+
CHIP_ERROR err = CHIP_NO_ERROR;
114+
jbyteArray jniMsg;
115+
jobject signedResult = nullptr;
116+
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
117+
VerifyOrReturnError(env != nullptr, err = CHIP_JNI_ERROR_NO_ENV);
118+
err = JniReferences::GetInstance().N2J_ByteArray(env, msg, static_cast<uint32_t>(msg_length), jniMsg);
119+
VerifyOrReturnError(err == CHIP_NO_ERROR, err);
120+
VerifyOrReturnError(jniMsg != nullptr, err);
121+
VerifyOrReturnError(mDelegate.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE);
122+
signedResult = env->CallObjectMethod(mDelegate.ObjectRef(), mEcdsaSignMessageMethod, jniMsg);
123+
124+
if (env->ExceptionCheck())
125+
{
126+
ChipLogError(Controller, "Java exception in KeypairDelegate.ecdsaSignMessage()");
127+
env->ExceptionDescribe();
128+
env->ExceptionClear();
129+
return CHIP_JNI_ERROR_EXCEPTION_THROWN;
130+
}
131+
132+
JniByteArray jniSignature(env, static_cast<jbyteArray>(signedResult));
133+
MutableByteSpan signatureSpan(out_signature.Bytes(), out_signature.Capacity());
134+
ReturnErrorOnFailure(EcdsaAsn1SignatureToRaw(CHIP_CRYPTO_GROUP_SIZE_BYTES, jniSignature.byteSpan(), signatureSpan));
135+
ReturnErrorOnFailure(out_signature.SetLength(signatureSpan.size()));
136+
137+
return err;
138+
}
139+
140+
CHIP_ERROR CHIPP256KeypairBridge::ECDH_derive_secret(const P256PublicKey & remote_public_key,
141+
P256ECDHDerivedSecret & out_secret) const
142+
{
143+
if (!HasKeypair())
144+
{
145+
return CHIP_ERROR_INCORRECT_STATE;
146+
}
147+
148+
// Not required for Java SDK.
149+
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
150+
}
151+
152+
CHIP_ERROR CHIPP256KeypairBridge::SetPubkey()
153+
{
154+
jobject publicKey = nullptr;
155+
JNIEnv * env = nullptr;
156+
157+
VerifyOrReturnError(HasKeypair(), CHIP_ERROR_INCORRECT_STATE);
158+
159+
env = JniReferences::GetInstance().GetEnvForCurrentThread();
160+
VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV);
161+
VerifyOrReturnError(mDelegate.HasValidObjectRef(), CHIP_ERROR_INCORRECT_STATE);
162+
publicKey = env->CallObjectMethod(mDelegate.ObjectRef(), mGetPublicKeyMethod);
163+
if (env->ExceptionCheck())
164+
{
165+
ChipLogError(Controller, "Java exception in KeypairDelegate.getPublicKey()");
166+
env->ExceptionDescribe();
167+
env->ExceptionClear();
168+
return CHIP_JNI_ERROR_EXCEPTION_THROWN;
169+
}
170+
171+
VerifyOrReturnError(publicKey != nullptr, CHIP_JNI_ERROR_NULL_OBJECT);
172+
JniByteArray jniPublicKey(env, static_cast<jbyteArray>(publicKey));
173+
FixedByteSpan<Crypto::kP256_PublicKey_Length> publicKeySpan =
174+
FixedByteSpan<kP256_PublicKey_Length>(reinterpret_cast<const uint8_t *>(jniPublicKey.data()));
175+
mPublicKey = P256PublicKey(publicKeySpan);
176+
return CHIP_NO_ERROR;
177+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
*
3+
* Copyright (c) 2021 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
#pragma once
18+
19+
#include "crypto/CHIPCryptoPAL.h"
20+
#include "lib/core/CHIPError.h"
21+
#include "lib/support/JniReferences.h"
22+
#include "lib/support/logging/CHIPLogging.h"
23+
#include <jni.h>
24+
25+
/**
26+
* Bridging implementation of P256Keypair to allow delegation of signing and
27+
* key generation to the JVM layer (through the KeypairDelegate Java interface).
28+
*
29+
* This implementation explicitly does not support serialization or
30+
* deserialization and will always return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE if
31+
* either of them are invoked (as this bridge is not expected to ever have
32+
* access to the raw key bits).
33+
*/
34+
class CHIPP256KeypairBridge : public chip::Crypto::P256Keypair
35+
{
36+
public:
37+
~CHIPP256KeypairBridge() override;
38+
39+
/**
40+
* Sets a reference to the Java implementation of the KeypairDelegate
41+
* interface that will be called whenever this P256Keypair is used.
42+
*/
43+
CHIP_ERROR SetDelegate(jobject delegate);
44+
45+
bool HasKeypair() const { return mDelegate.HasValidObjectRef(); }
46+
47+
CHIP_ERROR Initialize(chip::Crypto::ECPKeyTarget key_target) override;
48+
49+
CHIP_ERROR Serialize(chip::Crypto::P256SerializedKeypair & output) const override;
50+
51+
CHIP_ERROR Deserialize(chip::Crypto::P256SerializedKeypair & input) override;
52+
53+
CHIP_ERROR NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const override;
54+
55+
CHIP_ERROR ECDSA_sign_msg(const uint8_t * msg, size_t msg_length,
56+
chip::Crypto::P256ECDSASignature & out_signature) const override;
57+
58+
CHIP_ERROR ECDH_derive_secret(const chip::Crypto::P256PublicKey & remote_public_key,
59+
chip::Crypto::P256ECDHDerivedSecret & out_secret) const override;
60+
61+
const chip::Crypto::P256PublicKey & Pubkey() const override { return mPublicKey; };
62+
63+
private:
64+
chip::JniGlobalReference mDelegate;
65+
chip::JniGlobalReference mKeypairDelegateClass;
66+
jmethodID mGetPublicKeyMethod;
67+
jmethodID mCreateCertificateSigningRequestMethod;
68+
jmethodID mEcdsaSignMessageMethod;
69+
70+
chip::Crypto::P256PublicKey mPublicKey;
71+
72+
CHIP_ERROR SetPubkey();
73+
};

src/platform/android/BUILD.gn

-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ static_library("android") {
5151
"BleConnectCallback-JNI.cpp",
5252
"BlePlatformConfig.h",
5353
"CHIPDevicePlatformEvent.h",
54-
"CHIPP256KeypairBridge.cpp",
55-
"CHIPP256KeypairBridge.h",
5654
"CommissionableDataProviderImpl.cpp",
5755
"CommissionableDataProviderImpl.h",
5856
"ConfigurationManagerImpl.cpp",

0 commit comments

Comments
 (0)