blob: ba6b1e27c27e0c5026b82ddf5a787dbef739c2df [file] [log] [blame]
/*
*
* Copyright (c) 2013-2017 Nest Labs, Inc.
* 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.
*/
/**
* @file
* Native method implementations for the WeaveKeyExportClient Java wrapper class.
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <pthread.h>
#include <jni.h>
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveKeyIds.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Profiles/security/WeaveKeyExportClient.h>
#include "WeaveSecuritySupport.h"
#include "JNIUtils.h"
namespace nl {
namespace Weave {
namespace SecuritySupport {
using namespace nl::Weave::Profiles::Security::KeyExport;
enum
{
kMaxPubKeySize = (((WEAVE_CONFIG_MAX_EC_BITS + 7) / 8) + 1) * 2,
kMaxECDSASigSize = kMaxPubKeySize,
};
jlong WeaveKeyExportClientNative::newNativeClient(JNIEnv *env, jclass cls)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient;
keyExportClient = new WeaveStandAloneKeyExportClient();
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_NO_MEMORY);
keyExportClient->Init();
exit:
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
return (jlong)keyExportClient;
}
void WeaveKeyExportClientNative::releaseNativeClient(JNIEnv *env, jclass cls, jlong nativeClientPtr)
{
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
if (keyExportClient != NULL)
{
keyExportClient->Reset();
delete keyExportClient;
}
}
void WeaveKeyExportClientNative::resetNativeClient(JNIEnv *env, jclass cls, jlong nativeClientPtr)
{
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
if (keyExportClient != NULL)
{
keyExportClient->Reset();
}
}
jbyteArray WeaveKeyExportClientNative::generateKeyExportRequest_Cert(JNIEnv *env, jclass cls, jlong nativeClientPtr, jint keyId, jlong responderNodeId,
jbyteArray clientCert, jbyteArray clientKey)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
const uint8_t *clientCertBuf = NULL;
const uint8_t *clientKeyBuf = NULL;
jsize clientCertLen = 0;
jsize clientKeyLen = 0;
uint8_t *exportReqBuf = NULL;
size_t exportReqBufSize;
uint16_t exportReqLen;
jbyteArray exportReq = NULL;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
VerifyOrExit(clientCert != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
VerifyOrExit(clientKey != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
clientCertBuf = (uint8_t *)env->GetByteArrayElements(clientCert, 0);
clientCertLen = env->GetArrayLength(clientCert);
clientKeyBuf = (uint8_t *)env->GetByteArrayElements(clientKey, 0);
clientKeyLen = env->GetArrayLength(clientKey);
exportReqBufSize =
7 // Key export request header size
+ kMaxPubKeySize // Ephemeral public key size
+ kMaxECDSASigSize // Size of bare signature field
+ clientCertLen // Size of client certificate
+ 1024; // Space for additional signature fields plus encoding overhead
VerifyOrExit(exportReqBufSize <= UINT16_MAX, err = WEAVE_ERROR_INVALID_ARGUMENT);
exportReqBuf = (uint8_t *)malloc(exportReqBufSize);
VerifyOrExit(exportReqBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
err = keyExportClient->GenerateKeyExportRequest((uint32_t)keyId, (uint64_t)responderNodeId,
clientCertBuf, clientCertLen, clientKeyBuf, clientKeyLen,
exportReqBuf, (uint16_t)exportReqBufSize, exportReqLen);
SuccessOrExit(err);
err = JNIUtils::N2J_ByteArray(env, exportReqBuf, exportReqLen, exportReq);
SuccessOrExit(err);
exit:
if (clientCertBuf != NULL)
{
env->ReleaseByteArrayElements(clientCert, (jbyte *)clientCertBuf, JNI_ABORT);
}
if (clientKeyBuf != NULL)
{
env->ReleaseByteArrayElements(clientKey, (jbyte *)clientKeyBuf, JNI_ABORT);
}
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
return exportReq;
}
jbyteArray WeaveKeyExportClientNative::generateKeyExportRequest_AccessToken(JNIEnv *env, jclass cls, jlong nativeClientPtr, jint keyId, jlong responderNodeId,
jbyteArray accessToken)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
const uint8_t *accessTokenBuf = NULL;
jsize accessTokenLen = 0;
uint8_t *exportReqBuf = NULL;
size_t exportReqBufSize;
uint16_t exportReqLen;
jbyteArray exportReq = NULL;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
VerifyOrExit(accessToken != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
accessTokenBuf = (uint8_t *)env->GetByteArrayElements(accessToken, 0);
accessTokenLen = env->GetArrayLength(accessToken);
exportReqBufSize =
7 // Key export request header size
+ kMaxPubKeySize // Ephemeral public key size
+ kMaxECDSASigSize // Size of bare signature field
+ accessTokenLen // Size equal to at least the total size of the client certificates
+ 1024; // Space for additional signature fields plus encoding overhead
VerifyOrExit(exportReqBufSize <= UINT16_MAX, err = WEAVE_ERROR_INVALID_ARGUMENT);
exportReqBuf = (uint8_t *)malloc(exportReqBufSize);
VerifyOrExit(exportReqBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
err = keyExportClient->GenerateKeyExportRequest((uint32_t)keyId, (uint64_t)responderNodeId,
accessTokenBuf, accessTokenLen,
exportReqBuf, (uint16_t)exportReqBufSize, exportReqLen);
SuccessOrExit(err);
err = JNIUtils::N2J_ByteArray(env, exportReqBuf, exportReqLen, exportReq);
SuccessOrExit(err);
exit:
if (accessTokenBuf != NULL)
{
env->ReleaseByteArrayElements(accessToken, (jbyte *)accessTokenBuf, JNI_ABORT);
}
if (exportReqBuf != NULL)
{
free(exportReqBuf);
}
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
return exportReq;
}
jbyteArray WeaveKeyExportClientNative::processKeyExportResponse(JNIEnv *env, jclass cls, jlong nativeClientPtr, jlong responderNodeId, jbyteArray exportResp)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
const uint8_t *exportRespBuf = NULL;
jsize exportRespLen = 0;
uint8_t *exportedKeyBuf = NULL;
size_t exportedKeyBufSize;
uint16_t exportedKeyLen;
jbyteArray exportedKey = NULL;
uint32_t exportedKeyId;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
VerifyOrExit(exportResp != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
exportRespBuf = (uint8_t *)env->GetByteArrayElements(exportResp, 0);
exportRespLen = env->GetArrayLength(exportResp);
// Since the exported key is contained within the export response, a buffer of the same size
// is guaranteed to be sufficient.
exportedKeyBufSize = exportRespLen;
exportedKeyBuf = (uint8_t *)malloc(exportedKeyBufSize);
VerifyOrExit(exportedKeyBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
err = keyExportClient->ProcessKeyExportResponse(exportRespBuf, exportRespLen, (uint64_t)responderNodeId, exportedKeyBuf, exportedKeyBufSize, exportedKeyLen, exportedKeyId);
SuccessOrExit(err);
err = JNIUtils::N2J_ByteArray(env, exportedKeyBuf, exportedKeyLen, exportedKey);
SuccessOrExit(err);
exit:
if (keyExportClient != NULL)
{
keyExportClient->Reset();
}
if (exportRespBuf != NULL)
{
env->ReleaseByteArrayElements(exportResp, (jbyte *)exportRespBuf, JNI_ABORT);
}
if (exportedKeyBuf != NULL)
{
free(exportedKeyBuf);
}
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
return exportedKey;
}
void WeaveKeyExportClientNative::processKeyExportReconfigure(JNIEnv *env, jclass cls, jlong nativeClientPtr, jbyteArray reconfig)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
const uint8_t *reconfigBuf = NULL;
jsize reconfigLen = 0;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
VerifyOrExit(reconfig != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
reconfigBuf = (uint8_t *)env->GetByteArrayElements(reconfig, 0);
reconfigLen = env->GetArrayLength(reconfig);
err = keyExportClient->ProcessKeyExportReconfigure(reconfigBuf, reconfigLen);
SuccessOrExit(err);
exit:
if (reconfigBuf != NULL)
{
env->ReleaseByteArrayElements(reconfig, (jbyte *)reconfigBuf, JNI_ABORT);
}
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
}
jboolean WeaveKeyExportClientNative::allowNestDevelopmentDevices(JNIEnv *env, jclass cls, jlong nativeClientPtr)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
jboolean res = JNI_FALSE;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
res = keyExportClient->AllowNestDevelopmentDevices() ? JNI_TRUE : JNI_FALSE;
exit:
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
return res;
}
void WeaveKeyExportClientNative::setAllowNestDevelopmentDevices(JNIEnv *env, jclass cls, jlong nativeClientPtr, jboolean val)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
keyExportClient->AllowNestDevelopmentDevices(val != JNI_FALSE);
exit:
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
}
jboolean WeaveKeyExportClientNative::allowSHA1DeviceCertificates(JNIEnv *env, jclass cls, jlong nativeClientPtr)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
jboolean res = JNI_FALSE;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
res = keyExportClient->AllowSHA1DeviceCerts() ? JNI_TRUE : JNI_FALSE;
exit:
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
return res;
}
void WeaveKeyExportClientNative::setAllowSHA1DeviceCertificates(JNIEnv *env, jclass cls, jlong nativeClientPtr, jboolean val)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
WeaveStandAloneKeyExportClient *keyExportClient = (WeaveStandAloneKeyExportClient *)nativeClientPtr;
VerifyOrExit(keyExportClient != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
keyExportClient->AllowSHA1DeviceCerts(val != JNI_FALSE);
exit:
if (err != WEAVE_NO_ERROR)
{
JNIUtils::ThrowError(env, err);
}
}
} // namespace SecuritySupport
} // namespace Weave
} // namespace nl