| /** |
| * |
| * Copyright (c) 2021 Project CHIP Authors |
| * |
| * 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 "platform/android/CHIPP256KeypairBridge.h" |
| #include "lib/core/CHIPError.h" |
| #include "lib/support/CHIPJNIError.h" |
| #include "lib/support/JniReferences.h" |
| #include "lib/support/JniTypeWrappers.h" |
| #include "lib/support/SafeInt.h" |
| |
| #include <array> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <jni.h> |
| #include <platform/PlatformManager.h> |
| #include <string.h> |
| #include <type_traits> |
| |
| using namespace chip; |
| using namespace chip::Crypto; |
| |
| CHIPP256KeypairBridge::~CHIPP256KeypairBridge() |
| { |
| VerifyOrReturn(mDelegate != nullptr); |
| JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); |
| VerifyOrReturn(env != nullptr); |
| env->DeleteGlobalRef(mDelegate); |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::SetDelegate(jobject delegate) |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); |
| VerifyOrExit(env != nullptr, err = CHIP_JNI_ERROR_NO_ENV); |
| |
| mDelegate = env->NewGlobalRef(delegate); |
| |
| err = JniReferences::GetInstance().GetClassRef(env, "chip/devicecontroller/KeypairDelegate", mKeypairDelegateClass); |
| VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed to find class for KeypairDelegate.")); |
| |
| err = JniReferences::GetInstance().FindMethod(env, delegate, "createCertificateSigningRequest", "()[B", |
| &mCreateCertificateSigningRequestMethod); |
| VerifyOrExit(err == CHIP_NO_ERROR, |
| ChipLogError(Controller, "Failed to find KeypairDelegate.createCertificateSigningRequest() method.")); |
| |
| err = JniReferences::GetInstance().FindMethod(env, delegate, "getPublicKey", "()[B", &mGetPublicKeyMethod); |
| VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed to find KeypairDelegate.getPublicKey() method.")); |
| |
| err = JniReferences::GetInstance().FindMethod(env, delegate, "ecdsaSignMessage", "([B)[B", &mEcdsaSignMessageMethod); |
| VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Failed to find KeypairDelegate.ecdsaSignMessage() method.")); |
| |
| exit: |
| return err; |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::Initialize() |
| { |
| if (HasKeypair()) |
| { |
| SetPubkey(); |
| } |
| return CHIP_NO_ERROR; |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::Serialize(P256SerializedKeypair & output) const |
| { |
| if (!HasKeypair()) |
| { |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::Deserialize(P256SerializedKeypair & input) |
| { |
| if (!HasKeypair()) |
| { |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::NewCertificateSigningRequest(uint8_t * csr, size_t & csr_length) const |
| { |
| if (!HasKeypair()) |
| { |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| // Not supported for use from within the CHIP SDK. We provide our own |
| // implementation that is JVM-specific. |
| return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::ECDSA_sign_msg(const uint8_t * msg, size_t msg_length, P256ECDSASignature & out_signature) const |
| { |
| if (!HasKeypair()) |
| { |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| VerifyOrReturnError(CanCastTo<uint32_t>(msg_length), CHIP_ERROR_INVALID_ARGUMENT); |
| |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| jbyteArray jniMsg; |
| jobject signedResult = nullptr; |
| JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread(); |
| VerifyOrReturnError(env != nullptr, err = CHIP_JNI_ERROR_NO_ENV); |
| err = JniReferences::GetInstance().N2J_ByteArray(env, msg, static_cast<uint32_t>(msg_length), jniMsg); |
| VerifyOrReturnError(err == CHIP_NO_ERROR, err); |
| VerifyOrReturnError(jniMsg != nullptr, err); |
| |
| signedResult = env->CallObjectMethod(mDelegate, mEcdsaSignMessageMethod, jniMsg); |
| |
| if (env->ExceptionCheck()) |
| { |
| ChipLogError(Controller, "Java exception in KeypairDelegate.ecdsaSignMessage()"); |
| env->ExceptionDescribe(); |
| env->ExceptionClear(); |
| return CHIP_JNI_ERROR_EXCEPTION_THROWN; |
| } |
| |
| JniByteArray jniSignature(env, static_cast<jbyteArray>(signedResult)); |
| MutableByteSpan signatureSpan(out_signature, out_signature.Capacity()); |
| ReturnErrorOnFailure(EcdsaAsn1SignatureToRaw(CHIP_CRYPTO_GROUP_SIZE_BYTES, jniSignature.byteSpan(), signatureSpan)); |
| ReturnErrorOnFailure(out_signature.SetLength(signatureSpan.size())); |
| |
| return err; |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::ECDH_derive_secret(const P256PublicKey & remote_public_key, |
| P256ECDHDerivedSecret & out_secret) const |
| { |
| if (!HasKeypair()) |
| { |
| return CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| // Not required for Java SDK. |
| return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; |
| } |
| |
| CHIP_ERROR CHIPP256KeypairBridge::SetPubkey() |
| { |
| jobject publicKey = nullptr; |
| JNIEnv * env = nullptr; |
| |
| VerifyOrReturnError(HasKeypair(), CHIP_ERROR_INCORRECT_STATE); |
| |
| env = JniReferences::GetInstance().GetEnvForCurrentThread(); |
| VerifyOrReturnError(env != nullptr, CHIP_JNI_ERROR_NO_ENV); |
| |
| publicKey = env->CallObjectMethod(mDelegate, mGetPublicKeyMethod); |
| if (env->ExceptionCheck()) |
| { |
| ChipLogError(Controller, "Java exception in KeypairDelegate.getPublicKey()"); |
| env->ExceptionDescribe(); |
| env->ExceptionClear(); |
| return CHIP_JNI_ERROR_EXCEPTION_THROWN; |
| } |
| |
| VerifyOrReturnError(publicKey != nullptr, CHIP_JNI_ERROR_NULL_OBJECT); |
| JniByteArray jniPublicKey(env, static_cast<jbyteArray>(publicKey)); |
| FixedByteSpan<Crypto::kP256_PublicKey_Length> publicKeySpan = |
| FixedByteSpan<kP256_PublicKey_Length>(reinterpret_cast<const uint8_t *>(jniPublicKey.data())); |
| mPublicKey = P256PublicKey(publicKeySpan); |
| return CHIP_NO_ERROR; |
| } |