Skip to content
This repository has been archived by the owner on Dec 20, 2023. It is now read-only.

Commit

Permalink
Added Operational Device Credentials Generation Function for the Weav…
Browse files Browse the repository at this point in the history
…e Device Layer.

  -- If needed, this function is called early during Weave stack initialization
     to provision device with initial set of operational credentials.
  -- In a special case, when device doesn't have operational credentials but it is already
     paired to account, a flag will be set that manufacturer-assigned credentials should
     be used as operational credentials.
  • Loading branch information
emargolis committed Feb 14, 2020
1 parent 715fa56 commit 52f0c17
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 30 deletions.
10 changes: 5 additions & 5 deletions src/adaptations/device-layer/DeviceControlServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,15 @@ WEAVE_ERROR DeviceControlServer::OnResetConfig(uint16_t resetFlags)
}

#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
// If the device operational credentials reset has been requested, clear
// the device operational credentials, if present.
// If the operational device credentials reset has been requested, clear
// and generate new operational device certificate and private key.
if ((resetFlags & kResetConfigFlag_OperationalCredentials) != 0)
{
WeaveLogProgress(DeviceLayer, "Reset operational credentials");
tmpErr = ConfigurationMgr().ClearOperationalDeviceCredentials();
WeaveLogProgress(DeviceLayer, "Reset operational device certificate and private key");
tmpErr = ConfigurationMgr().GenerateAndStoreOperationalDeviceCertAndPrivateKey();
if (tmpErr != WEAVE_NO_ERROR)
{
WeaveLogProgress(DeviceLayer, "ConfigurationMgr().ClearOperationalDeviceCredentials() failed: %s", ErrorStr(tmpErr));
WeaveLogProgress(DeviceLayer, "ConfigurationMgr().GenerateAndStoreOperationalDeviceCertAndPrivateKey() failed: %s", ErrorStr(tmpErr));
err = (err == WEAVE_NO_ERROR) ? tmpErr : err;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ class ConfigurationManager
bool IsMemberOfFabric();
bool IsFullyProvisioned();
#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
bool OperationalDeviceCredentialsProvisioned();
bool OperationalDeviceIdProvisioned(void);
bool OperationalDeviceCertAndPrivateKeyProvisioned(void);
#endif

void InitiateFactoryReset();
Expand Down Expand Up @@ -155,7 +156,8 @@ class ConfigurationManager
WEAVE_ERROR ReadPersistedStorageValue(::nl::Weave::Platform::PersistedStorage::Key key, uint32_t & value);
WEAVE_ERROR WritePersistedStorageValue(::nl::Weave::Platform::PersistedStorage::Key key, uint32_t value);
#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
WEAVE_ERROR ClearOperationalDeviceCredentials(void);
WEAVE_ERROR GenerateAndStoreOperationalDeviceId(void);
WEAVE_ERROR GenerateAndStoreOperationalDeviceCertAndPrivateKey(void);
void UseManufacturerCredentialsAsOperational(bool val);
#endif

Expand Down Expand Up @@ -521,14 +523,24 @@ inline WEAVE_ERROR ConfigurationManager::SetFailSafeArmed(bool val)

#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING

inline bool ConfigurationManager::OperationalDeviceCredentialsProvisioned()
inline bool ConfigurationManager::OperationalDeviceIdProvisioned()
{
return static_cast<ImplClass*>(this)->_OperationalDeviceCredentialsProvisioned();
return static_cast<ImplClass*>(this)->_OperationalDeviceIdProvisioned();
}

inline WEAVE_ERROR ConfigurationManager::ClearOperationalDeviceCredentials(void)
inline bool ConfigurationManager::OperationalDeviceCertAndPrivateKeyProvisioned()
{
return static_cast<ImplClass*>(this)->_ClearOperationalDeviceCredentials();
return static_cast<ImplClass*>(this)->_OperationalDeviceCertAndPrivateKeyProvisioned();
}

inline WEAVE_ERROR ConfigurationManager::GenerateAndStoreOperationalDeviceId(void)
{
return static_cast<ImplClass*>(this)->_GenerateAndStoreOperationalDeviceId();
}

inline WEAVE_ERROR ConfigurationManager::GenerateAndStoreOperationalDeviceCertAndPrivateKey(void)
{
return static_cast<ImplClass*>(this)->_GenerateAndStoreOperationalDeviceCertAndPrivateKey();
}

inline void ConfigurationManager::UseManufacturerCredentialsAsOperational(bool val)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ class GenericConfigurationManagerImpl
WEAVE_ERROR _StoreDeviceCertificate(const uint8_t * cert, size_t certLen);
WEAVE_ERROR _StoreDeviceIntermediateCACerts(const uint8_t * certs, size_t certsLen);
WEAVE_ERROR _StoreDevicePrivateKey(const uint8_t * key, size_t keyLen);
WEAVE_ERROR _ClearOperationalDeviceCredentials(void);
#endif
WEAVE_ERROR _GetManufacturerDeviceId(uint64_t & deviceId);
WEAVE_ERROR _StoreManufacturerDeviceId(uint64_t deviceId);
Expand Down Expand Up @@ -110,7 +109,10 @@ class GenericConfigurationManagerImpl
bool _IsFullyProvisioned();
WEAVE_ERROR _ComputeProvisioningHash(uint8_t * hashBuf, size_t hashBufSize);
#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
bool _OperationalDeviceCredentialsProvisioned();
WEAVE_ERROR _GenerateAndStoreOperationalDeviceId(void);
WEAVE_ERROR _GenerateAndStoreOperationalDeviceCertAndPrivateKey(void);
bool _OperationalDeviceIdProvisioned(void);
bool _OperationalDeviceCertAndPrivateKeyProvisioned(void);
void _UseManufacturerCredentialsAsOperational(bool val);
#endif

Expand All @@ -121,8 +123,7 @@ class GenericConfigurationManagerImpl
kFlag_IsServiceProvisioned = 0x01,
kFlag_IsMemberOfFabric = 0x02,
kFlag_IsPairedToAccount = 0x04,
kFlag_OperationalDeviceCredentialsProvisioned = 0x08,
kFlag_UseManufacturerCredentialsAsOperational = 0x10,
kFlag_UseManufacturerCredentialsAsOperational = 0x08,
};

uint8_t mFlags;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.h>
#include <BleLayer/WeaveBleServiceData.h>
#include <Weave/Support/Base64.h>
#include <Weave/Profiles/security/WeavePrivateKey.h>

#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD
#include <Weave/DeviceLayer/ThreadStackManager.h>
Expand All @@ -53,7 +54,6 @@ WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_Init()
SetFlag(mFlags, kFlag_IsServiceProvisioned, Impl()->ConfigValueExists(ImplClass::kConfigKey_ServiceConfig));
SetFlag(mFlags, kFlag_IsMemberOfFabric, Impl()->ConfigValueExists(ImplClass::kConfigKey_FabricId));
SetFlag(mFlags, kFlag_IsPairedToAccount, Impl()->ConfigValueExists(ImplClass::kConfigKey_PairedAccountId));
SetFlag(mFlags, kFlag_OperationalDeviceCredentialsProvisioned, Impl()->ConfigValueExists(ImplClass::kConfigKey_OperationalDeviceCert));

return WEAVE_NO_ERROR;
}
Expand Down Expand Up @@ -502,26 +502,19 @@ WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDevicePrivateKey(c
}

template<class ImplClass>
WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_ClearOperationalDeviceCredentials(void)
bool GenericConfigurationManagerImpl<ImplClass>::_OperationalDeviceIdProvisioned(void)
{
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceId);
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceCert);
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceICACerts);
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDevicePrivateKey);

ClearFlag(mFlags, kFlag_OperationalDeviceCredentialsProvisioned);

return WEAVE_NO_ERROR;
return Impl()->ConfigValueExists(ImplClass::kConfigKey_OperationalDeviceId);
}

template<class ImplClass>
bool GenericConfigurationManagerImpl<ImplClass>::_OperationalDeviceCredentialsProvisioned()
bool GenericConfigurationManagerImpl<ImplClass>::_OperationalDeviceCertAndPrivateKeyProvisioned(void)
{
return ::nl::GetFlag(mFlags, kFlag_OperationalDeviceCredentialsProvisioned);
return Impl()->ConfigValueExists(ImplClass::kConfigKey_OperationalDeviceCert);
}

template<class ImplClass>
bool GenericConfigurationManagerImpl<ImplClass>::UseManufacturerCredentialsAsOperational()
bool GenericConfigurationManagerImpl<ImplClass>::UseManufacturerCredentialsAsOperational(void)
{
return ::nl::GetFlag(mFlags, kFlag_UseManufacturerCredentialsAsOperational);
}
Expand All @@ -532,6 +525,132 @@ void GenericConfigurationManagerImpl<ImplClass>::_UseManufacturerCredentialsAsOp
SetFlag(mFlags, kFlag_UseManufacturerCredentialsAsOperational, val);
}

static WEAVE_ERROR GenerateOperationalECDSASignature(const uint8_t *hash, uint8_t hashLen, EncodedECDSASignature& ecdsaSig)
{
WEAVE_ERROR err;
uint8_t * weavePrivKey = NULL;
size_t weavePrivKeyLen;
uint32_t weaveCurveId;
EncodedECPublicKey pubKey;
EncodedECPrivateKey privKey;

// Determine the length of the private key.
err = ConfigurationMgr().GetDevicePrivateKey((uint8_t *)NULL, 0, weavePrivKeyLen);
SuccessOrExit(err);

// Fail if no private key has been configured.
VerifyOrExit(weavePrivKeyLen != 0, err = WEAVE_ERROR_KEY_NOT_FOUND);

// Create a temporary buffer to hold the private key.
weavePrivKey = (uint8_t *)Platform::Security::MemoryAlloc(weavePrivKeyLen);
VerifyOrExit(weavePrivKey != NULL, err = WEAVE_ERROR_NO_MEMORY);

// Read the private key.
err = ConfigurationMgr().GetDevicePrivateKey(weavePrivKey, weavePrivKeyLen, weavePrivKeyLen);
SuccessOrExit(err);

// Decode operational device private/public keys from private key TLV structure.
err = Profiles::Security::DecodeWeaveECPrivateKey(weavePrivKey, weavePrivKeyLen, weaveCurveId, pubKey, privKey);
SuccessOrExit(err);

// Generate operational device signature.
err = nl::Weave::Crypto::GenerateECDSASignature(Profiles::Security::WeaveCurveIdToOID(weaveCurveId),
hash, hashLen, privKey, ecdsaSig);
SuccessOrExit(err);

exit:
if (weavePrivKey != NULL)
{
Platform::Security::MemoryFree(weavePrivKey);
}
return err;
}

template<class ImplClass>
WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GenerateAndStoreOperationalDeviceId(void)
{
WEAVE_ERROR err;
uint64_t deviceId;

// Generate random device Id.
err = GenerateWeaveNodeId(deviceId);
SuccessOrExit(err);

// Store generated device Id.
err = _StoreDeviceId(deviceId);
SuccessOrExit(err);

exit:
if (err != WEAVE_NO_ERROR)
{
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceId);
}
return err;
}

template<class ImplClass>
WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GenerateAndStoreOperationalDeviceCertAndPrivateKey(void)
{
enum
{
kWeaveDeviceCertBufSize = 300, // Size of buffer needed to hold Weave device certificate.
kWeaveDevicePrivateKeyBufSize = 128, // Size of buffer needed to hold Weave device private key.
};

WEAVE_ERROR err;
uint64_t deviceId;
uint8_t weavePrivKey[kWeaveDevicePrivateKeyBufSize];
uint32_t weavePrivKeyLen;
uint8_t weaveCert[kWeaveDeviceCertBufSize];
uint16_t weaveCertLen;
uint8_t privKeyBuf[EncodedECPrivateKey::kMaxValueLength];
uint8_t pubKeyBuf[EncodedECPublicKey::kMaxValueLength];
EncodedECPublicKey pubKey;
EncodedECPrivateKey privKey;

// Clear intermediate CA certificate if it was provisioned.
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceICACerts);

// Get operational device Id.
err = _GetDeviceId(deviceId);
SuccessOrExit(err);

privKey.PrivKey = privKeyBuf;
privKey.PrivKeyLen = sizeof(privKeyBuf);

pubKey.ECPoint = pubKeyBuf;
pubKey.ECPointLen = sizeof(pubKeyBuf);

// Generate random EC private/public key pair.
err = GenerateECDHKey(Profiles::Security::WeaveCurveIdToOID(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID), pubKey, privKey);
SuccessOrExit(err);

// Encode Weave device EC private/public key pair into EllipticCurvePrivateKey TLV structure.
err = EncodeWeaveECPrivateKey(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID, &pubKey, privKey,
weavePrivKey, sizeof(weavePrivKey), weavePrivKeyLen);
SuccessOrExit(err);

// Store generated operational device private key.
err = _StoreDevicePrivateKey(weavePrivKey, weavePrivKeyLen);
SuccessOrExit(err);

// Generate self-signed operational device certificate.
err = Profiles::Security::GenerateOperationalDeviceCert(deviceId, pubKey, weaveCert, sizeof(weaveCert), weaveCertLen, GenerateOperationalECDSASignature);
SuccessOrExit(err);

// Store generated operational device certificate.
err = _StoreDeviceCertificate(weaveCert, weaveCertLen);
SuccessOrExit(err);

exit:
if (err != WEAVE_NO_ERROR)
{
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceCert);
Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDevicePrivateKey);
}
return err;
}

#endif // WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING

template<class ImplClass>
Expand Down Expand Up @@ -666,6 +785,14 @@ WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_ClearServiceProvisionin
Impl()->ClearConfigValue(ImplClass::kConfigKey_ServiceConfig);
Impl()->ClearConfigValue(ImplClass::kConfigKey_PairedAccountId);

#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
// If necessary, generate new operational device credentials (certificate and private key).
if (_IsPairedToAccount() || _IsServiceProvisioned())
{
_GenerateAndStoreOperationalDeviceCertAndPrivateKey();
}
#endif

// TODO: Move these behaviors out of configuration manager.

// If necessary, post an event alerting other subsystems to the change in
Expand Down Expand Up @@ -899,7 +1026,7 @@ bool GenericConfigurationManagerImpl<ImplClass>::_IsFullyProvisioned()
Impl()->IsPairedToAccount() &&
#endif
#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
(!UseManufacturerCredentialsAsOperational() && _OperationalDeviceCredentialsProvisioned()) &&
(!UseManufacturerCredentialsAsOperational() && _OperationalDeviceCertAndPrivateKeyProvisioned()) &&
#endif
Impl()->IsMemberOfFabric();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
*
* Copyright (c) 2020 Google LLC.
* Copyright (c) 2018 Nest Labs, Inc.
* All rights reserved.
*
Expand Down Expand Up @@ -82,6 +83,37 @@ WEAVE_ERROR GenericPlatformManagerImpl<ImplClass>::_InitWeaveStack(void)
}
SuccessOrExit(err);

#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
if (!ConfigurationMgr().OperationalDeviceCertAndPrivateKeyProvisioned())
{
// If paired to account keep using manufacturer device credentials as operational.
if (ConfigurationMgr().IsServiceProvisioned() && ConfigurationMgr().IsPairedToAccount())
{
ConfigurationMgr().UseManufacturerCredentialsAsOperational(true);
}
// Otherwise, generate and store operational device credentials.
else
{
if (!ConfigurationMgr().OperationalDeviceIdProvisioned())
{
err = ConfigurationMgr().GenerateAndStoreOperationalDeviceId();
}
if (err != WEAVE_NO_ERROR)
{
WeaveLogError(DeviceLayer, "GenerateAndStoreOperationalDeviceId() failed: %s", ErrorStr(err));
}
SuccessOrExit(err);

err = ConfigurationMgr().GenerateAndStoreOperationalDeviceCertAndPrivateKey();
if (err != WEAVE_NO_ERROR)
{
WeaveLogError(DeviceLayer, "GenerateAndStoreOperationalDeviceCertAndPrivateKey() failed: %s", ErrorStr(err));
}
SuccessOrExit(err);
}
}
#endif // WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING

// Initialize the Weave Inet layer.
new (&InetLayer) Inet::InetLayer();
err = InetLayer.Init(SystemLayer, NULL);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/profiles/device-control/DeviceControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ enum
kResetConfigFlag_NetworkConfig = 0x0001, /**< Reset network configuration information. */
kResetConfigFlag_FabricConfig = 0x0002, /**< Reset fabric configuration information. */
kResetConfigFlag_ServiceConfig = 0x0004, /**< Reset network configuration information. */
kResetConfigFlag_OperationalCredentials = 0x0008, /**< Reset device operational credentials. */
kResetConfigFlag_OperationalCredentials = 0x4000, /**< Reset device operational credentials. */
kResetConfigFlag_FactoryDefaults = 0x8000 /**< Reset device to full factory defaults. */
};

Expand Down

0 comments on commit 52f0c17

Please sign in to comment.