WIP: Support Certificate Provisioning at the Weave Device Layer.
diff --git a/src/adaptations/device-layer/CASEAuth.cpp b/src/adaptations/device-layer/CASEAuth.cpp
index e23b6de..8aab685 100644
--- a/src/adaptations/device-layer/CASEAuth.cpp
+++ b/src/adaptations/device-layer/CASEAuth.cpp
@@ -147,7 +147,7 @@
     SuccessOrExit(err);
 
     // Fail if no private key has been configured.
-    VerifyOrExit(privKeyLen != 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+    VerifyOrExit(privKeyLen != 0, err = WEAVE_ERROR_KEY_NOT_FOUND);
 
     // Create a temporary buffer to hold the private key.
     mPrivKeyBuf = (uint8_t *)MemoryAlloc(privKeyLen);
diff --git a/src/adaptations/device-layer/CertificateProvisioningClient.cpp b/src/adaptations/device-layer/CertificateProvisioningClient.cpp
new file mode 100644
index 0000000..ad6ee2e
--- /dev/null
+++ b/src/adaptations/device-layer/CertificateProvisioningClient.cpp
@@ -0,0 +1,602 @@
+/*
+ *
+ *    Copyright (c) 2019 Google LLC.
+ *    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.
+ */
+
+#include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>
+#include <Weave/DeviceLayer/internal/CertificateProvisioningClient.h>
+#include <Weave/Core/WeaveTLV.h>
+#include <Weave/Profiles/common/CommonProfile.h>
+#include <Weave/Profiles/security/WeaveCert.h>
+#include <Weave/Profiles/security/WeavePrivateKey.h>
+#include <Weave/Profiles/security/WeaveSig.h>
+
+using namespace ::nl;
+using namespace ::nl::Weave;
+using namespace ::nl::Weave::TLV;
+using namespace ::nl::Weave::Profiles;
+using namespace ::nl::Weave::Profiles::Security;
+using namespace ::nl::Weave::Profiles::Security::CertProvisioning;
+using namespace ::nl::Weave::Platform::Security;
+
+namespace nl {
+namespace Weave {
+namespace DeviceLayer {
+namespace Internal {
+
+using ::nl::Weave::Platform::Security::MemoryAlloc;
+using ::nl::Weave::Platform::Security::MemoryFree;
+
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+
+static EncodedECPrivateKey sDevicePrivKey;
+
+static WEAVE_ERROR sGenerateDeviceECDSASignature(const uint8_t *hash, uint8_t hashLen, EncodedECDSASignature& ecdsaSig)
+{
+    return nl::Weave::Crypto::GenerateECDSASignature(WeaveCurveIdToOID(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID),
+                                                     hash, hashLen, sDevicePrivKey, ecdsaSig);
+}
+
+/**
+ * Generates and stores Weave operational device credentials:
+ *   -- Weave device Id (if needed)
+ *   -- Weave device self-signed certificate
+ *   -- Weave device private key
+ *
+ * @retval #WEAVE_NO_ERROR         If Weave device credentials were successfully generated and stored.
+ */
+WEAVE_ERROR GenerateAndStoreOperationalDeviceCredentials(uint64_t deviceId)
+{
+    enum {
+        kWeaveDeviceKeyBufSize  = 128,
+        kWeaveDeviceCertBufSize = 300,
+    };
+    WEAVE_ERROR err;
+    uint8_t key[kWeaveDeviceKeyBufSize];
+    uint32_t keyLen;
+    uint8_t cert[kWeaveDeviceCertBufSize];
+    uint16_t certLen;
+    uint8_t privKey[EncodedECPrivateKey::kMaxValueLength];
+    uint8_t pubKey[EncodedECPublicKey::kMaxValueLength];
+    EncodedECPublicKey devicePubKey;
+
+    // If not specified, generate random device Id.
+    if (deviceId == kNodeIdNotSpecified)
+    {
+        err = GenerateWeaveNodeId(deviceId);
+        SuccessOrExit(err);
+    }
+
+    sDevicePrivKey.PrivKey = privKey;
+    sDevicePrivKey.PrivKeyLen = sizeof(privKey);
+
+    devicePubKey.ECPoint = pubKey;
+    devicePubKey.ECPointLen = sizeof(pubKey);
+
+    // Generate random EC private/public key pair.
+    err = GenerateECDHKey(WeaveCurveIdToOID(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID), devicePubKey, sDevicePrivKey);
+    SuccessOrExit(err);
+
+    // Encode Weave device EC private/public key pair into EllipticCurvePrivateKey TLV structure.
+    err = EncodeWeaveECPrivateKey(WEAVE_CONFIG_OPERATIONAL_DEVICE_CERT_CURVE_ID, &devicePubKey, sDevicePrivKey, key, sizeof(key), keyLen);
+    SuccessOrExit(err);
+
+    // Generate self-signed operational device certificate.
+    err = GenerateOperationalDeviceCert(deviceId, devicePubKey, cert, sizeof(cert), certLen, sGenerateDeviceECDSASignature);
+    SuccessOrExit(err);
+
+    // Store generated device credentials.
+    err = ConfigurationMgr().StoreDeviceCredentials(deviceId, cert, certLen, key, keyLen);
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+WEAVE_ERROR CertificateProvisioningClient::Init(uint8_t reqType)
+{
+    return Init(reqType, NULL);
+}
+
+/**
+ * Initialize certificate provisioning client.
+ *
+ *  @param[in]  reqType              Get certificate request type.
+ *  @param[in]  encodeReqAuthInfo    A pointer to a function that generates ECDSA signature on the given
+ *                                   certificate hash using operational device private key.
+ *
+ *  @retval #WEAVE_NO_ERROR          If certificate provisioning client was successfully initialized.
+ */
+WEAVE_ERROR CertificateProvisioningClient::Init(uint8_t reqType, EncodeReqAuthInfoFunct encodeReqAuthInfo)
+{
+    mReqType = reqType;
+    mDoManufAttest = (reqType == WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert) ? true : false;
+
+    mEncodeReqAuthInfo = encodeReqAuthInfo;
+
+    mBinding = NULL;
+    mWaitingForServiceConnectivity = false;
+
+    return WEAVE_NO_ERROR;
+}
+
+/**
+ *  Handler for Certificate Provisioning Client API events.
+ *
+ *  @param[in]  appState    A pointer to application-defined state information associated with the client object.
+ *  @param[in]  eventType   Event ID passed by the event callback.
+ *  @param[in]  inParam     Reference of input event parameters passed by the event callback.
+ *  @param[in]  outParam    Reference of output event parameters passed by the event callback.
+ *
+ */
+void CertificateProvisioningClient::CertProvClientEventHandler(void * appState, WeaveCertProvEngine::EventType eventType, const WeaveCertProvEngine::InEventParam & inParam, WeaveCertProvEngine::OutEventParam & outParam)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    CertificateProvisioningClient * client = static_cast<CertificateProvisioningClient *>(appState);
+    WeaveCertProvEngine * certProvEngine = inParam.Source;
+
+    switch (eventType)
+    {
+    case WeaveCertProvEngine::kEvent_PrepareAuthorizeInfo:
+    {
+        if (client->mEncodeReqAuthInfo != NULL)
+        {
+            WeaveLogProgress(DeviceLayer, "Preparing authorization information for the GetCertificateRequest message");
+
+            err = client->mEncodeReqAuthInfo(*inParam.PrepareAuthorizeInfo.Writer);
+            SuccessOrExit(err);
+        }
+
+        break;
+    }
+
+    case WeaveCertProvEngine::kEvent_ResponseReceived:
+    {
+        if (inParam.ResponseReceived.ReplaceCert)
+        {
+            // Store service issued operational device certificate.
+            err = ConfigurationMgr().StoreDeviceCertificate(inParam.ResponseReceived.Cert, inParam.ResponseReceived.CertLen);
+            SuccessOrExit(err);
+
+            if (inParam.ResponseReceived.RelatedCerts != NULL)
+            {
+                // Store device intermediate CA certificates related to the service issued operational device certificate.
+                err = ConfigurationMgr().StoreDeviceICACerts(inParam.ResponseReceived.RelatedCerts, inParam.ResponseReceived.RelatedCertsLen);
+                SuccessOrExit(err);
+            }
+
+            // Post an event alerting other subsystems that the device now has new certificate.
+            {
+                WeaveDeviceEvent event;
+                event.Type = DeviceEventType::kDeviceCredentialsChange;
+                event.DeviceCredentialsChange.AreCredentialsProvisioned = true;
+                PlatformMgr().PostEvent(&event);
+            }
+
+            WeaveLogProgress(DeviceLayer, "Stored new operational device certificate received from the CA service");
+        }
+        else
+        {
+            WeaveLogProgress(DeviceLayer, "CA service reported: no need to replace operational device certificate");
+        }
+
+        certProvEngine->AbortCertificateProvisioning();
+
+        break;
+    }
+
+    case WeaveCertProvEngine::kEvent_CommunicationError:
+    {
+        if (inParam.CommunicationError.Reason == WEAVE_ERROR_STATUS_REPORT_RECEIVED)
+        {
+            WeaveLogError(DeviceLayer, "Received status report from the CA service: %s",
+                          nl::StatusReportStr(inParam.CommunicationError.RcvdStatusReport->mProfileId, inParam.CommunicationError.RcvdStatusReport->mStatusCode));
+        }
+        else
+        {
+            WeaveLogError(DeviceLayer, "Failed to prepare/send GetCertificateRequest message: %s", ErrorStr(inParam.CommunicationError.Reason));
+        }
+
+        certProvEngine->AbortCertificateProvisioning();
+
+        break;
+    }
+
+    default:
+        WeaveLogError(DeviceLayer, "Unrecognized certificate provisioning API event");
+        break;
+    }
+
+exit:
+    if (eventType == WeaveCertProvEngine::kEvent_PrepareAuthorizeInfo)
+        outParam.PrepareAuthorizeInfo.Error = err;
+    else if (eventType == WeaveCertProvEngine::kEvent_ResponseReceived)
+        outParam.ResponseReceived.Error = err;
+}
+
+// ===== Methods that implement the WeaveNodeOpAuthDelegate interface
+
+WEAVE_ERROR CertificateProvisioningClient::EncodeOpCert(TLVWriter & writer, uint64_t tag)
+{
+    WEAVE_ERROR err;
+    uint8_t * cert = NULL;
+    size_t certLen = 0;
+
+    // Determine the length of the operational device certificate.
+    err = ConfigurationMgr().GetDeviceCertificate((uint8_t *)NULL, 0, certLen);
+    SuccessOrExit(err);
+
+    // Fail if no operational device certificate has been configured.
+    VerifyOrExit(certLen != 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+
+    // Create a temporary buffer to hold the operational device certificate.
+    cert = static_cast<uint8_t *>(MemoryAlloc(certLen));
+    VerifyOrExit(cert != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    // Read the operational device certificate.
+    err = ConfigurationMgr().GetDeviceCertificate(cert, certLen, certLen);
+    SuccessOrExit(err);
+
+    // Copy encoded operational device certificate.
+    err = writer.CopyContainer(tag, cert, certLen);
+    SuccessOrExit(err);
+
+exit:
+    if (cert != NULL)
+    {
+        MemoryFree(cert);
+    }
+    return err;
+}
+
+WEAVE_ERROR CertificateProvisioningClient::EncodeOpRelatedCerts(TLVWriter & writer, uint64_t tag)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    uint8_t * caCerts = NULL;
+    size_t caCertsLen = 0;
+
+    if (ConfigurationMgr().DeviceICACertsProvisioned())
+    {
+        // Determine the length of the operational device intermediate certificates.
+        err = ConfigurationMgr().GetDeviceICACerts((uint8_t *)NULL, 0, caCertsLen);
+        SuccessOrExit(err);
+
+        // Fail if no operational device intermediate certificates array has been configured.
+        VerifyOrExit(caCertsLen != 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+
+        // Create a temporary buffer to hold the operational device intermediate certificates.
+        caCerts = static_cast<uint8_t *>(MemoryAlloc(caCertsLen));
+        VerifyOrExit(caCerts != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+        // Read the operational device intermediate certificates.
+        err = ConfigurationMgr().GetDeviceCertificate(caCerts, caCertsLen, caCertsLen);
+        SuccessOrExit(err);
+
+        // Copy encoded operational device intermediate certificates array.
+        err = writer.CopyContainer(tag, caCerts, caCertsLen);
+        SuccessOrExit(err);
+    }
+
+exit:
+    if (caCerts != NULL)
+    {
+        MemoryFree(caCerts);
+    }
+    return err;
+}
+
+WEAVE_ERROR CertificateProvisioningClient::GenerateAndEncodeOpSig(const uint8_t * hash, uint8_t hashLen, TLVWriter & writer, uint64_t tag)
+{
+    WEAVE_ERROR err;
+    uint8_t * privKey = NULL;
+    size_t privKeyLen = 0;
+
+    // Determine the length of the operational device private key.
+    err = ConfigurationMgr().GetDevicePrivateKey((uint8_t *)NULL, 0, privKeyLen);
+    SuccessOrExit(err);
+
+    // Fail if no operational device private key has been configured.
+    VerifyOrExit(privKeyLen != 0, err = WEAVE_ERROR_KEY_NOT_FOUND);
+
+    // Create a temporary buffer to hold the operational device private key.
+    privKey = static_cast<uint8_t *>(MemoryAlloc(privKeyLen));
+    VerifyOrExit(privKey != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    // Read the operational device private key.
+    err = ConfigurationMgr().GetDevicePrivateKey(privKey, privKeyLen, privKeyLen);
+    SuccessOrExit(err);
+
+    // Generate and encode operational device signature.
+    err = GenerateAndEncodeWeaveECDSASignature(writer, tag, hash, hashLen, privKey, privKeyLen);
+    SuccessOrExit(err);
+
+exit:
+    if (privKey != NULL)
+    {
+        MemoryFree(privKey);
+    }
+    return err;
+}
+
+// ===== Methods that implement the WeaveNodeManufAttestDelegate interface
+
+WEAVE_ERROR CertificateProvisioningClient::EncodeMAInfo(TLVWriter & writer)
+{
+    WEAVE_ERROR err;
+    uint8_t * cert = NULL;
+    size_t certLen = 0;
+
+    // Determine the length of the manufacturer attestation device certificate.
+    err = ConfigurationMgr().GetManufAttestDeviceCertificate((uint8_t *)NULL, 0, certLen);
+    SuccessOrExit(err);
+
+    // Fail if no manufacturer attestation device certificate has been configured.
+    VerifyOrExit(certLen != 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+
+    // Create a temporary buffer to hold the manufacturer attestation device certificate.
+    cert = static_cast<uint8_t *>(MemoryAlloc(certLen));
+    VerifyOrExit(cert != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    // Read the manufacturer attestation device certificate.
+    err = ConfigurationMgr().GetManufAttestDeviceCertificate(cert, certLen, certLen);
+    SuccessOrExit(err);
+
+    // Copy encoded manufacturer attestation device certificate.
+    err = writer.CopyContainer(ContextTag(kTag_GetCertReqMsg_ManufAttest_WeaveCert), cert, certLen);
+    SuccessOrExit(err);
+
+    if (ConfigurationMgr().ManufAttestDeviceICACertsProvisioned())
+    {
+        size_t caCertsLen = 0;
+
+        // Determine the length of the manufacturer attestation device intermediate CA certificates.
+        err = ConfigurationMgr().GetManufAttestDeviceICACerts((uint8_t *)NULL, 0, caCertsLen);
+        SuccessOrExit(err);
+
+        // If needed, allocate larger buffer to hold the intermediate CA certificates.
+        if (caCertsLen > certLen)
+        {
+            MemoryFree(cert);
+
+            cert = static_cast<uint8_t *>(MemoryAlloc(caCertsLen));
+            VerifyOrExit(cert != NULL, err = WEAVE_ERROR_NO_MEMORY);
+        }
+
+        // Read the manufacturer attestation device intermediate CA certificates.
+        err = ConfigurationMgr().GetManufAttestDeviceICACerts(cert, caCertsLen, caCertsLen);
+        SuccessOrExit(err);
+
+        // Copy encoded manufacturer attestation device intermediate CA certificates.
+        err = writer.CopyContainer(ContextTag(kTag_GetCertReqMsg_ManufAttest_WeaveRelCerts), cert, caCertsLen);
+        SuccessOrExit(err);
+    }
+
+exit:
+    if (cert != NULL)
+    {
+        MemoryFree(cert);
+    }
+    return err;
+}
+
+WEAVE_ERROR CertificateProvisioningClient::GenerateAndEncodeMASig(const uint8_t * data, uint16_t dataLen, TLVWriter & writer)
+{
+    WEAVE_ERROR err;
+    uint8_t * privKey = NULL;
+    size_t privKeyLen = 0;
+    nl::Weave::Platform::Security::SHA256 sha256;
+    uint8_t hash[SHA256::kHashLength];
+
+    // Determine the length of the manufacturer attestation device private key.
+    err = ConfigurationMgr().GetDevicePrivateKey((uint8_t *)NULL, 0, privKeyLen);
+    SuccessOrExit(err);
+
+    // Fail if no manufacturer attestation device private key has been configured.
+    VerifyOrExit(privKeyLen != 0, err = WEAVE_ERROR_KEY_NOT_FOUND);
+
+    // Create a temporary buffer to hold the manufacturer attestation device private key.
+    privKey = static_cast<uint8_t *>(MemoryAlloc(privKeyLen));
+    VerifyOrExit(privKey != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    // Read the manufacturer attestation device private key.
+    err = ConfigurationMgr().GetDevicePrivateKey(privKey, privKeyLen, privKeyLen);
+    SuccessOrExit(err);
+
+    // Calculate data hash.
+    sha256.Begin();
+    sha256.AddData(data, dataLen);
+    sha256.Finish(hash);
+
+    // Encode manufacturer attestation device signature algorithm: ECDSAWithSHA256.
+    err = writer.Put(ContextTag(kTag_GetCertReqMsg_ManufAttestSigAlgo), static_cast<uint16_t>(ASN1::kOID_SigAlgo_ECDSAWithSHA256));
+    SuccessOrExit(err);
+
+    // Generate and encode manufacturer attestation device signature.
+    err = GenerateAndEncodeWeaveECDSASignature(writer, ContextTag(kTag_GetCertReqMsg_ManufAttestSig_ECDSA),
+                                               hash, SHA256::kHashLength, privKey, privKeyLen);
+    SuccessOrExit(err);
+
+exit:
+    if (privKey != NULL)
+    {
+        MemoryFree(privKey);
+    }
+    return err;
+}
+
+// ===== Members for internal use by this class only.
+
+void CertificateProvisioningClient::OnPlatformEvent(const WeaveDeviceEvent * event)
+{
+    // If a tunnel to the service has been established...
+    // OR if service connectivity has been established (e.g. via Thread)...
+    if ((event->Type == DeviceEventType::kServiceTunnelStateChange &&
+         event->ServiceTunnelStateChange.Result == kConnectivity_Established) ||
+        (event->Type == DeviceEventType::kServiceConnectivityChange &&
+         event->ServiceConnectivityChange.Overall.Result == kConnectivity_Established))
+    {
+        // If the system is waiting for the service connectivity to be established,
+        // initiate the Certificate Provisioning now.
+        if (mWaitingForServiceConnectivity)
+        {
+            StartCertificateProvisioning();
+        }
+    }
+}
+
+void CertificateProvisioningClient::StartCertificateProvisioning(void)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    // If the system does not currently have a tunnel established with the service,
+    // AND the system does not have service connectivity by some other means (e.g. Thread)
+    // wait a period of time for connectivity to be established.
+    if (!ConnectivityMgr().HaveServiceConnectivity() && !ConnectivityMgr().IsServiceTunnelConnected())
+    {
+        mWaitingForServiceConnectivity = true;
+
+        err = SystemLayer.StartTimer(WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_CONNECTIVITY_TIMEOUT,
+                                     HandleServiceConnectivityTimeout, this);
+        SuccessOrExit(err);
+        ExitNow();
+
+        WeaveLogProgress(DeviceLayer, "Waiting for service connectivity to complete RegisterServicePairDevice action");
+    }
+
+    mWaitingForServiceConnectivity = false;
+    SystemLayer.CancelTimer(HandleServiceConnectivityTimeout, this);
+
+    WeaveLogProgress(DeviceLayer, "Initiating communication with Service Provisioning service");
+
+    // Create a binding and begin the process of preparing it for talking to the Certificate Provisioning
+    // service. When this completes HandleCertProvBindingEvent will be called with a BindingReady event.
+    mBinding = nl::Weave::DeviceLayer::ExchangeMgr.NewBinding(HandleCertProvBindingEvent, NULL);
+    VerifyOrExit(mBinding != NULL, err = WEAVE_ERROR_NO_MEMORY);
+    err = mBinding->BeginConfiguration()
+            .Target_ServiceEndpoint(WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_ENDPOINT_ID)
+            .Transport_UDP_WRM()
+            .Exchange_ResponseTimeoutMsec(WEAVE_DEVICE_CONFIG_GET_CERTIFICATE_REQUEST_TIMEOUT)
+            .Security_SharedCASESession()
+            .PrepareBinding();
+    SuccessOrExit(err);
+
+    err = mCertProvEngine.Init(mBinding, this, this, CertProvClientEventHandler, this);
+    SuccessOrExit(err);
+
+exit:
+    if (err != WEAVE_NO_ERROR)
+    {
+        HandleCertificateProvisioningResult(err, kWeaveProfile_Common, Profiles::Common::kStatus_InternalError);
+    }
+}
+
+void CertificateProvisioningClient::SendGetCertificateRequest(void)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    WeaveLogProgress(DeviceLayer, "Sending GetCertificateRequest to Certificate Provisioning service");
+
+    err = mCertProvEngine.StartCertificateProvisioning(mReqType, mDoManufAttest);
+    SuccessOrExit(err);
+
+exit:
+    if (err != WEAVE_NO_ERROR)
+    {
+        HandleCertificateProvisioningResult(err, kWeaveProfile_Common, Profiles::Common::kStatus_InternalError);
+    }
+}
+
+void CertificateProvisioningClient::HandleCertificateProvisioningResult(WEAVE_ERROR err, uint32_t statusReportProfileId, uint16_t statusReportStatusCode)
+{
+    // Close the binding if necessary.
+    if (mBinding != NULL)
+    {
+        mBinding->Close();
+        mBinding = NULL;
+    }
+
+    if (err != WEAVE_NO_ERROR)
+    {
+        WeaveLogError(DeviceLayer, "Certificate Provisioning failed with %s: %s",
+                 (err == WEAVE_ERROR_STATUS_REPORT_RECEIVED) ? "status report from service" : "local error",
+                 (err == WEAVE_ERROR_STATUS_REPORT_RECEIVED)
+                  ? ::nl::StatusReportStr(statusReportProfileId, statusReportStatusCode)
+                  : ::nl::ErrorStr(err));
+
+        // Choose an appropriate StatusReport to return if not already given.
+        if (statusReportProfileId == 0 && statusReportStatusCode == 0)
+        {
+            if (err == WEAVE_ERROR_TIMEOUT)
+            {
+                statusReportProfileId = kWeaveProfile_Security;
+                statusReportStatusCode = Profiles::Security::kStatusCode_ServiceCommunicationError;
+            }
+            else
+            {
+                statusReportProfileId = kWeaveProfile_Common;
+                statusReportStatusCode = Profiles::Common::kStatus_InternalError;
+            }
+        }
+
+        // TODO: Error CallBack to the the Calling Application.
+    }
+}
+
+void CertificateProvisioningClient::HandleServiceConnectivityTimeout(System::Layer * aSystemLayer, void * aAppState, System::Error aErr)
+{
+    CertificateProvisioningClient *client = static_cast<CertificateProvisioningClient *>(aAppState);
+
+    client->HandleCertificateProvisioningResult(WEAVE_ERROR_TIMEOUT, 0, 0);
+}
+
+void CertificateProvisioningClient::HandleCertProvBindingEvent(void * appState, Binding::EventType eventType,
+            const Binding::InEventParam & inParam, Binding::OutEventParam & outParam)
+{
+    uint32_t statusReportProfileId;
+    uint16_t statusReportStatusCode;
+    CertificateProvisioningClient *client = static_cast<CertificateProvisioningClient *>(appState);
+
+    switch (eventType)
+    {
+    case Binding::kEvent_BindingReady:
+        client->SendGetCertificateRequest();
+        break;
+    case Binding::kEvent_PrepareFailed:
+        if (inParam.PrepareFailed.StatusReport != NULL)
+        {
+            statusReportProfileId = inParam.PrepareFailed.StatusReport->mProfileId;
+            statusReportStatusCode = inParam.PrepareFailed.StatusReport->mStatusCode;
+        }
+        else
+        {
+            statusReportProfileId = kWeaveProfile_Security;
+            statusReportStatusCode = Profiles::Security::kStatusCode_ServiceCommunicationError;
+        }
+        client->HandleCertificateProvisioningResult(inParam.PrepareFailed.Reason,
+                statusReportProfileId, statusReportStatusCode);
+        break;
+    default:
+        Binding::DefaultEventHandler(appState, eventType, inParam, outParam);
+        break;
+    }
+}
+
+#endif // WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace Weave
+} // namespace nl
diff --git a/src/adaptations/device-layer/DeviceControlServer.cpp b/src/adaptations/device-layer/DeviceControlServer.cpp
index 51fec14..c4fd215 100644
--- a/src/adaptations/device-layer/DeviceControlServer.cpp
+++ b/src/adaptations/device-layer/DeviceControlServer.cpp
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -109,6 +110,21 @@
             ThreadStackMgr().ClearThreadProvision();
 #endif // WEAVE_DEVICE_CONFIG_ENABLE_THREAD
         }
+
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+        // If a credentials config request has been requested, clear the credential
+        // data, if present.
+        if ((resetFlags & kResetConfigFlag_Credentials) != 0)
+        {
+            WeaveLogProgress(DeviceLayer, "Reset credentials");
+            tmpErr = ConfigurationMgr().ClearDeviceCredentials();
+            if (tmpErr != WEAVE_NO_ERROR)
+            {
+                WeaveLogProgress(DeviceLayer, "ConfigurationMgr().ClearDeviceCredentials() failed: %s", ErrorStr(tmpErr));
+                err = (err == WEAVE_NO_ERROR) ? tmpErr : err;
+            }
+        }
+#endif // WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
     }
 
     return err;
@@ -171,7 +187,8 @@
     }
 
     const uint16_t supportedResetOps =
-            (kResetConfigFlag_NetworkConfig | kResetConfigFlag_FabricConfig | kResetConfigFlag_ServiceConfig);
+            (kResetConfigFlag_NetworkConfig | kResetConfigFlag_FabricConfig |
+             kResetConfigFlag_ServiceConfig | kResetConfigFlag_Credentials);
 
     // Otherwise, verify the requested reset operation is supported.
     return (resetFlags == kResetConfigFlag_All || (resetFlags & ~supportedResetOps) == 0);
@@ -213,5 +230,3 @@
 } // namespace DeviceLayer
 } // namespace Weave
 } // namespace nl
-
-
diff --git a/src/adaptations/device-layer/ESP32/BLEManagerImpl.cpp b/src/adaptations/device-layer/ESP32/BLEManagerImpl.cpp
index 9107270..8c06ac2 100644
--- a/src/adaptations/device-layer/ESP32/BLEManagerImpl.cpp
+++ b/src/adaptations/device-layer/ESP32/BLEManagerImpl.cpp
@@ -245,6 +245,7 @@
     case DeviceEventType::kFabricMembershipChange:
     case DeviceEventType::kServiceProvisioningChange:
     case DeviceEventType::kAccountPairingChange:
+    case DeviceEventType::kDeviceCredentialsChange:
 
         // If WOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the
         // device's provisioning state, then automatically disable WoBLE advertising if the device
@@ -1302,4 +1303,3 @@
 } // namespace nl
 
 #endif // WEAVE_DEVICE_CONFIG_ENABLE_WOBLE
-
diff --git a/src/adaptations/device-layer/ESP32/ConnectivityManagerImpl.cpp b/src/adaptations/device-layer/ESP32/ConnectivityManagerImpl.cpp
index 93e26bd..f94ec81 100644
--- a/src/adaptations/device-layer/ESP32/ConnectivityManagerImpl.cpp
+++ b/src/adaptations/device-layer/ESP32/ConnectivityManagerImpl.cpp
@@ -525,18 +525,19 @@
         DriveServiceTunnelState();
     }
 
-#if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
+#if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING || WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
 
-    // Handle account pairing changes.
-    else if (event->Type == DeviceEventType::kAccountPairingChange)
-    {
-        // When account pairing successfully completes, if the tunnel to the
-        // service is subject to routing restrictions (imposed because at the time
-        // the tunnel was established the device was not paired to an account)
+    // Handle account pairing and device credentials changes.
+    else if (((event->Type == DeviceEventType::kAccountPairingChange) && event->AccountPairingChange.IsPairedToAccount) ||
+             ((event->Type == DeviceEventType::kDeviceCredentialsChange) && event->DeviceCredentialsChange.AreCredentialsProvisioned))
+        {
+        // When account pairing successfully completes or new device credentials
+        // provisioned, if the tunnel to the service is subject to routing restrictions
+        // (imposed because at the time the tunnel was established the device was
+        // not paired to an account or the device only had initial self-signed certificate)
         // then force the tunnel to close.  This will result in the tunnel being
         // re-established, which should lift the service-side restrictions.
-        if (event->AccountPairingChange.IsPairedToAccount &&
-            GetFlag(mFlags, kFlag_ServiceTunnelStarted) &&
+        if (GetFlag(mFlags, kFlag_ServiceTunnelStarted) &&
             ServiceTunnelAgent.IsTunnelRoutingRestricted())
         {
             WeaveLogProgress(DeviceLayer, "Restarting service tunnel to lift routing restrictions");
@@ -546,7 +547,7 @@
         }
     }
 
-#endif // !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
+#endif // !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING || WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
 }
 
 void ConnectivityManagerImpl::_OnWiFiScanDone()
diff --git a/src/adaptations/device-layer/ESP32/ESP32Config.cpp b/src/adaptations/device-layer/ESP32/ESP32Config.cpp
index 4202160..17160f6 100644
--- a/src/adaptations/device-layer/ESP32/ESP32Config.cpp
+++ b/src/adaptations/device-layer/ESP32/ESP32Config.cpp
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -40,27 +41,32 @@
 const char ESP32Config::kConfigNamespace_WeaveCounters[]                   = "weave-counters";
 
 // Keys stored in the weave-factory namespace
-const ESP32Config::Key ESP32Config::kConfigKey_SerialNum               = { kConfigNamespace_WeaveFactory, "serial-num"         };
-const ESP32Config::Key ESP32Config::kConfigKey_DeviceId                = { kConfigNamespace_WeaveFactory, "device-id"          };
-const ESP32Config::Key ESP32Config::kConfigKey_DeviceCert              = { kConfigNamespace_WeaveFactory, "device-cert"        };
-const ESP32Config::Key ESP32Config::kConfigKey_DevicePrivateKey        = { kConfigNamespace_WeaveFactory, "device-key"         };
-const ESP32Config::Key ESP32Config::kConfigKey_ProductRevision         = { kConfigNamespace_WeaveFactory, "product-rev"        };
-const ESP32Config::Key ESP32Config::kConfigKey_ManufacturingDate       = { kConfigNamespace_WeaveFactory, "mfg-date"           };
-const ESP32Config::Key ESP32Config::kConfigKey_PairingCode             = { kConfigNamespace_WeaveFactory, "pairing-code"       };
+const ESP32Config::Key ESP32Config::kConfigKey_SerialNum                   = { kConfigNamespace_WeaveFactory, "serial-num"         };
+const ESP32Config::Key ESP32Config::kConfigKey_ManufAttestDeviceId         = { kConfigNamespace_WeaveFactory, "ma-device-id"       };
+const ESP32Config::Key ESP32Config::kConfigKey_ManufAttestDeviceCert       = { kConfigNamespace_WeaveFactory, "ma-device-cert"     };
+const ESP32Config::Key ESP32Config::kConfigKey_ManufAttestDeviceICACerts   = { kConfigNamespace_WeaveFactory, "ma-device-ca-certs" };
+const ESP32Config::Key ESP32Config::kConfigKey_ManufAttestDevicePrivateKey = { kConfigNamespace_WeaveFactory, "ma-device-key"      };
+const ESP32Config::Key ESP32Config::kConfigKey_ProductRevision             = { kConfigNamespace_WeaveFactory, "product-rev"        };
+const ESP32Config::Key ESP32Config::kConfigKey_ManufacturingDate           = { kConfigNamespace_WeaveFactory, "mfg-date"           };
+const ESP32Config::Key ESP32Config::kConfigKey_PairingCode                 = { kConfigNamespace_WeaveFactory, "pairing-code"       };
 
 // Keys stored in the weave-config namespace
-const ESP32Config::Key ESP32Config::kConfigKey_FabricId                = { kConfigNamespace_WeaveConfig,  "fabric-id"          };
-const ESP32Config::Key ESP32Config::kConfigKey_ServiceConfig           = { kConfigNamespace_WeaveConfig,  "service-config"     };
-const ESP32Config::Key ESP32Config::kConfigKey_PairedAccountId         = { kConfigNamespace_WeaveConfig,  "account-id"         };
-const ESP32Config::Key ESP32Config::kConfigKey_ServiceId               = { kConfigNamespace_WeaveConfig,  "service-id"         };
-const ESP32Config::Key ESP32Config::kConfigKey_FabricSecret            = { kConfigNamespace_WeaveConfig,  "fabric-secret"      };
-const ESP32Config::Key ESP32Config::kConfigKey_GroupKeyIndex           = { kConfigNamespace_WeaveConfig,  "group-key-index"    };
-const ESP32Config::Key ESP32Config::kConfigKey_LastUsedEpochKeyId      = { kConfigNamespace_WeaveConfig,  "last-ek-id"         };
-const ESP32Config::Key ESP32Config::kConfigKey_FailSafeArmed           = { kConfigNamespace_WeaveConfig,  "fail-safe-armed"    };
-const ESP32Config::Key ESP32Config::kConfigKey_WiFiStationSecType      = { kConfigNamespace_WeaveConfig,  "sta-sec-type"       };
+const ESP32Config::Key ESP32Config::kConfigKey_FabricId                    = { kConfigNamespace_WeaveConfig,  "fabric-id"          };
+const ESP32Config::Key ESP32Config::kConfigKey_ServiceConfig               = { kConfigNamespace_WeaveConfig,  "service-config"     };
+const ESP32Config::Key ESP32Config::kConfigKey_PairedAccountId             = { kConfigNamespace_WeaveConfig,  "account-id"         };
+const ESP32Config::Key ESP32Config::kConfigKey_ServiceId                   = { kConfigNamespace_WeaveConfig,  "service-id"         };
+const ESP32Config::Key ESP32Config::kConfigKey_FabricSecret                = { kConfigNamespace_WeaveConfig,  "fabric-secret"      };
+const ESP32Config::Key ESP32Config::kConfigKey_GroupKeyIndex               = { kConfigNamespace_WeaveConfig,  "group-key-index"    };
+const ESP32Config::Key ESP32Config::kConfigKey_LastUsedEpochKeyId          = { kConfigNamespace_WeaveConfig,  "last-ek-id"         };
+const ESP32Config::Key ESP32Config::kConfigKey_FailSafeArmed               = { kConfigNamespace_WeaveConfig,  "fail-safe-armed"    };
+const ESP32Config::Key ESP32Config::kConfigKey_WiFiStationSecType          = { kConfigNamespace_WeaveConfig,  "sta-sec-type"       };
+const ESP32Config::Key ESP32Config::kConfigKey_OperationalDeviceId         = { kConfigNamespace_WeaveConfig,  "op-device-id"       };
+const ESP32Config::Key ESP32Config::kConfigKey_OperationalDeviceCert       = { kConfigNamespace_WeaveConfig,  "op-device-cert"     };
+const ESP32Config::Key ESP32Config::kConfigKey_OperationalDeviceICACerts   = { kConfigNamespace_WeaveConfig,  "op-device-ca-certs" };
+const ESP32Config::Key ESP32Config::kConfigKey_OperationalDevicePrivateKey = { kConfigNamespace_WeaveConfig,  "op-device-key"      };
 
 // Prefix used for NVS keys that contain Weave group encryption keys.
-const char ESP32Config::kGroupKeyNamePrefix[]                        = "gk-";
+const char ESP32Config::kGroupKeyNamePrefix[]                              = "gk-";
 
 
 WEAVE_ERROR ESP32Config::ReadConfigValue(Key key, bool & val)
@@ -126,15 +132,15 @@
     SuccessOrExit(err);
     needClose = true;
 
-    // Special case the DeviceId value, optionally allowing it to be read as a blob containing a 64-bit
-    // big-endian integer, instead of a u64 value.
+    // Special case the ManufAttestDeviceId value, optionally allowing it to be read as a blob containing
+    // a 64-bit big-endian integer, instead of a u64 value.
     //
     // The ESP32 development environment provides a tool for pre-populating the NVS partition using
     // values from a CSV file.  This tool is convenient for provisioning devices during manufacturing.
-    // However currently the tool does not support pre-populating u64 values such as DeviceId.  Thus
-    // we allow DeviceId to be stored as a blob instead.
+    // However currently the tool does not support pre-populating u64 values such as ManufAttestDeviceId.
+    // Thus we allow ManufAttestDeviceId to be stored as a blob instead.
     //
-    if (key == kConfigKey_DeviceId)
+    if (key == kConfigKey_ManufAttestDeviceId)
     {
         uint8_t deviceIdBytes[sizeof(uint64_t)];
         size_t deviceIdLen = sizeof(deviceIdBytes);
diff --git a/src/adaptations/device-layer/Makefile.am b/src/adaptations/device-layer/Makefile.am
index 0812312..9a87a3b 100644
--- a/src/adaptations/device-layer/Makefile.am
+++ b/src/adaptations/device-layer/Makefile.am
@@ -66,6 +66,7 @@
     include/Weave/DeviceLayer/WeaveDeviceEvent.h \
     include/Weave/DeviceLayer/WeaveDeviceLayer.h \
     include/Weave/DeviceLayer/internal/BLEManager.h \
+    include/Weave/DeviceLayer/internal/CertificateProvisioningClient.h \
     include/Weave/DeviceLayer/internal/DeviceControlServer.h \
     include/Weave/DeviceLayer/internal/DeviceDescriptionServer.h \
     include/Weave/DeviceLayer/internal/DeviceIdentityTraitDataSource.h \
@@ -111,6 +112,7 @@
 
 libDeviceLayer_a_SOURCES                = \
     CASEAuth.cpp                          \
+    CertificateProvisioningClient.cpp     \
     DeviceControlServer.cpp               \
     DeviceDescriptionServer.cpp           \
     DeviceIdentityTraitDataSource.cpp     \
diff --git a/src/adaptations/device-layer/Makefile.in b/src/adaptations/device-layer/Makefile.in
index 7586211..70634a4 100644
--- a/src/adaptations/device-layer/Makefile.in
+++ b/src/adaptations/device-layer/Makefile.in
@@ -216,13 +216,13 @@
 libDeviceLayer_a_AR = $(AR) $(ARFLAGS)
 libDeviceLayer_a_LIBADD =
 am__libDeviceLayer_a_SOURCES_DIST = CASEAuth.cpp \
-	DeviceControlServer.cpp DeviceDescriptionServer.cpp \
-	DeviceIdentityTraitDataSource.cpp DeviceNetworkInfo.cpp \
-	EchoServer.cpp EventLogging.cpp FabricProvisioningServer.cpp \
-	GeneralUtils.cpp Globals.cpp NetworkTelemetryManager.cpp \
-	PersistedStorage.cpp ServiceDirectoryManager.cpp \
-	ServiceProvisioningServer.cpp ServiceTunnelAgent.cpp \
-	SystemEventSupport.cpp SystemTimerSupport.cpp \
+	CertificateProvisioningClient.cpp DeviceControlServer.cpp \
+	DeviceDescriptionServer.cpp DeviceIdentityTraitDataSource.cpp \
+	DeviceNetworkInfo.cpp EchoServer.cpp EventLogging.cpp \
+	FabricProvisioningServer.cpp GeneralUtils.cpp Globals.cpp \
+	NetworkTelemetryManager.cpp PersistedStorage.cpp \
+	ServiceDirectoryManager.cpp ServiceProvisioningServer.cpp \
+	ServiceTunnelAgent.cpp SystemEventSupport.cpp SystemTimerSupport.cpp \
 	TestDeviceIds.cpp TimeSyncManager.cpp TraitManager.cpp \
 	trait-support/nest/trait/firmware/SoftwareUpdateTrait.cpp \
 	trait-support/nest/trait/network/TelemetryNetworkTrait.cpp \
@@ -280,6 +280,7 @@
 @CONFIG_DEVICE_LAYER_TRUE@@WEAVE_DEVICE_LAYER_TARGET_NRF5_TRUE@	LwIP/libDeviceLayer_a-WarmSupport.$(OBJEXT)
 @CONFIG_DEVICE_LAYER_TRUE@am_libDeviceLayer_a_OBJECTS =  \
 @CONFIG_DEVICE_LAYER_TRUE@	libDeviceLayer_a-CASEAuth.$(OBJEXT) \
+@CONFIG_DEVICE_LAYER_TRUE@	libDeviceLayer_a-CertificateProvisioningClient.$(OBJEXT) \
 @CONFIG_DEVICE_LAYER_TRUE@	libDeviceLayer_a-DeviceControlServer.$(OBJEXT) \
 @CONFIG_DEVICE_LAYER_TRUE@	libDeviceLayer_a-DeviceDescriptionServer.$(OBJEXT) \
 @CONFIG_DEVICE_LAYER_TRUE@	libDeviceLayer_a-DeviceIdentityTraitDataSource.$(OBJEXT) \
@@ -679,6 +680,7 @@
     include/Weave/DeviceLayer/WeaveDeviceEvent.h \
     include/Weave/DeviceLayer/WeaveDeviceLayer.h \
     include/Weave/DeviceLayer/internal/BLEManager.h \
+    include/Weave/DeviceLayer/internal/CertificateProvisioningClient.h \
     include/Weave/DeviceLayer/internal/DeviceControlServer.h \
     include/Weave/DeviceLayer/internal/DeviceDescriptionServer.h \
     include/Weave/DeviceLayer/internal/DeviceIdentityTraitDataSource.h \
@@ -720,6 +722,7 @@
 @CONFIG_DEVICE_LAYER_TRUE@    $(NULL)
 
 @CONFIG_DEVICE_LAYER_TRUE@libDeviceLayer_a_SOURCES = CASEAuth.cpp \
+@CONFIG_DEVICE_LAYER_TRUE@	CertificateProvisioningClient.cpp \
 @CONFIG_DEVICE_LAYER_TRUE@	DeviceControlServer.cpp \
 @CONFIG_DEVICE_LAYER_TRUE@	DeviceDescriptionServer.cpp \
 @CONFIG_DEVICE_LAYER_TRUE@	DeviceIdentityTraitDataSource.cpp \
@@ -973,6 +976,7 @@
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libDeviceLayer_a-CASEAuth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libDeviceLayer_a-CertificateProvisioningClient.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libDeviceLayer_a-DeviceControlServer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libDeviceLayer_a-DeviceDescriptionServer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libDeviceLayer_a-DeviceIdentityTraitDataSource.Po@am__quote@
@@ -1067,6 +1071,20 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libDeviceLayer_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libDeviceLayer_a-CASEAuth.obj `if test -f 'CASEAuth.cpp'; then $(CYGPATH_W) 'CASEAuth.cpp'; else $(CYGPATH_W) '$(srcdir)/CASEAuth.cpp'; fi`
 
+libDeviceLayer_a-CertificateProvisioningClient.o: CertificateProvisioningClient.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libDeviceLayer_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libDeviceLayer_a-CertificateProvisioningClient.o -MD -MP -MF $(DEPDIR)/libDeviceLayer_a-CertificateProvisioningClient.Tpo -c -o libDeviceLayer_a-CertificateProvisioningClient.o `test -f 'CertificateProvisioningClient.cpp' || echo '$(srcdir)/'`CertificateProvisioningClient.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libDeviceLayer_a-CertificateProvisioningClient.Tpo $(DEPDIR)/libDeviceLayer_a-CertificateProvisioningClient.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='CertificateProvisioningClient.cpp' object='libDeviceLayer_a-CertificateProvisioningClient.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libDeviceLayer_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libDeviceLayer_a-CertificateProvisioningClient.o `test -f 'CertificateProvisioningClient.cpp' || echo '$(srcdir)/'`CertificateProvisioningClient.cpp
+
+libDeviceLayer_a-CertificateProvisioningClient.obj: CertificateProvisioningClient.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libDeviceLayer_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libDeviceLayer_a-CertificateProvisioningClient.obj -MD -MP -MF $(DEPDIR)/libDeviceLayer_a-CertificateProvisioningClient.Tpo -c -o libDeviceLayer_a-CertificateProvisioningClient.obj `if test -f 'CertificateProvisioningClient.cpp'; then $(CYGPATH_W) 'CertificateProvisioningClient.cpp'; else $(CYGPATH_W) '$(srcdir)/CertificateProvisioningClient.cpp'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libDeviceLayer_a-CertificateProvisioningClient.Tpo $(DEPDIR)/libDeviceLayer_a-CertificateProvisioningClient.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='CertificateProvisioningClient.cpp' object='libDeviceLayer_a-CertificateProvisioningClient.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libDeviceLayer_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libDeviceLayer_a-CertificateProvisioningClient.obj `if test -f 'CertificateProvisioningClient.cpp'; then $(CYGPATH_W) 'CertificateProvisioningClient.cpp'; else $(CYGPATH_W) '$(srcdir)/CertificateProvisioningClient.cpp'; fi`
+
 libDeviceLayer_a-DeviceControlServer.o: DeviceControlServer.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libDeviceLayer_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libDeviceLayer_a-DeviceControlServer.o -MD -MP -MF $(DEPDIR)/libDeviceLayer_a-DeviceControlServer.Tpo -c -o libDeviceLayer_a-DeviceControlServer.o `test -f 'DeviceControlServer.cpp' || echo '$(srcdir)/'`DeviceControlServer.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libDeviceLayer_a-DeviceControlServer.Tpo $(DEPDIR)/libDeviceLayer_a-DeviceControlServer.Po
diff --git a/src/adaptations/device-layer/ServiceProvisioningServer.cpp b/src/adaptations/device-layer/ServiceProvisioningServer.cpp
index c0de161..95d2187 100644
--- a/src/adaptations/device-layer/ServiceProvisioningServer.cpp
+++ b/src/adaptations/device-layer/ServiceProvisioningServer.cpp
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -22,14 +23,19 @@
 
 using namespace ::nl;
 using namespace ::nl::Weave;
+using namespace ::nl::Weave::TLV;
 using namespace ::nl::Weave::Profiles;
 using namespace ::nl::Weave::Profiles::ServiceProvisioning;
+using namespace ::nl::Weave::Profiles::Security;
 
 namespace nl {
 namespace Weave {
 namespace DeviceLayer {
 namespace Internal {
 
+using ::nl::Weave::Platform::Security::MemoryAlloc;
+using ::nl::Weave::Platform::Security::MemoryFree;
+
 ServiceProvisioningServer ServiceProvisioningServer::sInstance;
 
 WEAVE_ERROR ServiceProvisioningServer::Init(void)
@@ -91,7 +97,12 @@
         PlatformMgr().PostEvent(&event);
     }
 
-#if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+
+    // Initiate the process of sending a GetCertificateRequest to the Certificate Provisioning service.
+    PlatformMgr().ScheduleWork(AsyncStartCertificateProvisioning);
+
+#elif !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
 
     // Initiate the process of sending a PairDeviceToAccount request to the Service Provisioning service.
     PlatformMgr().ScheduleWork(AsyncStartPairDeviceToAccount);
@@ -304,6 +315,15 @@
         mProvServiceBinding = NULL;
     }
 
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+    // If necessary, free memory allocated for the certificate provisioning engine.
+    if (mCertProvClient != NULL)
+    {
+        MemoryFree(mCertProvClient);
+        mCertProvClient = NULL;
+    }
+#endif // WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+
     // Return immediately if for some reason the client's RegisterServicePairAccount request
     // is no longer pending.  Note that, even if the PairDeviceToAccount request succeeded,
     // the device must clear the persisted service configuration in this case because it has
@@ -374,6 +394,33 @@
     }
 }
 
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+void ServiceProvisioningServer::AsyncStartCertificateProvisioning(intptr_t arg)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    // Allocate temporary memory to hold the certificate provisioning client.
+    sInstance.mCertProvClient = static_cast<CertificateProvisioningClient *>(MemoryAlloc(sizeof(CertificateProvisioningClient)));
+    VerifyOrExit(sInstance.mCertProvClient != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    // Initialize certificate provisioning client.
+    err = sInstance.mCertProvClient->Init(WeaveCertProvEngine::kReqType_GetInitialOpDeviceCert, sInstance.EncodeGetCertificateRequestAuthInfo);
+    SuccessOrExit(err);
+
+    // Start certificate provisioning.
+    sInstance.mCertProvClient->StartCertificateProvisioning();
+
+exit:
+    if (err != WEAVE_NO_ERROR)
+    {
+        MemoryFree(sInstance.mCertProvClient);
+        sInstance.mCertProvClient = NULL;
+
+        sInstance.HandlePairDeviceToAccountResult(err, kWeaveProfile_Common, Profiles::Common::kStatus_InternalServerProblem);
+    }
+}
+#endif // WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+
 void ServiceProvisioningServer::AsyncStartPairDeviceToAccount(intptr_t arg)
 {
     sInstance.StartPairDeviceToAccount();
@@ -415,6 +462,23 @@
     }
 }
 
+WEAVE_ERROR ServiceProvisioningServer::EncodeGetCertificateRequestAuthInfo(TLVWriter & writer)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    const RegisterServicePairAccountMessage & regServiceMsg = sInstance.mCurClientOpMsg.RegisterServicePairAccount;
+
+    // Encode pairing token.
+    err = writer.PutBytes(ContextTag(kTag_GetCertReqMsg_Authorize_PairingToken), regServiceMsg.PairingToken, regServiceMsg.PairingTokenLen);
+    SuccessOrExit(err);
+
+    // Encode pairing initialization data.
+    err = writer.PutBytes(ContextTag(kTag_GetCertReqMsg_Authorize_PairingInitData), regServiceMsg.PairingInitData, regServiceMsg.PairingInitDataLen);
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
 #else // !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
 
 void ServiceProvisioningServer::HandlePairDeviceToAccountResult(WEAVE_ERROR err, uint32_t statusReportProfileId, uint16_t statusReportStatusCode)
diff --git a/src/adaptations/device-layer/TestDeviceIds.cpp b/src/adaptations/device-layer/TestDeviceIds.cpp
index b0d828d..2b6bae0 100644
--- a/src/adaptations/device-layer/TestDeviceIds.cpp
+++ b/src/adaptations/device-layer/TestDeviceIds.cpp
@@ -8805,7 +8805,28 @@
 
 #if WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
 
+const uint8_t TestDeviceICACert[] =
+{
+    0xD5, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x30, 0x01, 0x08, 0x0C, 0x39, 0x7C, 0x12, 0xA3, 0x49, 
+    0xC7, 0x28, 0x24, 0x02, 0x05, 0x37, 0x03, 0x27, 0x13, 0x02, 0x00, 0x00, 0xEE, 0xEE, 0x30, 0xB4, 
+    0x18, 0x18, 0x26, 0x04, 0x80, 0x41, 0x1B, 0x23, 0x26, 0x05, 0x7F, 0xFF, 0xFF, 0x52, 0x37, 0x06, 
+    0x27, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0xB4, 0x18, 0x18, 0x24, 0x07, 0x02, 0x26, 0x08, 
+    0x25, 0x00, 0x5A, 0x23, 0x30, 0x0A, 0x39, 0x04, 0xB9, 0x1D, 0xF2, 0x01, 0x7B, 0xA9, 0x4B, 0xB3, 
+    0x5D, 0x81, 0x70, 0x80, 0x9E, 0xE3, 0xA9, 0x86, 0xC4, 0x47, 0x23, 0xD7, 0xDC, 0xB0, 0x1E, 0x68, 
+    0xC4, 0xB5, 0x6D, 0x0B, 0xF1, 0xEA, 0x10, 0xC5, 0x53, 0x55, 0x43, 0x52, 0x66, 0x6A, 0xF9, 0xB2, 
+    0x66, 0x41, 0xFC, 0x2F, 0xDE, 0x83, 0xDE, 0x4B, 0xD2, 0xF1, 0xBB, 0x81, 0x02, 0x09, 0x16, 0x74, 
+    0x35, 0x83, 0x29, 0x01, 0x18, 0x35, 0x82, 0x29, 0x01, 0x24, 0x02, 0x05, 0x18, 0x35, 0x84, 0x29, 
+    0x01, 0x36, 0x02, 0x04, 0x02, 0x04, 0x01, 0x18, 0x18, 0x35, 0x81, 0x30, 0x02, 0x08, 0x43, 0x4E, 
+    0x72, 0x88, 0x39, 0xDA, 0x6C, 0xC7, 0x18, 0x35, 0x80, 0x30, 0x02, 0x08, 0x44, 0xE3, 0x40, 0x38, 
+    0xA9, 0xD4, 0xB5, 0xA7, 0x18, 0x35, 0x0C, 0x30, 0x01, 0x19, 0x00, 0xEA, 0x20, 0x41, 0xC9, 0x4F, 
+    0xDE, 0xBE, 0xA6, 0x8B, 0x9D, 0x43, 0xD8, 0x84, 0x4D, 0x06, 0xD2, 0x2F, 0xD2, 0x49, 0x9E, 0x46, 
+    0x49, 0x1D, 0x1F, 0x30, 0x02, 0x19, 0x00, 0xF2, 0xB2, 0x39, 0xC6, 0xFB, 0x13, 0x92, 0x3C, 0x7A, 
+    0xAB, 0x79, 0x04, 0x67, 0x78, 0xCB, 0xFE, 0xE1, 0x80, 0x26, 0x4A, 0x35, 0xCF, 0x02, 0x1C, 0x18, 
+    0x18,
+};
+
 const uint16_t TestDeviceCertLength = sizeof(TestDeviceCert);
+const uint16_t TestDeviceICACertLength = sizeof(TestDeviceICACert);
 const uint16_t TestDevicePrivateKeyLength = sizeof(TestDevicePrivateKey);
 
 #endif // WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/ConfigurationManager.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/ConfigurationManager.h
index e23ba39..4fd6bcd 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/ConfigurationManager.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/ConfigurationManager.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -77,7 +78,12 @@
             uint8_t & hour, uint8_t & minute, uint8_t & second);
     WEAVE_ERROR GetDeviceId(uint64_t & deviceId);
     WEAVE_ERROR GetDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen);
+    WEAVE_ERROR GetDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen);
     WEAVE_ERROR GetDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen);
+    WEAVE_ERROR GetManufAttestDeviceId(uint64_t & deviceId);
+    WEAVE_ERROR GetManufAttestDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen);
+    WEAVE_ERROR GetManufAttestDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen);
+    WEAVE_ERROR GetManufAttestDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen);
     WEAVE_ERROR GetPairingCode(char * buf, size_t bufSize, size_t & pairingCodeLen);
     WEAVE_ERROR GetServiceId(uint64_t & serviceId);
     WEAVE_ERROR GetFabricId(uint64_t & fabricId);
@@ -92,7 +98,14 @@
     WEAVE_ERROR StoreProductRevision(uint16_t productRev);
     WEAVE_ERROR StoreFabricId(uint64_t fabricId);
     WEAVE_ERROR StoreDeviceCertificate(const uint8_t * cert, size_t certLen);
+    WEAVE_ERROR StoreDeviceICACerts(const uint8_t * certs, size_t certsLen);
     WEAVE_ERROR StoreDevicePrivateKey(const uint8_t * key, size_t keyLen);
+    WEAVE_ERROR StoreDeviceCredentials(uint64_t deviceId, const uint8_t * cert, size_t certLen, const uint8_t * key, size_t keyLen);
+    WEAVE_ERROR ClearDeviceCredentials(void);
+    WEAVE_ERROR StoreManufAttestDeviceId(uint64_t deviceId);
+    WEAVE_ERROR StoreManufAttestDeviceCertificate(const uint8_t * cert, size_t certLen);
+    WEAVE_ERROR StoreManufAttestDeviceICACerts(const uint8_t * certs, size_t certsLen);
+    WEAVE_ERROR StoreManufAttestDevicePrivateKey(const uint8_t * key, size_t keyLen);
     WEAVE_ERROR StorePairingCode(const char * pairingCode, size_t pairingCodeLen);
     WEAVE_ERROR StoreServiceProvisioningData(uint64_t serviceId, const uint8_t * serviceConfig, size_t serviceConfigLen, const char * accountId, size_t accountIdLen);
     WEAVE_ERROR ClearServiceProvisioningData();
@@ -111,6 +124,11 @@
     bool IsPairedToAccount();
     bool IsMemberOfFabric();
     bool IsFullyProvisioned();
+    bool DeviceCredentialsProvisioned();
+    bool DeviceICACertsProvisioned();
+    bool ManufAttestDeviceICACertsProvisioned();
+    bool UseManufAttestCredentialsAsOperational();
+    void UseManufAttestCredentialsAsOperational(bool val);
 
     void InitiateFactoryReset();
 
@@ -249,11 +267,36 @@
     return static_cast<ImplClass*>(this)->_GetDeviceCertificate(buf, bufSize, certLen);
 }
 
+inline WEAVE_ERROR ConfigurationManager::GetDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen)
+{
+    return static_cast<ImplClass*>(this)->_GetDeviceICACerts(buf, bufSize, certsLen);
+}
+
 inline WEAVE_ERROR ConfigurationManager::GetDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen)
 {
     return static_cast<ImplClass*>(this)->_GetDevicePrivateKey(buf, bufSize, keyLen);
 }
 
+inline WEAVE_ERROR ConfigurationManager::GetManufAttestDeviceId(uint64_t & deviceId)
+{
+    return static_cast<ImplClass*>(this)->_GetManufAttestDeviceId(deviceId);
+}
+
+inline WEAVE_ERROR ConfigurationManager::GetManufAttestDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen)
+{
+    return static_cast<ImplClass*>(this)->_GetManufAttestDeviceCertificate(buf, bufSize, certLen);
+}
+
+inline WEAVE_ERROR ConfigurationManager::GetManufAttestDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen)
+{
+    return static_cast<ImplClass*>(this)->_GetManufAttestDeviceICACerts(buf, bufSize, certsLen);
+}
+
+inline WEAVE_ERROR ConfigurationManager::GetManufAttestDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen)
+{
+    return static_cast<ImplClass*>(this)->_GetManufAttestDevicePrivateKey(buf, bufSize, keyLen);
+}
+
 inline WEAVE_ERROR ConfigurationManager::GetPairingCode(char * buf, size_t bufSize, size_t & pairingCodeLen)
 {
     return static_cast<ImplClass*>(this)->_GetPairingCode(buf, bufSize, pairingCodeLen);
@@ -319,11 +362,46 @@
     return static_cast<ImplClass*>(this)->_StoreDeviceCertificate(cert, certLen);
 }
 
+inline WEAVE_ERROR ConfigurationManager::StoreDeviceICACerts(const uint8_t * certs, size_t certsLen)
+{
+    return static_cast<ImplClass*>(this)->_StoreDeviceICACerts(certs, certsLen);
+}
+
 inline WEAVE_ERROR ConfigurationManager::StoreDevicePrivateKey(const uint8_t * key, size_t keyLen)
 {
     return static_cast<ImplClass*>(this)->_StoreDevicePrivateKey(key, keyLen);
 }
 
+inline WEAVE_ERROR ConfigurationManager::StoreDeviceCredentials(uint64_t deviceId, const uint8_t * cert, size_t certLen, const uint8_t * key, size_t keyLen)
+{
+    return static_cast<ImplClass*>(this)->_StoreDeviceCredentials(deviceId, cert, certLen, key, keyLen);
+}
+
+inline WEAVE_ERROR ConfigurationManager::ClearDeviceCredentials(void)
+{
+    return static_cast<ImplClass*>(this)->_ClearDeviceCredentials();
+}
+
+inline WEAVE_ERROR ConfigurationManager::StoreManufAttestDeviceId(uint64_t deviceId)
+{
+    return static_cast<ImplClass*>(this)->_StoreManufAttestDeviceId(deviceId);
+}
+
+inline WEAVE_ERROR ConfigurationManager::StoreManufAttestDeviceCertificate(const uint8_t * cert, size_t certLen)
+{
+    return static_cast<ImplClass*>(this)->_StoreManufAttestDeviceCertificate(cert, certLen);
+}
+
+inline WEAVE_ERROR ConfigurationManager::StoreManufAttestDeviceICACerts(const uint8_t * certs, size_t certsLen)
+{
+    return static_cast<ImplClass*>(this)->_StoreManufAttestDeviceICACerts(certs, certsLen);
+}
+
+inline WEAVE_ERROR ConfigurationManager::StoreManufAttestDevicePrivateKey(const uint8_t * key, size_t keyLen)
+{
+    return static_cast<ImplClass*>(this)->_StoreManufAttestDevicePrivateKey(key, keyLen);
+}
+
 inline WEAVE_ERROR ConfigurationManager::StorePairingCode(const char * pairingCode, size_t pairingCodeLen)
 {
     return static_cast<ImplClass*>(this)->_StorePairingCode(pairingCode, pairingCodeLen);
@@ -404,6 +482,31 @@
     return static_cast<ImplClass*>(this)->_IsFullyProvisioned();
 }
 
+inline bool ConfigurationManager::DeviceCredentialsProvisioned()
+{
+    return static_cast<ImplClass*>(this)->_DeviceCredentialsProvisioned();
+}
+
+inline bool ConfigurationManager::DeviceICACertsProvisioned()
+{
+    return static_cast<ImplClass*>(this)->_DeviceICACertsProvisioned();
+}
+
+inline bool ConfigurationManager::ManufAttestDeviceICACertsProvisioned()
+{
+    return static_cast<ImplClass*>(this)->_ManufAttestDeviceICACertsProvisioned();
+}
+
+inline bool ConfigurationManager::UseManufAttestCredentialsAsOperational()
+{
+    return static_cast<ImplClass*>(this)->_UseManufAttestCredentialsAsOperational();
+}
+
+inline void ConfigurationManager::UseManufAttestCredentialsAsOperational(bool val)
+{
+    static_cast<ImplClass*>(this)->_UseManufAttestCredentialsAsOperational(val);
+}
+
 inline void ConfigurationManager::InitiateFactoryReset()
 {
     static_cast<ImplClass*>(this)->_InitiateFactoryReset();
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/ESP32/ESP32Config.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/ESP32/ESP32Config.h
index 56d8b32..a108404 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/ESP32/ESP32Config.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/ESP32/ESP32Config.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -53,9 +54,10 @@
 
     // Key definitions for well-known keys.
     static const Key kConfigKey_SerialNum;
-    static const Key kConfigKey_DeviceId;
-    static const Key kConfigKey_DeviceCert;
-    static const Key kConfigKey_DevicePrivateKey;
+    static const Key kConfigKey_ManufAttestDeviceId;
+    static const Key kConfigKey_ManufAttestDeviceCert;
+    static const Key kConfigKey_ManufAttestDeviceICACerts;
+    static const Key kConfigKey_ManufAttestDevicePrivateKey;
     static const Key kConfigKey_ProductRevision;
     static const Key kConfigKey_ManufacturingDate;
     static const Key kConfigKey_PairingCode;
@@ -68,6 +70,10 @@
     static const Key kConfigKey_LastUsedEpochKeyId;
     static const Key kConfigKey_FailSafeArmed;
     static const Key kConfigKey_WiFiStationSecType;
+    static const Key kConfigKey_OperationalDeviceId;
+    static const Key kConfigKey_OperationalDeviceCert;
+    static const Key kConfigKey_OperationalDeviceICACerts;
+    static const Key kConfigKey_OperationalDevicePrivateKey;
 
     static const char kGroupKeyNamePrefix[];
 
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/PlatformManager.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/PlatformManager.h
index 37d5fd4..ca3eb53 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/PlatformManager.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/PlatformManager.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -36,6 +37,7 @@
 class TraitManager;
 class TimeSyncManager;
 namespace Internal {
+class CertificateProvisioningClient;
 class FabricProvisioningServer;
 class ServiceProvisioningServer;
 class BLEManagerImpl;
@@ -81,6 +83,7 @@
     friend class ConfigurationManagerImpl;
     friend class TraitManager;
     friend class TimeSyncManager;
+    friend class Internal::CertificateProvisioningClient;
     friend class Internal::FabricProvisioningServer;
     friend class Internal::ServiceProvisioningServer;
     friend class Internal::BLEManagerImpl;
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceConfig.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceConfig.h
index 85dde96..076ea1f 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceConfig.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceConfig.h
@@ -480,6 +480,56 @@
 #define WEAVE_DEVICE_CONFIG_SERVICE_PROVISIONING_REQUEST_TIMEOUT 10000
 #endif
 
+// -------------------- Operational Device Credentials Configuration --------------------
+
+/**
+ * WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+ *
+ * Enable the ephemeral operational device credentials feature.
+ *
+ * When enabled device creates and uses its ephemeral operational credentials:
+ *   - operational device id
+ *   - operational device certificate
+ *   - operational device private key
+ * Device uses these credentials to authenticate and communicate to other Weave nodes.
+ */
+#ifndef WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+#define WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS 1
+#endif
+
+/**
+ * WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_ENDPOINT_ID
+ *
+ * Specifies the service endpoint id of the Weave Certificate Provisioning service.  When a device
+ * undergoes certificate provisioning, this is the endpoint to which it will send its Get Certificate
+ * request.
+ */
+#ifndef WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_ENDPOINT_ID
+#define WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_ENDPOINT_ID 0x18B4300200000016ULL
+#endif
+
+/**
+ * WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_CONNECTIVITY_TIMEOUT
+ *
+ * The maximum amount of time (in milliseconds) to wait for service connectivity during the device
+ * certificate provisioning step.  More specifically, this is the maximum amount of time the device will
+ * wait for connectivity to be established with the service at the point where the device waiting
+ * to send a Get Certificate request to the Certificate Provisioning service.
+ */
+#ifndef WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_CONNECTIVITY_TIMEOUT
+#define WEAVE_DEVICE_CONFIG_CERTIFICATE_PROVISIONING_CONNECTIVITY_TIMEOUT 10000
+#endif
+
+/**
+ * WEAVE_DEVICE_CONFIG_GET_CERTIFICATE_REQUEST_TIMEOUT
+ *
+ * Specifies the maximum amount of time (in milliseconds) to wait for a response from the Certificate
+ * Provisioning service.
+ */
+#ifndef WEAVE_DEVICE_CONFIG_GET_CERTIFICATE_REQUEST_TIMEOUT
+#define WEAVE_DEVICE_CONFIG_GET_CERTIFICATE_REQUEST_TIMEOUT 10000
+#endif
+
 // -------------------- Thread Configuration --------------------
 
 /**
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceEvent.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceEvent.h
index 194204c..91ce198 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceEvent.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceEvent.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -196,6 +197,13 @@
      * Signals that the state of WoBLE advertising has changed.
      */
     kWoBLEAdvertisingChange,
+
+    /**
+     * Device Credentials Change
+     *
+     * Signals that the device's credentials has changed
+     */
+    kDeviceCredentialsChange,
 };
 
 /**
@@ -397,6 +405,10 @@
         {
             ActivityChange Result;
         } WoBLEAdvertisingChange;
+        struct
+        {
+            bool AreCredentialsProvisioned;
+        } DeviceCredentialsChange;
     };
 
     void Clear() { memset(this, 0, sizeof(*this)); }
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/CertificateProvisioningClient.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/CertificateProvisioningClient.h
new file mode 100644
index 0000000..c413e3b
--- /dev/null
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/CertificateProvisioningClient.h
@@ -0,0 +1,114 @@
+/*
+ *
+ *    Copyright (c) 2019 Google LLC.
+ *    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
+ *          Defines the Device Layer CertificateProvisioningClient object.
+ */
+
+#ifndef CERTIFICATE_PROVISIONING_CLIENT_H
+#define CERTIFICATE_PROVISIONING_CLIENT_H
+
+#include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>
+#include <Weave/Profiles/security/WeaveCertProvisioning.h>
+
+namespace nl {
+namespace Weave {
+namespace DeviceLayer {
+namespace Internal {
+
+using nl::Weave::Profiles::Security::CertProvisioning::WeaveCertProvEngine;
+
+extern WEAVE_ERROR GenerateAndStoreOperationalDeviceCredentials(uint64_t deviceId = kNodeIdNotSpecified);
+
+/**
+ * Implements the Weave Certificate Provisioning profile for a Weave device.
+ */
+class CertificateProvisioningClient final
+    : public ::nl::Weave::Profiles::Security::CertProvisioning::WeaveNodeOpAuthDelegate,
+      public ::nl::Weave::Profiles::Security::CertProvisioning::WeaveNodeManufAttestDelegate
+{
+
+public:
+
+    /**
+     *  This function is the callback that is invoked by Certificate Provisioning Client to add
+     *  authorization info to the GetCertificateRequest message in a TLV form to the supplied TLV writer.
+     *
+     *  @param[in]  writer      A reference to a TLV writer to write request authorization data.
+     */
+    typedef WEAVE_ERROR (* EncodeReqAuthInfoFunct)(TLVWriter & writer);
+
+    // ===== Members for internal use by other Device Layer components.
+
+    WEAVE_ERROR Init(uint8_t reqType);
+    WEAVE_ERROR Init(uint8_t reqType, EncodeReqAuthInfoFunct encodeReqAuthInfo);
+    void OnPlatformEvent(const WeaveDeviceEvent * event);
+
+    // ===== Methods that implement the WeaveNodeOpAuthDelegate interface
+
+    WEAVE_ERROR EncodeOpCert(TLVWriter & writer, uint64_t tag) __OVERRIDE;
+    WEAVE_ERROR EncodeOpRelatedCerts(TLVWriter & writer, uint64_t tag) __OVERRIDE;
+    WEAVE_ERROR GenerateAndEncodeOpSig(const uint8_t * hash, uint8_t hashLen, TLVWriter & writer, uint64_t tag) __OVERRIDE;
+
+    // ===== Methods that implement the WeaveNodeManufAttestDelegate interface
+
+    WEAVE_ERROR EncodeMAInfo(TLVWriter & writer) __OVERRIDE;
+    WEAVE_ERROR GenerateAndEncodeMASig(const uint8_t * data, uint16_t dataLen, TLVWriter & writer) __OVERRIDE;
+
+    // ===== Members that override virtual methods on ServiceProvisioningDelegate
+
+    void StartCertificateProvisioning(void);
+    void HandleCertificateProvisioningResult(WEAVE_ERROR localErr, uint32_t serverStatusProfileId, uint16_t serverStatusCode);
+
+private:
+
+    // ===== Members for internal use by this class only.
+
+    WeaveCertProvEngine mCertProvEngine;
+    ::nl::Weave::Binding * mBinding;
+    uint8_t mReqType;
+    bool mDoManufAttest;
+    EncodeReqAuthInfoFunct mEncodeReqAuthInfo;
+    bool mWaitingForServiceConnectivity;
+
+    void SendGetCertificateRequest(void);
+
+    static void HandleServiceConnectivityTimeout(::nl::Weave::System::Layer * layer, void * appState, ::nl::Weave::System::Error err);
+    static void HandleCertProvBindingEvent(void * appState, nl::Weave::Binding::EventType eventType,
+            const nl::Weave::Binding::InEventParam & inParam, nl::Weave::Binding::OutEventParam & outParam);
+    static void CertProvClientEventHandler(void * appState, WeaveCertProvEngine::EventType eventType, const WeaveCertProvEngine::InEventParam & inParam, WeaveCertProvEngine::OutEventParam & outParam);
+
+protected:
+
+    // Construction/destruction limited to subclasses.
+    CertificateProvisioningClient() = default;
+    ~CertificateProvisioningClient() = default;
+
+    // No copy, move or assignment.
+    CertificateProvisioningClient(const CertificateProvisioningClient &) = delete;
+    CertificateProvisioningClient(const CertificateProvisioningClient &&) = delete;
+    CertificateProvisioningClient & operator=(const CertificateProvisioningClient &) = delete;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace Weave
+} // namespace nl
+
+#endif // CERTIFICATE_PROVISIONING_CLIENT_H
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.h
index 8cb9a15..538fa38 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.h
@@ -97,7 +97,8 @@
     kTag_DevicePrivateKey       = 3,    // [ byte string ] Manufacturer-assigned device key
     kTag_PairingCode            = 4,    // [ utf-8 string ] Pairing code
     kTag_ProductRev             = 5,    // [ uint, 16-bit max ] Product revision
-    kTag_MfgDate                = 6     // [ utf-8 string ] Manufacturing date
+    kTag_MfgDate                = 6,    // [ utf-8 string ] Manufacturing date
+    kTag_DeviceICACerts         = 7,    // [ byte string ] Manufacturer-assigned device intermediate CA certificates
 };
 
 /**
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.ipp b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.ipp
index 6a83547..6a79364 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.ipp
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/FactoryProvisioning.ipp
@@ -176,7 +176,7 @@
         uint64_t deviceId;
         err = reader.Get(deviceId);
         SuccessOrExit(err);
-        err = ConfigurationMgr().StoreDeviceId(deviceId);
+        err = ConfigurationMgr().StoreManufAttestDeviceId(deviceId);
         SuccessOrExit(err);
         break;
     }
@@ -186,7 +186,17 @@
         const uint8_t * cert;
         err = reader.GetDataPtr(cert);
         SuccessOrExit(err);
-        err = ConfigurationMgr().StoreDeviceCertificate(cert, reader.GetLength());
+        err = ConfigurationMgr().StoreManufAttestDeviceCertificate(cert, reader.GetLength());
+        SuccessOrExit(err);
+        break;
+    }
+
+    case FactoryProvisioningData::kTag_DeviceICACerts:
+    {
+        const uint8_t * certs;
+        err = reader.GetDataPtr(certs);
+        SuccessOrExit(err);
+        err = ConfigurationMgr().StoreManufAttestDeviceICACerts(certs, reader.GetLength());
         SuccessOrExit(err);
         break;
     }
@@ -196,7 +206,7 @@
         const uint8_t * privKey;
         err = reader.GetDataPtr(privKey);
         SuccessOrExit(err);
-        err = ConfigurationMgr().StoreDevicePrivateKey(privKey, reader.GetLength());
+        err = ConfigurationMgr().StoreManufAttestDevicePrivateKey(privKey, reader.GetLength());
         SuccessOrExit(err);
         break;
     }
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.h
index 227c538..ed74c32 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -69,8 +70,20 @@
     WEAVE_ERROR _StoreManufacturingDate(const char * mfgDate, size_t mfgDateLen);
     WEAVE_ERROR _GetDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen);
     WEAVE_ERROR _StoreDeviceCertificate(const uint8_t * cert, size_t certLen);
+    WEAVE_ERROR _GetDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen);
+    WEAVE_ERROR _StoreDeviceICACerts(const uint8_t * certs, size_t certsLen);
     WEAVE_ERROR _GetDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen);
     WEAVE_ERROR _StoreDevicePrivateKey(const uint8_t * key, size_t keyLen);
+    WEAVE_ERROR _StoreDeviceCredentials(uint64_t deviceId, const uint8_t * cert, size_t certLen, const uint8_t * key, size_t keyLen);
+    WEAVE_ERROR _ClearDeviceCredentials(void);
+    WEAVE_ERROR _GetManufAttestDeviceId(uint64_t & deviceId);
+    WEAVE_ERROR _StoreManufAttestDeviceId(uint64_t deviceId);
+    WEAVE_ERROR _GetManufAttestDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen);
+    WEAVE_ERROR _StoreManufAttestDeviceCertificate(const uint8_t * cert, size_t certLen);
+    WEAVE_ERROR _GetManufAttestDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen);
+    WEAVE_ERROR _StoreManufAttestDeviceICACerts(const uint8_t * certs, size_t certsLen);
+    WEAVE_ERROR _GetManufAttestDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen);
+    WEAVE_ERROR _StoreManufAttestDevicePrivateKey(const uint8_t * key, size_t keyLen);
     WEAVE_ERROR _GetPairingCode(char * buf, size_t bufSize, size_t & pairingCodeLen);
     WEAVE_ERROR _StorePairingCode(const char * pairingCode, size_t pairingCodeLen);
     WEAVE_ERROR _GetFabricId(uint64_t & fabricId);
@@ -95,14 +108,21 @@
     bool _IsPairedToAccount();
     bool _IsFullyProvisioned();
     WEAVE_ERROR _ComputeProvisioningHash(uint8_t * hashBuf, size_t hashBufSize);
+    bool _DeviceCredentialsProvisioned();
+    bool _DeviceICACertsProvisioned();
+    bool _ManufAttestDeviceICACertsProvisioned();
+    bool _UseManufAttestCredentialsAsOperational();
+    void _UseManufAttestCredentialsAsOperational(bool val);
 
 protected:
 
     enum
     {
-        kFlag_IsServiceProvisioned      = 0x01,
-        kFlag_IsMemberOfFabric          = 0x02,
-        kFlag_IsPairedToAccount         = 0x04,
+        kFlag_IsServiceProvisioned                   = 0x01,
+        kFlag_IsMemberOfFabric                       = 0x02,
+        kFlag_IsPairedToAccount                      = 0x04,
+        kFlag_DeviceCredentialsProvisioned           = 0x08,
+        kFlag_UseManufAttestCredentialsAsOperational = 0x10,
     };
 
     uint8_t mFlags;
@@ -143,4 +163,3 @@
 } // namespace nl
 
 #endif // GENERIC_CONFIGURATION_MANAGER_IMPL_H
-
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.ipp b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.ipp
index d5e91d2..a1d6385 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.ipp
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericConfigurationManagerImpl.ipp
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -52,6 +53,7 @@
     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_DeviceCredentialsProvisioned, Impl()->ConfigValueExists(ImplClass::kConfigKey_OperationalDeviceCert));
 
     return WEAVE_NO_ERROR;
 }
@@ -154,11 +156,11 @@
 }
 
 template<class ImplClass>
-WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetDeviceId(uint64_t & deviceId)
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetManufAttestDeviceId(uint64_t & deviceId)
 {
     WEAVE_ERROR err;
 
-    err = Impl()->ReadConfigValue(ImplClass::kConfigKey_DeviceId, deviceId);
+    err = Impl()->ReadConfigValue(ImplClass::kConfigKey_ManufAttestDeviceId, deviceId);
 
 #if WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
     if (err == WEAVE_DEVICE_ERROR_CONFIG_NOT_FOUND)
@@ -172,9 +174,9 @@
 }
 
 template<class ImplClass>
-WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDeviceId(uint64_t deviceId)
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreManufAttestDeviceId(uint64_t deviceId)
 {
-    return Impl()->WriteConfigValue(ImplClass::kConfigKey_DeviceId, deviceId);
+    return Impl()->WriteConfigValue(ImplClass::kConfigKey_ManufAttestDeviceId, deviceId);
 }
 
 template<class ImplClass>
@@ -299,11 +301,11 @@
 }
 
 template<class ImplClass>
-WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen)
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetManufAttestDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen)
 {
     WEAVE_ERROR err;
 
-    err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_DeviceCert, buf, bufSize, certLen);
+    err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_ManufAttestDeviceCert, buf, bufSize, certLen);
 
 #if WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
 
@@ -326,17 +328,50 @@
 }
 
 template<class ImplClass>
-WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDeviceCertificate(const uint8_t * cert, size_t certLen)
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreManufAttestDeviceCertificate(const uint8_t * cert, size_t certLen)
 {
-    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_DeviceCert, cert, certLen);
+    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_ManufAttestDeviceCert, cert, certLen);
 }
 
 template<class ImplClass>
-WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen)
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetManufAttestDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen)
 {
     WEAVE_ERROR err;
 
-    err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_DevicePrivateKey, buf, bufSize, keyLen);
+    err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_ManufAttestDeviceICACerts, buf, bufSize, certsLen);
+
+#if WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
+
+    if (err == WEAVE_DEVICE_ERROR_CONFIG_NOT_FOUND)
+    {
+        certsLen = TestDeviceICACertLength;
+        VerifyOrExit(buf != NULL, err = WEAVE_NO_ERROR);
+        VerifyOrExit(TestDeviceICACertLength <= bufSize, err = WEAVE_ERROR_BUFFER_TOO_SMALL);
+        WeaveLogProgress(DeviceLayer, "Device certificate not found; using default");
+        memcpy(buf, TestDeviceICACert, TestDeviceICACertLength);
+        err = WEAVE_NO_ERROR;
+    }
+
+#endif // WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
+
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreManufAttestDeviceICACerts(const uint8_t * certs, size_t certsLen)
+{
+    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_ManufAttestDeviceICACerts, certs, certsLen);
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetManufAttestDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen)
+{
+    WEAVE_ERROR err;
+
+    err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_ManufAttestDevicePrivateKey, buf, bufSize, keyLen);
 
 #if WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
 
@@ -359,9 +394,169 @@
 }
 
 template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreManufAttestDevicePrivateKey(const uint8_t * key, size_t keyLen)
+{
+    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_ManufAttestDevicePrivateKey, key, keyLen);
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetDeviceId(uint64_t & deviceId)
+{
+    WEAVE_ERROR err;
+
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+    if (!_UseManufAttestCredentialsAsOperational())
+    {
+        err = Impl()->ReadConfigValue(ImplClass::kConfigKey_OperationalDeviceId, deviceId);
+    }
+    else
+#endif
+    {
+        err = Impl()->_GetManufAttestDeviceId(deviceId);
+    }
+
+    return err;
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDeviceId(uint64_t deviceId)
+{
+    return Impl()->WriteConfigValue(ImplClass::kConfigKey_OperationalDeviceId, deviceId);
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetDeviceCertificate(uint8_t * buf, size_t bufSize, size_t & certLen)
+{
+    WEAVE_ERROR err;
+
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+    if (!_UseManufAttestCredentialsAsOperational())
+    {
+        err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_OperationalDeviceCert, buf, bufSize, certLen);
+    }
+    else
+#endif
+    {
+        err = Impl()->_GetManufAttestDeviceCertificate(buf, bufSize, certLen);
+    }
+
+    return err;
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDeviceCertificate(const uint8_t * cert, size_t certLen)
+{
+    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_OperationalDeviceCert, cert, certLen);
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetDeviceICACerts(uint8_t * buf, size_t bufSize, size_t & certsLen)
+{
+    WEAVE_ERROR err;
+
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+    if (!_UseManufAttestCredentialsAsOperational())
+    {
+        err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_OperationalDeviceICACerts, buf, bufSize, certsLen);
+    }
+    else
+#endif
+    {
+        err = Impl()->_GetManufAttestDeviceICACerts(buf, bufSize, certsLen);
+    }
+
+    return err;
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDeviceICACerts(const uint8_t * certs, size_t certsLen)
+{
+    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_OperationalDeviceICACerts, certs, certsLen);
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_GetDevicePrivateKey(uint8_t * buf, size_t bufSize, size_t & keyLen)
+{
+    WEAVE_ERROR err;
+
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+    if (!_UseManufAttestCredentialsAsOperational())
+    {
+        err = Impl()->ReadConfigValueBin(ImplClass::kConfigKey_OperationalDevicePrivateKey, buf, bufSize, keyLen);
+    }
+    else
+#endif
+    {
+        err = Impl()->_GetManufAttestDevicePrivateKey(buf, bufSize, keyLen);
+    }
+
+    return err;
+}
+
+template<class ImplClass>
 WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDevicePrivateKey(const uint8_t * key, size_t keyLen)
 {
-    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_DevicePrivateKey, key, keyLen);
+    return Impl()->WriteConfigValueBin(ImplClass::kConfigKey_OperationalDevicePrivateKey, key, keyLen);
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_StoreDeviceCredentials(uint64_t deviceId, const uint8_t * cert, size_t certLen, const uint8_t * key, size_t keyLen)
+{
+    WEAVE_ERROR err;
+
+    err = Impl()->_StoreDeviceId(deviceId);
+    SuccessOrExit(err);
+
+    err = Impl()->_StoreDeviceCertificate(cert, certLen);
+    SuccessOrExit(err);
+
+    err = Impl()->_StoreDevicePrivateKey(key, keyLen);
+    SuccessOrExit(err);
+
+    Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceICACerts);
+
+    SetFlag(mFlags, kFlag_DeviceCredentialsProvisioned);
+
+    // Post an event alerting other subsystems that the device now new credentials.
+    {
+        WeaveDeviceEvent event;
+        event.Type = DeviceEventType::kDeviceCredentialsChange;
+        event.DeviceCredentialsChange.AreCredentialsProvisioned = true;
+        PlatformMgr().PostEvent(&event);
+    }
+
+exit:
+    if (err != WEAVE_NO_ERROR)
+    {
+        Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceId);
+        Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceCert);
+        Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDevicePrivateKey);
+        ClearFlag(mFlags, kFlag_DeviceCredentialsProvisioned);
+    }
+    return err;
+}
+
+template<class ImplClass>
+WEAVE_ERROR GenericConfigurationManagerImpl<ImplClass>::_ClearDeviceCredentials(void)
+{
+    Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceId);
+    Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceCert);
+    Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDeviceICACerts);
+    Impl()->ClearConfigValue(ImplClass::kConfigKey_OperationalDevicePrivateKey);
+
+    // If necessary, post an event alerting other subsystems to the change in
+    // the certificate state.
+    if (_DeviceCredentialsProvisioned())
+    {
+        WeaveDeviceEvent event;
+        event.Type = DeviceEventType::kDeviceCredentialsChange;
+        event.DeviceCredentialsChange.AreCredentialsProvisioned = false;
+        PlatformMgr().PostEvent(&event);
+    }
+
+    ClearFlag(mFlags, kFlag_DeviceCredentialsProvisioned);
+
+    return WEAVE_NO_ERROR;
 }
 
 template<class ImplClass>
@@ -728,6 +923,9 @@
 #if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
             Impl()->IsPairedToAccount() &&
 #endif
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+            (!Impl()->UseManufAttestCredentialsAsOperational() && Impl()->DeviceCredentialsProvisioned()) &&
+#endif
             Impl()->IsMemberOfFabric();
 }
 
@@ -770,7 +968,7 @@
         constexpr uint16_t kDeviceIdLen = 16; // 16 hex characters
         char inputBuf[kLenFieldLen + kDeviceIdLen + 1]; // +1 for terminator
 
-        err = Impl()->_GetDeviceId(deviceId);
+        err = Impl()->_GetManufAttestDeviceId(deviceId);
         SuccessOrExit(err);
 
         snprintf(inputBuf, sizeof(inputBuf), "0010%016" PRIX64, deviceId);
@@ -783,7 +981,7 @@
         size_t certLen;
 
         // Determine the length of the device certificate.
-        err = Impl()->_GetDeviceCertificate((uint8_t *)NULL, 0, certLen);
+        err = Impl()->_GetManufAttestDeviceCertificate((uint8_t *)NULL, 0, certLen);
         SuccessOrExit(err);
 
         // Create a temporary buffer to hold the certificate.  (This will also be used for
@@ -793,25 +991,53 @@
         VerifyOrExit(dataBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
 
         // Read the certificate.
-        err = Impl()->_GetDeviceCertificate(dataBuf, certLen, certLen);
+        err = Impl()->_GetManufAttestDeviceCertificate(dataBuf, certLen, certLen);
         SuccessOrExit(err);
 
         // Hash the length and value of the device certificate in base-64 form.
         HashLengthAndBase64Value(hash, dataBuf, (uint16_t)certLen);
     }
 
+    // Hash the device intermediate CA certificates
+    if (Impl()->ConfigValueExists(ImplClass::kConfigKey_ManufAttestDeviceICACerts))
+    {
+        size_t certsLen;
+
+        // Determine the length of the device certificate.
+        err = Impl()->_GetManufAttestDeviceICACerts((uint8_t *)NULL, 0, certsLen);
+        SuccessOrExit(err);
+
+        // Allocate larger buffer to hold the intermediate CA certificates.
+	// (This will also be used for the private key).
+	if (certsLen > dataBufSize)
+	{
+            Platform::Security::MemoryFree(dataBuf);
+
+            dataBufSize = certsLen;
+            dataBuf = (uint8_t *)Platform::Security::MemoryAlloc(dataBufSize);
+            VerifyOrExit(dataBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
+        }
+
+        // Read the certificate.
+        err = Impl()->_GetManufAttestDeviceICACerts(dataBuf, certsLen, certsLen);
+        SuccessOrExit(err);
+
+        // Hash the length and value of the device certificate in base-64 form.
+        HashLengthAndBase64Value(hash, dataBuf, (uint16_t)certsLen);
+    }
+
     // Hash the device private key
     {
         size_t keyLen;
 
         // Determine the length of the device private key.
-        err = Impl()->_GetDevicePrivateKey((uint8_t *)NULL, 0, keyLen);
+        err = Impl()->_GetManufAttestDevicePrivateKey((uint8_t *)NULL, 0, keyLen);
         SuccessOrExit(err);
 
         // Read the private key.  (Note that we presume the buffer allocated to hold the certificate
         // is big enough to hold the private key.  _GetDevicePrivateKey() will return an error in the
         // unlikely event that this is not the case.)
-        err = Impl()->_GetDevicePrivateKey(dataBuf, dataBufSize, keyLen);
+        err = Impl()->_GetManufAttestDevicePrivateKey(dataBuf, dataBufSize, keyLen);
         SuccessOrExit(err);
 
         // Hash the length and value of the private key in base-64 form.
@@ -873,6 +1099,36 @@
     }
 }
 
+template<class ImplClass>
+bool GenericConfigurationManagerImpl<ImplClass>::_DeviceCredentialsProvisioned()
+{
+    return ::nl::GetFlag(mFlags, kFlag_DeviceCredentialsProvisioned);
+}
+
+template<class ImplClass>
+bool GenericConfigurationManagerImpl<ImplClass>::_DeviceICACertsProvisioned()
+{
+    return Impl()->ConfigValueExists(ImplClass::kConfigKey_OperationalDeviceICACerts);
+}
+
+template<class ImplClass>
+bool GenericConfigurationManagerImpl<ImplClass>::_ManufAttestDeviceICACertsProvisioned()
+{
+    return Impl()->ConfigValueExists(ImplClass::kConfigKey_ManufAttestDeviceICACerts);
+}
+
+template<class ImplClass>
+bool GenericConfigurationManagerImpl<ImplClass>::_UseManufAttestCredentialsAsOperational()
+{
+    return ::nl::GetFlag(mFlags, kFlag_UseManufAttestCredentialsAsOperational);
+}
+
+template<class ImplClass>
+void GenericConfigurationManagerImpl<ImplClass>::_UseManufAttestCredentialsAsOperational(bool val)
+{
+    SetFlag(mFlags, kFlag_UseManufAttestCredentialsAsOperational, val);
+}
+
 #if WEAVE_PROGRESS_LOGGING
 
 template<class ImplClass>
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericPlatformManagerImpl.ipp b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericPlatformManagerImpl.ipp
index 71af0d7..3be554b 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericPlatformManagerImpl.ipp
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/GenericPlatformManagerImpl.ipp
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -28,6 +29,7 @@
 
 #include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>
 #include <Weave/DeviceLayer/PlatformManager.h>
+#include <Weave/DeviceLayer/internal/CertificateProvisioningClient.h>
 #include <Weave/DeviceLayer/internal/GenericPlatformManagerImpl.h>
 #include <Weave/DeviceLayer/internal/DeviceControlServer.h>
 #include <Weave/DeviceLayer/internal/DeviceDescriptionServer.h>
@@ -73,6 +75,27 @@
     }
     SuccessOrExit(err);
 
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+    if (!ConfigurationMgr().DeviceCredentialsProvisioned())
+    {
+        // If paired to account keep using device manufacturing credentials as operational.
+        if (ConfigurationMgr().IsServiceProvisioned() && ConfigurationMgr().IsPairedToAccount())
+        {
+	    ConfigurationMgr().UseManufAttestCredentialsAsOperational(true);
+        }
+        // Otherwise, generate and store new device credentials.
+        else
+        {
+            err = GenerateAndStoreOperationalDeviceCredentials();
+            if (err != WEAVE_NO_ERROR)
+            {
+                WeaveLogError(DeviceLayer, "GenerateAndStoreOperationalDeviceCredentials() failed: %s", ErrorStr(err));
+            }
+            SuccessOrExit(err);
+        }
+    }
+#endif
+
     // Initialize the Weave system layer.
     new (&SystemLayer) System::Layer();
     err = SystemLayer.Init(NULL);
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/ServiceProvisioningServer.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/ServiceProvisioningServer.h
index 364ed65..677d8a7 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/ServiceProvisioningServer.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/ServiceProvisioningServer.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -26,6 +27,7 @@
 
 #include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>
 #include <Weave/Profiles/service-provisioning/ServiceProvisioning.h>
+#include <Weave/DeviceLayer/internal/CertificateProvisioningClient.h>
 
 namespace nl {
 namespace Weave {
@@ -84,14 +86,19 @@
 
     ::nl::Weave::Binding * mProvServiceBinding;
     bool mWaitingForServiceConnectivity;
+#if WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
+    CertificateProvisioningClient * mCertProvClient;
+#endif // WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS
 
     void StartPairDeviceToAccount(void);
     void SendPairDeviceToAccountRequest(void);
 
+    static void AsyncStartCertificateProvisioning(intptr_t arg);
     static void AsyncStartPairDeviceToAccount(intptr_t arg);
     static void HandleServiceConnectivityTimeout(::nl::Weave::System::Layer * layer, void * appState, ::nl::Weave::System::Error err);
     static void HandleProvServiceBindingEvent(void * appState, nl::Weave::Binding::EventType eventType,
             const nl::Weave::Binding::InEventParam & inParam, nl::Weave::Binding::OutEventParam & outParam);
+    static WEAVE_ERROR EncodeGetCertificateRequestAuthInfo(TLVWriter &writer);
 
 protected:
 
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h
index abec891..8e06465 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h
@@ -44,8 +44,10 @@
 #if WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
 extern const uint64_t TestDeviceId;
 extern const uint8_t TestDeviceCert[];
+extern const uint8_t TestDeviceICACert[];
 extern const uint8_t TestDevicePrivateKey[];
 extern const uint16_t TestDeviceCertLength;
+extern const uint16_t TestDeviceICACertLength;
 extern const uint16_t TestDevicePrivateKeyLength;
 #endif // WEAVE_DEVICE_CONFIG_ENABLE_TEST_DEVICE_IDENTITY
 
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/testing/ConfigUnitTest.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/testing/ConfigUnitTest.h
index 50676a3..1239bc3 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/testing/ConfigUnitTest.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/testing/ConfigUnitTest.h
@@ -50,12 +50,12 @@
     {
         uint64_t v = 9872349687345;
 
-        err = ConfigClass::WriteConfigValue(ConfigClass::kConfigKey_DeviceId, v);
+        err = ConfigClass::WriteConfigValue(ConfigClass::kConfigKey_ManufAttestDeviceId, v);
         VerifyOrDie(err == WEAVE_NO_ERROR);
 
         v = 0;
 
-        err = ConfigClass::ReadConfigValue(ConfigClass::kConfigKey_DeviceId, v);
+        err = ConfigClass::ReadConfigValue(ConfigClass::kConfigKey_ManufAttestDeviceId, v);
         VerifyOrDie(err == WEAVE_NO_ERROR);
 
         VerifyOrDie(v == 9872349687345);
@@ -149,10 +149,10 @@
         uint8_t buf[512];
         size_t dataLen;
 
-        err = ConfigClass::WriteConfigValueBin(ConfigClass::kConfigKey_DeviceCert, kTestData, sizeof(kTestData));
+        err = ConfigClass::WriteConfigValueBin(ConfigClass::kConfigKey_ManufAttestDeviceCert, kTestData, sizeof(kTestData));
         VerifyOrDie(err == WEAVE_NO_ERROR);
 
-        err = ConfigClass::ReadConfigValueBin(ConfigClass::kConfigKey_DeviceCert, buf, sizeof(buf), dataLen);
+        err = ConfigClass::ReadConfigValueBin(ConfigClass::kConfigKey_ManufAttestDeviceCert, buf, sizeof(buf), dataLen);
         VerifyOrDie(err == WEAVE_NO_ERROR);
 
         VerifyOrDie(dataLen == sizeof(kTestData));
@@ -164,10 +164,10 @@
         uint8_t buf[512];
         size_t dataLen;
 
-        err = ConfigClass::WriteConfigValueBin(ConfigClass::kConfigKey_DeviceCert, NULL, 0);
+        err = ConfigClass::WriteConfigValueBin(ConfigClass::kConfigKey_ManufAttestDeviceCert, NULL, 0);
         VerifyOrDie(err == WEAVE_NO_ERROR);
 
-        err = ConfigClass::ReadConfigValueBin(ConfigClass::kConfigKey_DeviceCert, buf, sizeof(buf), dataLen);
+        err = ConfigClass::ReadConfigValueBin(ConfigClass::kConfigKey_ManufAttestDeviceCert, buf, sizeof(buf), dataLen);
         VerifyOrDie(err == WEAVE_DEVICE_ERROR_CONFIG_NOT_FOUND);
     }
 
@@ -175,13 +175,13 @@
     {
         bool v;
 
-        v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_DeviceId);
+        v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_ManufAttestDeviceId);
         VerifyOrDie(v == true);
 
         v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_FailSafeArmed);
         VerifyOrDie(v == true);
 
-        v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_DeviceCert);
+        v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_ManufAttestDeviceCert);
         VerifyOrDie(v == false);
     }
 
@@ -192,7 +192,7 @@
         err = ConfigClass::FactoryResetConfig();
         VerifyOrDie(err == WEAVE_NO_ERROR);
 
-        v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_DeviceId);
+        v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_ManufAttestDeviceId);
         VerifyOrDie(v == true);
 
         v = ConfigClass::ConfigValueExists(ConfigClass::kConfigKey_FailSafeArmed);
diff --git a/src/adaptations/device-layer/include/Weave/DeviceLayer/nRF5/nRF5Config.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/nRF5/nRF5Config.h
index 8d40646..b3c8f85 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/nRF5/nRF5Config.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/nRF5/nRF5Config.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -79,9 +80,9 @@
 
     // Key definitions for well-known configuration values.
     static constexpr Key kConfigKey_SerialNum                   = NRF5ConfigKey(kFileId_WeaveFactory, 0x0001);
-    static constexpr Key kConfigKey_DeviceId                    = NRF5ConfigKey(kFileId_WeaveFactory, 0x0002);
-    static constexpr Key kConfigKey_DeviceCert                  = NRF5ConfigKey(kFileId_WeaveFactory, 0x0003);
-    static constexpr Key kConfigKey_DevicePrivateKey            = NRF5ConfigKey(kFileId_WeaveFactory, 0x0004);
+    static constexpr Key kConfigKey_ManufAttestDeviceId         = NRF5ConfigKey(kFileId_WeaveFactory, 0x0002);
+    static constexpr Key kConfigKey_ManufAttestDeviceCert       = NRF5ConfigKey(kFileId_WeaveFactory, 0x0003);
+    static constexpr Key kConfigKey_ManufAttestDevicePrivateKey = NRF5ConfigKey(kFileId_WeaveFactory, 0x0004);
     static constexpr Key kConfigKey_ManufacturingDate           = NRF5ConfigKey(kFileId_WeaveFactory, 0x0005);
     static constexpr Key kConfigKey_PairingCode                 = NRF5ConfigKey(kFileId_WeaveFactory, 0x0006);
     static constexpr Key kConfigKey_FabricId                    = NRF5ConfigKey(kFileId_WeaveConfig,  0x0007);
@@ -93,6 +94,11 @@
     static constexpr Key kConfigKey_FailSafeArmed               = NRF5ConfigKey(kFileId_WeaveConfig,  0x000D);
     static constexpr Key kConfigKey_GroupKey                    = NRF5ConfigKey(kFileId_WeaveConfig,  0x000E);
     static constexpr Key kConfigKey_ProductRevision             = NRF5ConfigKey(kFileId_WeaveFactory, 0x000F);
+    static constexpr Key kConfigKey_ManufAttestDeviceICACerts   = NRF5ConfigKey(kFileId_WeaveFactory, 0x0010);
+    static constexpr Key kConfigKey_OperationalDeviceId         = NRF5ConfigKey(kFileId_WeaveConfig,  0x0011);
+    static constexpr Key kConfigKey_OperationalDeviceCert       = NRF5ConfigKey(kFileId_WeaveConfig,  0x0012);
+    static constexpr Key kConfigKey_OperationalDeviceICACerts   = NRF5ConfigKey(kFileId_WeaveConfig,  0x0013);
+    static constexpr Key kConfigKey_OperationalDevicePrivateKey = NRF5ConfigKey(kFileId_WeaveConfig,  0x0014);
 
     // Range of FDS record keys used to store Weave persisted counter values.
     static constexpr uint16_t kPersistedCounterRecordKeyBase    = kFDSRecordKeyMin;
diff --git a/src/adaptations/device-layer/nRF5/BLEManagerImpl.cpp b/src/adaptations/device-layer/nRF5/BLEManagerImpl.cpp
index 2ed18c6..5866cc5 100644
--- a/src/adaptations/device-layer/nRF5/BLEManagerImpl.cpp
+++ b/src/adaptations/device-layer/nRF5/BLEManagerImpl.cpp
@@ -282,6 +282,7 @@
     case DeviceEventType::kFabricMembershipChange:
     case DeviceEventType::kServiceProvisioningChange:
     case DeviceEventType::kAccountPairingChange:
+    case DeviceEventType::kDeviceCredentialsChange:
 
         // If WOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the
         // device's provisioning state, then automatically disable WoBLE advertising if the device
diff --git a/src/adaptations/device-layer/nRF5/nRF5Config.cpp b/src/adaptations/device-layer/nRF5/nRF5Config.cpp
index 5ed4065..483006e 100644
--- a/src/adaptations/device-layer/nRF5/nRF5Config.cpp
+++ b/src/adaptations/device-layer/nRF5/nRF5Config.cpp
@@ -769,13 +769,13 @@
 
         for (int i = 0; i < 100; i++)
         {
-            err = WriteConfigValueBin(kConfigKey_DeviceCert, kTestData, sizeof(kTestData));
+            err = WriteConfigValueBin(kConfigKey_ManufAttestDeviceCert, kTestData, sizeof(kTestData));
             VerifyOrDie(err == WEAVE_NO_ERROR);
 
             vTaskDelay(pdMS_TO_TICKS(50));
         }
 
-        err = ReadConfigValueBin(kConfigKey_DeviceCert, buf, sizeof(buf), dataLen);
+        err = ReadConfigValueBin(kConfigKey_ManufAttestDeviceCert, buf, sizeof(buf), dataLen);
         VerifyOrDie(err == WEAVE_NO_ERROR);
 
         VerifyOrDie(dataLen == sizeof(kTestData));
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 1c55496..86d266c 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -1061,6 +1061,7 @@
 
 nl_public_WeaveDeviceLayer_internal_header_sources =                                                \
 $(nl_public_WeaveDeviceLayer_source_dirstem)/internal/BLEManager.h                                  \
+$(nl_public_WeaveDeviceLayer_source_dirstem)/internal/CertificateProvisioningClient.h               \
 $(nl_public_WeaveDeviceLayer_source_dirstem)/internal/DeviceControlServer.h                         \
 $(nl_public_WeaveDeviceLayer_source_dirstem)/internal/DeviceDescriptionServer.h                     \
 $(nl_public_WeaveDeviceLayer_source_dirstem)/internal/DeviceIdentityTraitDataSource.h               \
diff --git a/src/include/Makefile.in b/src/include/Makefile.in
index 4a97d96..3fac8f6 100644
--- a/src/include/Makefile.in
+++ b/src/include/Makefile.in
@@ -1423,6 +1423,7 @@
 
 @CONFIG_DEVICE_LAYER_TRUE@nl_public_WeaveDeviceLayer_internal_header_sources = \
 @CONFIG_DEVICE_LAYER_TRUE@$(nl_public_WeaveDeviceLayer_source_dirstem)/internal/BLEManager.h                                  \
+@CONFIG_DEVICE_LAYER_TRUE@$(nl_public_WeaveDeviceLayer_source_dirstem)/internal/CertificateProvisioningClient.h               \
 @CONFIG_DEVICE_LAYER_TRUE@$(nl_public_WeaveDeviceLayer_source_dirstem)/internal/DeviceControlServer.h                         \
 @CONFIG_DEVICE_LAYER_TRUE@$(nl_public_WeaveDeviceLayer_source_dirstem)/internal/DeviceDescriptionServer.h                     \
 @CONFIG_DEVICE_LAYER_TRUE@$(nl_public_WeaveDeviceLayer_source_dirstem)/internal/DeviceIdentityTraitDataSource.h               \
diff --git a/src/lib/profiles/device-control/DeviceControl.h b/src/lib/profiles/device-control/DeviceControl.h
index 3686718..ab44ce2 100644
--- a/src/lib/profiles/device-control/DeviceControl.h
+++ b/src/lib/profiles/device-control/DeviceControl.h
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019 Google LLC.
  *    Copyright (c) 2013-2017 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -110,6 +111,7 @@
     kResetConfigFlag_NetworkConfig              = 0x0001, /**< Reset network configuration information. */
     kResetConfigFlag_FabricConfig               = 0x0002, /**< Reset fabric configuration information. */
     kResetConfigFlag_ServiceConfig              = 0x0004, /**< Reset network configuration information. */
+    kResetConfigFlag_Credentials                = 0x0008, /**< Reset device credentials. */
     kResetConfigFlag_FactoryDefaults            = 0x8000  /**< Reset device to full factory defaults. */
 };
 
diff --git a/src/lib/profiles/security/WeaveSecurity.h b/src/lib/profiles/security/WeaveSecurity.h
index 3ea86c9..3c9c428 100644
--- a/src/lib/profiles/security/WeaveSecurity.h
+++ b/src/lib/profiles/security/WeaveSecurity.h
@@ -108,8 +108,9 @@
     kStatusCode_InternalKeyError                = 16, // The receiver of the Weave message encountered key error.
     kStatusCode_NoCommonKeyExportConfiguration  = 17, // No common key export protocol configuration supported.
     kStatusCode_UnathorizedKeyExportRequest     = 18, // An unauthorized key export request.
-    kStatusCode_UnathorizedGetCertRequest       = 19, // An unauthorized get certificate request.
-    kStatusCode_NoNewCertRequired               = 20, // No new certificate required.
+    kStatusCode_ServiceCommunicationError       = 19, /**< The device could not complete certificate provisioning because it encountered an error when communicating with the service. */
+    kStatusCode_UnathorizedGetCertRequest       = 20, /**< An unauthorized get certificate request. */
+    kStatusCode_NoNewCertRequired               = 21, /**< No new certificate required. */
 };
 
 // Weave Key Error Message Size
diff --git a/src/lib/support/StatusReportStr.cpp b/src/lib/support/StatusReportStr.cpp
index 5ff499e..e52eee4 100644
--- a/src/lib/support/StatusReportStr.cpp
+++ b/src/lib/support/StatusReportStr.cpp
@@ -265,6 +265,7 @@
         case Security::kStatusCode_InternalKeyError                                     : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Internal key error"; break;
         case Security::kStatusCode_NoCommonKeyExportConfiguration                       : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] No common key export configuration"; break;
         case Security::kStatusCode_UnathorizedKeyExportRequest                          : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Unauthorized key export request"; break;
+        case Security::kStatusCode_ServiceCommunicationError                            : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Service communication error"; break;
         case Security::kStatusCode_UnathorizedGetCertRequest                            : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] Unauthorized get certificate request"; break;
         case Security::kStatusCode_NoNewCertRequired                                    : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ] No new certificate required"; break;
         default                                                                         : fmt = "[ Security(%08" PRIX32 "):%" PRIu16 " ]"; break;