WIP: Implement Certificate Provisioning Client at the Weave Device Layer.
diff --git a/src/adaptations/device-layer/CertificateProvisioningClient.cpp b/src/adaptations/device-layer/CertificateProvisioningClient.cpp
new file mode 100644
index 0000000..a4010d8
--- /dev/null
+++ b/src/adaptations/device-layer/CertificateProvisioningClient.cpp
@@ -0,0 +1,544 @@
+/*
+ *
+ *    Copyright (c) 2019-2020 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_JUST_IN_TIME_PROVISIONING
+
+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;
+    mDoMfrAttest = (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().StoreDeviceIntermediateCACerts(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 * icaCerts = NULL;
+    size_t icaCertsLen = 0;
+
+    // Determine if present and the length of the operational device intermediate CA certificates.
+    err = ConfigurationMgr().GetDeviceIntermediateCACerts((uint8_t *)NULL, 0, icaCertsLen);
+    if (err == WEAVE_DEVICE_ERROR_CONFIG_NOT_FOUND)
+    {
+        // Exit without error if operational device intermediate CA certificates is not configured.
+        ExitNow(err = WEAVE_NO_ERROR);
+    }
+    SuccessOrExit(err);
+
+    VerifyOrExit(icaCertsLen != 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+
+    // Create a temporary buffer to hold the operational device intermediate CA certificates.
+    icaCerts = static_cast<uint8_t *>(MemoryAlloc(icaCertsLen));
+    VerifyOrExit(icaCerts != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    // Read the operational device intermediate CA certificates.
+    err = ConfigurationMgr().GetDeviceCertificate(icaCerts, icaCertsLen, icaCertsLen);
+    SuccessOrExit(err);
+
+    // Copy encoded operational device intermediate CA certificates.
+    err = writer.CopyContainer(tag, icaCerts, icaCertsLen);
+    SuccessOrExit(err);
+
+exit:
+    if (icaCerts != NULL)
+    {
+        MemoryFree(icaCerts);
+    }
+    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 WeaveNodeMfrAttestDelegate interface
+
+WEAVE_ERROR CertificateProvisioningClient::EncodeMAInfo(TLVWriter & writer)
+{
+    WEAVE_ERROR err;
+    uint8_t * cert = NULL;
+    size_t certLen = 0;
+    size_t icaCertsLen = 0;
+
+    // Determine the length of the manufacturer assigned device certificate.
+    err = ConfigurationMgr().GetManufacturerDeviceCertificate((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 assigned device certificate.
+    err = ConfigurationMgr().GetManufacturerDeviceCertificate(cert, certLen, certLen);
+    SuccessOrExit(err);
+
+    // Copy encoded manufacturer attestation device certificate.
+    err = writer.CopyContainer(ContextTag(kTag_GetCertReqMsg_MfrAttest_WeaveCert), cert, certLen);
+    SuccessOrExit(err);
+
+    // Determine if present and the length of the manufacturer assigned device intermediate CA certificates.
+    err = ConfigurationMgr().GetManufacturerDeviceIntermediateCACerts((uint8_t *)NULL, 0, icaCertsLen);
+    if (err == WEAVE_DEVICE_ERROR_CONFIG_NOT_FOUND)
+    {
+        // Exit without error if manufacturer assigned intermediate CA certificates is not configured.
+        ExitNow(err = WEAVE_NO_ERROR);
+    }
+    SuccessOrExit(err);
+
+    {
+        VerifyOrExit(icaCertsLen != 0, err = WEAVE_ERROR_CERT_NOT_FOUND);
+
+        // If needed, allocate larger buffer to hold the intermediate CA certificates.
+        if (icaCertsLen > certLen)
+        {
+            MemoryFree(cert);
+
+            cert = static_cast<uint8_t *>(MemoryAlloc(icaCertsLen));
+            VerifyOrExit(cert != NULL, err = WEAVE_ERROR_NO_MEMORY);
+        }
+
+        // Read the manufacturer assigned device intermediate CA certificates.
+        err = ConfigurationMgr().GetManufacturerDeviceIntermediateCACerts(cert, icaCertsLen, icaCertsLen);
+        SuccessOrExit(err);
+
+        // Copy encoded manufacturer attestation device intermediate CA certificates.
+        err = writer.CopyContainer(ContextTag(kTag_GetCertReqMsg_MfrAttest_WeaveRelCerts), cert, icaCertsLen);
+        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().GetManufacturerDevicePrivateKey((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().GetManufacturerDevicePrivateKey(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_MfrAttestSigAlgo), static_cast<uint16_t>(ASN1::kOID_SigAlgo_ECDSAWithSHA256));
+    SuccessOrExit(err);
+
+    // Generate and encode manufacturer attestation device signature.
+    err = GenerateAndEncodeWeaveECDSASignature(writer, ContextTag(kTag_GetCertReqMsg_MfrAttestSig_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, mDoMfrAttest);
+    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_JUST_IN_TIME_PROVISIONING
+
+} // namespace Internal
+} // 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..42a5397 100644
--- a/src/adaptations/device-layer/ESP32/ConnectivityManagerImpl.cpp
+++ b/src/adaptations/device-layer/ESP32/ConnectivityManagerImpl.cpp
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019-2020 Google LLC.
  *    Copyright (c) 2018 Nest Labs, Inc.
  *    All rights reserved.
  *
@@ -525,18 +526,19 @@
         DriveServiceTunnelState();
     }
 
-#if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
+#if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING || WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
 
-    // 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 +548,7 @@
         }
     }
 
-#endif // !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
+#endif // !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING || WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
 }
 
 void ConnectivityManagerImpl::_OnWiFiScanDone()
diff --git a/src/adaptations/device-layer/Makefile.am b/src/adaptations/device-layer/Makefile.am
index 0812312..76cb5a9 100644
--- a/src/adaptations/device-layer/Makefile.am
+++ b/src/adaptations/device-layer/Makefile.am
@@ -1,6 +1,6 @@
 #
 #    Copyright (c) 2014-2018 Nest Labs, Inc.
-#    Copyright (c) 2018 Google LLC
+#    Copyright (c) 2018-2020 Google LLC
 #    All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License");
@@ -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/ServiceProvisioningServer.cpp b/src/adaptations/device-layer/ServiceProvisioningServer.cpp
index c0de161..f54fed8 100644
--- a/src/adaptations/device-layer/ServiceProvisioningServer.cpp
+++ b/src/adaptations/device-layer/ServiceProvisioningServer.cpp
@@ -1,5 +1,6 @@
 /*
  *
+ *    Copyright (c) 2019-2020 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)
@@ -46,6 +52,10 @@
     mProvServiceBinding = NULL;
     mWaitingForServiceConnectivity = false;
 
+#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
+    mCertProvClient = NULL;
+#endif
+
 exit:
     return err;
 }
@@ -91,7 +101,12 @@
         PlatformMgr().PostEvent(&event);
     }
 
-#if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING
+#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
+
+    // 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 +319,15 @@
         mProvServiceBinding = NULL;
     }
 
+#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
+    // If necessary, free memory allocated for the certificate provisioning engine.
+    if (mCertProvClient != NULL)
+    {
+        MemoryFree(mCertProvClient);
+        mCertProvClient = NULL;
+    }
+#endif // WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
+
     // 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 +398,33 @@
     }
 }
 
+#if WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING
+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_JUST_IN_TIME_PROVISIONING
+
 void ServiceProvisioningServer::AsyncStartPairDeviceToAccount(intptr_t arg)
 {
     sInstance.StartPairDeviceToAccount();
@@ -415,6 +466,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/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 f1dcdcd..f124419 100644
--- a/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceConfig.h
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/WeaveDeviceConfig.h
@@ -501,6 +501,39 @@
 #define WEAVE_DEVICE_CONFIG_ENABLE_JUST_IN_TIME_PROVISIONING 0
 #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..25f4072
--- /dev/null
+++ b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/CertificateProvisioningClient.h
@@ -0,0 +1,112 @@
+/*
+ *
+ *    Copyright (c) 2019-2020 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;
+
+/**
+ * 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::WeaveNodeMfrAttestDelegate
+{
+
+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 WeaveNodeMfrAttestDelegate 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 mDoMfrAttest;
+    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/ServiceProvisioningServer.h b/src/adaptations/device-layer/include/Weave/DeviceLayer/internal/ServiceProvisioningServer.h
index 364ed65..57871f5 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-2020 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_JUST_IN_TIME_PROVISIONING
+    CertificateProvisioningClient * mCertProvClient;
+#endif
 
     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/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/include/Makefile.am b/src/include/Makefile.am
index 1c55496..14d7830 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -1,5 +1,5 @@
 #
-#    Copyright (c) 2019 Google LLC.
+#    Copyright (c) 2019-2020 Google LLC.
 #    Copyright (c) 2014-2017 Nest Labs, Inc.
 #    All rights reserved.
 #
@@ -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               \