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

Commit d6d48a6

Browse files
committed
Added Operational Device Credentials Generation Function for the Weave Device Layer.
-- If needed, this function should be 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.
1 parent 83bec2e commit d6d48a6

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

src/adaptations/device-layer/include/Weave/DeviceLayer/ConfigurationManager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ class ConfigurationManager
154154
WEAVE_ERROR ReadPersistedStorageValue(::nl::Weave::Platform::PersistedStorage::Key key, uint32_t & value);
155155
WEAVE_ERROR WritePersistedStorageValue(::nl::Weave::Platform::PersistedStorage::Key key, uint32_t value);
156156
#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
157+
WEAVE_ERROR GenerateAndStoreOperationalDeviceCredentials(uint64_t deviceId = kNodeIdNotSpecified);
157158
WEAVE_ERROR ClearOperationalDeviceCredentials(void);
158159
void UseManufacturerCredentialsAsOperational(bool val);
159160
#endif
@@ -525,6 +526,11 @@ inline bool ConfigurationManager::OperationalDeviceCredentialsProvisioned()
525526
return static_cast<ImplClass*>(this)->_OperationalDeviceCredentialsProvisioned();
526527
}
527528

529+
inline WEAVE_ERROR ConfigurationManager::GenerateAndStoreOperationalDeviceCredentials(uint64_t deviceId)
530+
{
531+
return static_cast<ImplClass*>(this)->_GenerateAndStoreOperationalDeviceCredentials(deviceId);
532+
}
533+
528534
inline WEAVE_ERROR ConfigurationManager::ClearOperationalDeviceCredentials(void)
529535
{
530536
return static_cast<ImplClass*>(this)->_ClearOperationalDeviceCredentials();

src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class GenericConfigurationManagerImpl
110110
bool _IsFullyProvisioned();
111111
WEAVE_ERROR _ComputeProvisioningHash(uint8_t * hashBuf, size_t hashBufSize);
112112
#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
113+
WEAVE_ERROR _GenerateAndStoreOperationalDeviceCredentials(uint64_t deviceId);
113114
bool _OperationalDeviceCredentialsProvisioned();
114115
void _UseManufacturerCredentialsAsOperational(bool val);
115116
#endif

src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.ipp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.h>
3131
#include <BleLayer/WeaveBleServiceData.h>
3232
#include <Weave/Support/Base64.h>
33+
#include <Weave/Profiles/security/WeavePrivateKey.h>
3334

3435
#if WEAVE_DEVICE_CONFIG_ENABLE_THREAD
3536
#include <Weave/DeviceLayer/ThreadStackManager.h>
@@ -532,6 +533,115 @@ void GenericConfigurationManagerImpl<ImplClass>::_UseManufacturerCredentialsAsOp
532533
SetFlag(mFlags, kFlag_UseManufacturerCredentialsAsOperational, val);
533534
}
534535

536+
static WEAVE_ERROR GenerateOperationalECDSASignature(const uint8_t *hash, uint8_t hashLen, EncodedECDSASignature& ecdsaSig)
537+
{
538+
WEAVE_ERROR err;
539+
uint8_t * weavePrivKey = NULL;
540+
size_t weavePrivKeyLen;
541+
uint32_t weaveCurveId;
542+
EncodedECPublicKey pubKey;
543+
EncodedECPrivateKey privKey;
544+
545+
// Determine the length of the private key.
546+
err = ConfigurationMgr().GetDevicePrivateKey((uint8_t *)NULL, 0, weavePrivKeyLen);
547+
SuccessOrExit(err);
548+
549+
// Fail if no private key has been configured.
550+
VerifyOrExit(weavePrivKeyLen != 0, err = WEAVE_ERROR_KEY_NOT_FOUND);
551+
552+
// Create a temporary buffer to hold the private key.
553+
weavePrivKey = (uint8_t *)Platform::Security::MemoryAlloc(weavePrivKeyLen);
554+
VerifyOrExit(weavePrivKey != NULL, err = WEAVE_ERROR_NO_MEMORY);
555+
556+
// Read the private key.
557+
err = ConfigurationMgr().GetDevicePrivateKey(weavePrivKey, weavePrivKeyLen, weavePrivKeyLen);
558+
SuccessOrExit(err);
559+
560+
// Decode operational device private/public keys from private key TLV structure.
561+
err = Profiles::Security::DecodeWeaveECPrivateKey(weavePrivKey, weavePrivKeyLen, weaveCurveId, pubKey, privKey);
562+
SuccessOrExit(err);
563+
564+
// Generate operational device signature.
565+
err = nl::Weave::Crypto::GenerateECDSASignature(Profiles::Security::WeaveCurveIdToOID(weaveCurveId),
566+
hash, hashLen, privKey, ecdsaSig);
567+
SuccessOrExit(err);
568+
569+
exit:
570+
if (weavePrivKey != NULL)
571+
{
572+
Platform::Security::MemoryFree(weavePrivKey);
573+
}
574+
return err;
575+
}
576+
577+
template<class ImplClass>
578+
WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GenerateAndStoreOperationalDeviceCredentials(uint64_t deviceId)
579+
{
580+
enum
581+
{
582+
kWeaveDeviceCertBufSize = 300, // Size of buffer needed to hold Weave device certificate.
583+
kWeaveDevicePrivateKeyBufSize = 128, // Size of buffer needed to hold Weave device private key.
584+
};
585+
586+
WEAVE_ERROR err;
587+
uint8_t weavePrivKey[kWeaveDevicePrivateKeyBufSize];
588+
uint32_t weavePrivKeyLen;
589+
uint8_t weaveCert[kWeaveDeviceCertBufSize];
590+
uint16_t weaveCertLen;
591+
uint8_t privKeyBuf[EncodedECPrivateKey::kMaxValueLength];
592+
uint8_t pubKeyBuf[EncodedECPublicKey::kMaxValueLength];
593+
EncodedECPublicKey pubKey;
594+
EncodedECPrivateKey privKey;
595+
596+
// If not specified, generate random device Id.
597+
if (deviceId == kNodeIdNotSpecified)
598+
{
599+
err = GenerateWeaveNodeId(deviceId);
600+
SuccessOrExit(err);
601+
}
602+
603+
// Store generated device Id.
604+
err = _StoreDeviceId(deviceId);
605+
SuccessOrExit(err);
606+
607+
privKey.PrivKey = privKeyBuf;
608+
privKey.PrivKeyLen = sizeof(privKeyBuf);
609+
610+
pubKey.ECPoint = pubKeyBuf;
611+
pubKey.ECPointLen = sizeof(pubKeyBuf);
612+
613+
// Generate random EC private/public key pair.
614+
err = GenerateECDHKey(Profiles::Security::WeaveCurveIdToOID(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID), pubKey, privKey);
615+
SuccessOrExit(err);
616+
617+
// Encode Weave device EC private/public key pair into EllipticCurvePrivateKey TLV structure.
618+
err = EncodeWeaveECPrivateKey(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID, &pubKey, privKey,
619+
weavePrivKey, sizeof(weavePrivKey), weavePrivKeyLen);
620+
SuccessOrExit(err);
621+
622+
// Store generated operational device private key.
623+
err = _StoreDevicePrivateKey(weavePrivKey, weavePrivKeyLen);
624+
SuccessOrExit(err);
625+
626+
// Generate self-signed operational device certificate.
627+
err = Profiles::Security::GenerateOperationalDeviceCert(deviceId, pubKey, weaveCert, sizeof(weaveCert), weaveCertLen, GenerateOperationalECDSASignature);
628+
SuccessOrExit(err);
629+
630+
// Store generated operational device certificate.
631+
err = _StoreDeviceCertificate(weaveCert, weaveCertLen);
632+
SuccessOrExit(err);
633+
634+
// Set flag indicating that the device has been provisioned with operational credentials.
635+
SetFlag(mFlags, kFlag_OperationalDeviceCredentialsProvisioned, Impl()->ConfigValueExists(ImplClass::kConfigKey_OperationalDeviceCert));
636+
637+
exit:
638+
if (err != WEAVE_NO_ERROR)
639+
{
640+
_ClearOperationalDeviceCredentials();
641+
}
642+
return err;
643+
}
644+
535645
#endif // WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
536646

537647
template<class ImplClass>

src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericPlatformManagerImpl.ipp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
*
3+
* Copyright (c) 2019-2020 Google LLC.
34
* Copyright (c) 2018 Nest Labs, Inc.
45
* All rights reserved.
56
*
@@ -82,6 +83,27 @@ WEAVE_ERROR GenericPlatformManagerImpl<ImplClass>::_InitWeaveStack(void)
8283
}
8384
SuccessOrExit(err);
8485

86+
#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
87+
if (!ConfigurationMgr().OperationalDeviceCredentialsProvisioned())
88+
{
89+
// If paired to account keep using manufacturer device credentials as operational.
90+
if (ConfigurationMgr().IsServiceProvisioned() && ConfigurationMgr().IsPairedToAccount())
91+
{
92+
ConfigurationMgr().UseManufacturerCredentialsAsOperational(true);
93+
}
94+
// Otherwise, generate and store operational device credentials.
95+
else
96+
{
97+
err = ConfigurationMgr().GenerateAndStoreOperationalDeviceCredentials();
98+
if (err != WEAVE_NO_ERROR)
99+
{
100+
WeaveLogError(DeviceLayer, "GenerateAndStoreOperationalDeviceCredentials() failed: %s", ErrorStr(err));
101+
}
102+
SuccessOrExit(err);
103+
}
104+
}
105+
#endif // WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
106+
85107
// Initialize the Weave Inet layer.
86108
new (&InetLayer) Inet::InetLayer();
87109
err = InetLayer.Init(SystemLayer, NULL);

0 commit comments

Comments
 (0)