blob: 0a45945fe0be2154cc31344cd0a3505fd76f0baa [file] [log] [blame]
/*
*
* Copyright (c) 2016-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
* This file defines a Wrapper for C++ implementation of key export functionality
* to support pin encryption.
*
*/
#import "NLWeaveKeyExportClient.h"
#import "NLWeaveKeyExportSupport.h"
#include <Weave/Core/WeaveCore.h>
#include <Weave/Core/WeaveKeyIds.h>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Profiles/security/WeaveKeyExportClient.h>
using namespace nl::Weave::Profiles::Security::KeyExport;
NSString * const NLWeaveKeyExportClientErrorDomain = @"NLWeaveKeyExportClientErrorDomain";
@interface NLWeaveKeyExportClient () {
WeaveStandAloneKeyExportClient * _mKeyExportClientCpp;
}
@end
@implementation NLWeaveKeyExportClient
static UInt32 const kMaxPubKeySize = (((WEAVE_CONFIG_MAX_EC_BITS + 7) / 8) + 1) * 2;
static UInt32 const kMaxECDSASigSize = kMaxPubKeySize;
- (nullable NSData *)generateKeyExportRequest:(UInt32)keyId
responderNodeId:(UInt64)responderNodeId
accessToken:(NSData *)accessToken
error:(NSError **)errOut
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t exportReqLen = 0;
if (accessToken == nil) {
if (errOut) {
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainInvalidArgument
userInfo:nil];
}
return nil;
}
size_t exportReqBufSize = 7 // Key export request header size
+ kMaxPubKeySize // Ephemeral public key size
+ kMaxECDSASigSize // Size of bare signature field
+ [accessToken length] // Size equal to at least the total size of the client certificates
+ 1024; // Space for additional signature fields plus encoding overhead
if (exportReqBufSize > UINT16_MAX) {
if (errOut) {
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainInvalidExportBufferSize
userInfo:nil];
}
return nil;
}
NSMutableData * exportReqBuf = [[NSMutableData alloc] initWithLength:exportReqBufSize];
err = _mKeyExportClientCpp->GenerateKeyExportRequest((uint32_t) keyId, (uint64_t) responderNodeId,
(unsigned char *) [accessToken bytes], [accessToken length], (unsigned char *) [exportReqBuf mutableBytes],
exportReqBufSize, exportReqLen);
if (err != WEAVE_NO_ERROR) {
if (errOut) {
NSString * failureReason =
[NSString stringWithFormat:NSLocalizedString(@"GenerateKeyExportRequest error: %d", @""), err];
NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason };
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainKeyExportRequestFailure
userInfo:userInfo];
}
return nil;
}
[exportReqBuf setLength:exportReqLen];
return exportReqBuf;
}
- (nullable NSData *)generateKeyExportRequest:(UInt32)keyId
responderNodeId:(UInt64)responderNodeId
clientCert:(NSData *)clientCert
clientKey:(NSData *)clientKey
error:(NSError **)errOut
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
uint16_t exportReqLen = 0;
if (clientKey == nil || clientCert) {
if (errOut) {
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainInvalidArgument
userInfo:nil];
}
return nil;
}
size_t exportReqBufSize = 7 // Key export request header size
+ kMaxPubKeySize // Ephemeral public key size
+ kMaxECDSASigSize // Size of bare signature field
+ [clientCert length] // Size equal to at least the total size of the client certificates
+ 1024; // Space for additional signature fields plus encoding overhead
if (exportReqBufSize > UINT16_MAX) {
if (errOut) {
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainInvalidExportBufferSize
userInfo:nil];
}
return nil;
}
NSMutableData * exportReqBuf = [[NSMutableData alloc] initWithLength:exportReqBufSize];
err = _mKeyExportClientCpp->GenerateKeyExportRequest((uint32_t) keyId, (uint64_t) responderNodeId,
(unsigned char *) [clientCert bytes], [clientCert length], (unsigned char *) [clientKey bytes], [clientKey length],
(unsigned char *) [exportReqBuf mutableBytes], exportReqBufSize, exportReqLen);
if (err != WEAVE_NO_ERROR) {
if (errOut) {
NSString * failureReason =
[NSString stringWithFormat:NSLocalizedString(@"GenerateKeyExportRequest error: %d", @""), err];
NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason };
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainKeyExportRequestFailure
userInfo:userInfo];
}
return nil;
}
[exportReqBuf setLength:exportReqLen];
return exportReqBuf;
}
- (nullable NSData *)processKeyExportResponse:(UInt64)responderNodeId exportResp:(NSData *)exportResp error:(NSError **)errOut
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
if (exportResp == nil) {
if (errOut) {
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainInvalidArgument
userInfo:nil];
}
return nil;
}
// Since the exported key is contained within the export response, a buffer of the same size
// is guaranteed to be sufficient.
size_t exportedKeyBufLen = [exportResp length];
NSMutableData * exportedKeyBuf = [[NSMutableData alloc] initWithLength:exportedKeyBufLen];
uint16_t exportedKeyLen;
uint32_t exportedKeyId;
err = _mKeyExportClientCpp->ProcessKeyExportResponse((unsigned char *) [exportResp bytes], [exportResp length],
(uint64_t) responderNodeId, (unsigned char *) [exportedKeyBuf mutableBytes], exportedKeyBufLen, exportedKeyLen,
exportedKeyId);
if (err != WEAVE_NO_ERROR) {
if (errOut) {
NSString * failureReason =
[NSString stringWithFormat:NSLocalizedString(@"ProcessKeyExportResponse error:: %d", @""), err];
NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason };
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainKeyExportResponseFailure
userInfo:userInfo];
}
return nil;
}
[exportedKeyBuf setLength:exportedKeyLen];
return exportedKeyBuf;
}
- (void)reset
{
_mKeyExportClientCpp->Reset();
}
/**
@note
This function can only be called by the ARC runtime
*/
- (void)dealloc
{
_mKeyExportClientCpp->Reset();
delete _mKeyExportClientCpp;
}
- (BOOL)processKeyExportReconfigure:(NSData *)reconfig error:(NSError **)errOut
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
if (reconfig == nil) {
if (errOut) {
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainInvalidArgument
userInfo:nil];
}
return false;
}
err = _mKeyExportClientCpp->ProcessKeyExportReconfigure((unsigned char *) [reconfig bytes], [reconfig length]);
if (err != WEAVE_NO_ERROR) {
if (errOut) {
NSString * failureReason =
[NSString stringWithFormat:NSLocalizedString(@"ProcessKeyExportResponse error: %d", @""), err];
NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : failureReason };
*errOut = [NSError errorWithDomain:NLWeaveKeyExportClientErrorDomain
code:NLWeaveKeyExportClientErrorDomainProcessReconfiugreFailure
userInfo:userInfo];
}
return false;
}
return true;
}
- (BOOL)allowNestDevelopmentDevices
{
return _mKeyExportClientCpp->AllowNestDevelopmentDevices();
}
- (void)setAllowNestDevelopmentDevices:(BOOL)nestDev
{
_mKeyExportClientCpp->AllowNestDevelopmentDevices(nestDev);
}
- (BOOL)allowSHA1DeviceCertificates
{
return _mKeyExportClientCpp->AllowSHA1DeviceCerts();
}
- (void)setAllowSHA1DeviceCertificates:(BOOL)nestDev
{
_mKeyExportClientCpp->AllowSHA1DeviceCerts(nestDev);
}
- (instancetype)init
{
self = [super init];
if (self) {
_mKeyExportClientCpp = new WeaveStandAloneKeyExportClient();
_mKeyExportClientCpp->Init();
}
return self;
}
@end