blob: 524ea6823355344d17125270409665d476ab7c7b [file] [log] [blame]
/**
*
* 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;
}