{"action":"created","comment":{"url":"https://api.github.com/repos/openweave/openweave-core/pulls/comments/364509206","pull_request_review_id":340228464,"id":364509206,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDM2NDUwOTIwNg==","diff_hunk":"@@ -0,0 +1,767 @@\n+/*\n+ *\n+ *    Copyright (c) 2019 Google LLC.\n+ *    All rights reserved.\n+ *\n+ *    Licensed under the Apache License, Version 2.0 (the \"License\");\n+ *    you may not use this file except in compliance with the License.\n+ *    You may obtain a copy of the License at\n+ *\n+ *        http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ *    Unless required by applicable law or agreed to in writing, software\n+ *    distributed under the License is distributed on an \"AS IS\" BASIS,\n+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ *    See the License for the specific language governing permissions and\n+ *    limitations under the License.\n+ */\n+\n+/**\n+ *    @file\n+ *      This file implements the Certificate Provisioning Protocol, used to\n+ *      get new Weave operational device certificate from the CA service.\n+ *\n+ */\n+\n+#include <Weave/Core/WeaveCore.h>\n+#include <Weave/Core/WeaveTLV.h>\n+#include <Weave/Support/CodeUtils.h>\n+#include <Weave/Core/WeaveEncoding.h>\n+#include <Weave/Profiles/WeaveProfiles.h>\n+#include \"WeaveCertProvisioning.h\"\n+#include <Weave/Profiles/common/CommonProfile.h>\n+#include <Weave/Support/crypto/HashAlgos.h>\n+\n+namespace nl {\n+namespace Weave {\n+namespace Profiles {\n+namespace Security {\n+namespace CertProvisioning {\n+\n+using namespace nl::Weave::Crypto;\n+using namespace nl::Weave::Encoding;\n+using namespace nl::Weave::TLV;\n+using namespace nl::Weave::Platform::Security;\n+\n+// ==================== Public Members ====================\n+\n+/**\n+ * Initialize a WeaveCertProvEngine object in preparation for sending get certificate request message.\n+ *\n+ *  @param[in]  binding              A Binding object that will be used to establish communication with the\n+ *                                   peer node.\n+ *  @param[in]  opAuthDelegate       A pointer to a operational authentication delegate object that will be used to\n+ *                                   construct and sign using node's operatational credentials.\n+ *  @param[in]  manufAttestDelegate  A pointer to a manufacturer attestation delegate object that will be used to\n+ *                                   construct and sign request using node's manufacturer provisioned credentials.\n+ *  @param[in]  eventCallback        A pointer to a function that will be called by the WeaveCertProvEngine object\n+ *                                   to deliver API events to the application.\n+ *  @param[in]  appState             A pointer to an application-defined object which will be passed back\n+ *                                   to the application whenever an API event occurs.\n+ */\n+WEAVE_ERROR WeaveCertProvEngine::Init(Binding * binding, WeaveNodeOpAuthDelegate * opAuthDelegate, WeaveNodeManufAttestDelegate * manufAttestDelegate, EventCallback eventCallback, void * appState)\n+{\n+    WEAVE_ERROR err = WEAVE_NO_ERROR;\n+\n+    VerifyOrExit(opAuthDelegate != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);\n+\n+    VerifyOrExit(eventCallback != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);\n+\n+    AppState = appState;\n+    mReqType = kReqType_NotSpecified;\n+    mDoManufAttest = false;\n+    mBinding = binding;\n+    mOpAuthDelegate = opAuthDelegate;\n+    mManufAttestDelegate = manufAttestDelegate;\n+    mEventCallback = eventCallback;\n+    mEC = NULL;\n+\n+    // Retain a reference to the binding object.\n+    if (binding != NULL)\n+    {\n+        binding->AddRef();\n+    }\n+\n+    mState = kState_Idle;\n+\n+exit:\n+    return err;\n+}\n+\n+/**\n+ * Shutdown a previously initialized WeaveCertProvEngine object.\n+ *\n+ * Note that this method can only be called if the Init() method has been called previously.\n+ */\n+void WeaveCertProvEngine::Shutdown(void)\n+{\n+    // Stop request if currently in progress.\n+    HandleRequestDone();\n+\n+    // Release the reference to the binding.\n+    if (mBinding != NULL)\n+    {\n+        mBinding->Release();\n+        mBinding = NULL;\n+    }\n+\n+    mOpAuthDelegate = NULL;\n+    mManufAttestDelegate = NULL;\n+    mEventCallback = NULL;\n+    mState = kState_NotInitialized;\n+}\n+\n+/**\n+ * Start Certificate Provisioning Protocol.\n+ *\n+ * This method initiates the process of sending a GetCertificateRequest message to the\n+ * CA service. If and when a corresponding GetCertificateResponse message is received it will be\n+ * delivered to the application via the ResponseReceived API event.\n+ *\n+ * If the Binding object is not in the Ready state when this method is called, a request\n+ * will be made to Binding::RequestPrepare() method to initiate on-demand preparation.\n+ * The request operation will then be waiting until this process completes. Any call to\n+ * StartCertificateProvisioning() while there is a previous request in process will be ignored.\n+ *\n+ *  @param[in]  reqType              Get certificate request type.\n+ *  @param[in]  doManufAttest        A boolean flag that indicates whether protocol should\n+ *                                   include manufacturer attestation data.\n+ *\n+ *  @retval #WEAVE_NO_ERROR          If StartCertificateProvisioning() was processed successfully.\n+ */\n+WEAVE_ERROR WeaveCertProvEngine::StartCertificateProvisioning(uint8_t reqType, bool doManufAttest)\n+{\n+    WEAVE_ERROR err;\n+\n+    VerifyOrExit(mState == kState_Idle, err = WEAVE_ERROR_INCORRECT_STATE);\n+\n+    VerifyOrExit(mBinding != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);\n+\n+    mReqType = reqType;\n+    mDoManufAttest = doManufAttest;\n+\n+    err = SendGetCertificateRequest();\n+    SuccessOrExit(err);\n+\n+exit:\n+    return err;\n+}\n+\n+/**\n+ * Generate GetCertificateRequest message.\n+ *\n+ * This method generates Weave GetCertificateRequest structure encoded in the Weave TLV format.\n+ *\n+ * When forming the GetCertificateRequest message, the method makes a request to the application,\n+ * via WeaveNodeOpAuthDelegate and WeaveNodeManufAttestDelegate functions and\n+ * the PrepareAuthorizeInfo API event, to prepare the payload of the message.\n+ *\n+ *  @param[in]  msgBuf               A pointer to the PacketBuffer object holding the GetCertificateRequest message.\n+ *  @param[in]  reqType              Get certificate request type.\n+ *  @param[in]  doManufAttest        A boolean flag that indicates whether request should\n+ *                                   include manufacturer attestation data.\n+ *\n+ *  @retval #WEAVE_NO_ERROR          If GetCertificateRequest was successfully generated.\n+ */\n+WEAVE_ERROR WeaveCertProvEngine::GenerateGetCertificateRequest(PacketBuffer * msgBuf, uint8_t reqType, bool doManufAttest)\n+{\n+    WEAVE_ERROR err = WEAVE_NO_ERROR;\n+    TLVWriter writer;\n+    TLVType containerType;\n+    SHA256 sha256;\n+    uint8_t *tbsDataStart;\n+    uint16_t tbsDataStartOffset;\n+    uint16_t tbsDataLen;\n+    uint8_t tbsHash[SHA256::kHashLength];\n+\n+    WeaveLogDetail(SecurityManager, \"WeaveCertProvEngine:GenerateGetCertificateRequest\");\n+\n+    VerifyOrExit(mState == kState_Idle, err = WEAVE_ERROR_INCORRECT_STATE);\n+\n+    VerifyOrExit(reqType == kReqType_GetInitialOpDeviceCert ||\n+                 reqType == kReqType_RotateOpDeviceCert, err = WEAVE_ERROR_INVALID_ARGUMENT);\n+\n+    mReqType = reqType;\n+    mDoManufAttest = doManufAttest;\n+\n+    if (doManufAttest)\n+    {\n+        VerifyOrExit(mManufAttestDelegate != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);\n+    }\n+\n+    writer.Init(msgBuf, msgBuf->AvailableDataLength());\n+\n+    err = writer.StartContainer(AnonymousTag, kTLVType_Structure, containerType);\n+    SuccessOrExit(err);\n+\n+    // Record the offset and the start of the TBS (To-Be-Signed) portion of the message.\n+    tbsDataStartOffset = writer.GetLengthWritten();\n+    tbsDataStart = msgBuf->Start() + tbsDataStartOffset;\n+\n+    // Request type.\n+    err = writer.Put(ContextTag(kTag_GetCertReqMsg_ReqType), reqType);\n+    SuccessOrExit(err);\n+\n+    // Get Certificate authorization information.\n+    {\n+        InEventParam inParam;\n+        OutEventParam outParam;\n+        inParam.Clear();\n+        inParam.Source = this;\n+        inParam.PrepareAuthorizeInfo.Writer = &writer;\n+        outParam.Clear();\n+        mEventCallback(AppState, kEvent_PrepareAuthorizeInfo, inParam, outParam);\n+        err = outParam.PrepareAuthorizeInfo.Error;\n+        SuccessOrExit(err);\n+    }\n+\n+    // Call the delegate to write the local node Weave operational certificate.\n+    err = mOpAuthDelegate->EncodeOpCert(writer, ContextTag(kTag_GetCertReqMsg_OpDeviceCert));\n+    SuccessOrExit(err);\n+\n+    // Call the delegate to write the local node Weave operational related certificate.\n+    err = mOpAuthDelegate->EncodeOpRelatedCerts(writer, ContextTag(kTag_GetCertReqMsg_OpRelatedCerts));\n+    SuccessOrExit(err);\n+\n+    // Call the delegate to write the local node manufacturer attestation information.\n+    if (doManufAttest)\n+    {\n+        err = mManufAttestDelegate->EncodeMAInfo(writer);\n+        SuccessOrExit(err);\n+    }\n+\n+    tbsDataLen = writer.GetLengthWritten() - tbsDataStartOffset;\n+\n+    // Calculate TBS hash.\n+    sha256.Begin();\n+    sha256.AddData(tbsDataStart, tbsDataLen);\n+    sha256.Finish(tbsHash);\n+\n+    // Operational signature algorithm.\n+    err = writer.Put(ContextTag(kTag_GetCertReqMsg_OpDeviceSigAlgo), static_cast<uint16_t>(ASN1::kOID_SigAlgo_ECDSAWithSHA256));\n+    SuccessOrExit(err);\n+\n+    // Generate and encode operational device signature.\n+    err = mOpAuthDelegate->GenerateAndEncodeOpSig(tbsHash, SHA256::kHashLength, writer, ContextTag(kTag_GetCertReqMsg_OpDeviceSig_ECDSA));\n+    SuccessOrExit(err);\n+\n+    // Generate and encode manufacturer attestation device signature.\n+    if (doManufAttest)\n+    {\n+        err = mManufAttestDelegate->GenerateAndEncodeMASig(tbsDataStart, tbsDataLen, writer);\n+        SuccessOrExit(err);\n+    }\n+\n+    err = writer.EndContainer(containerType);\n+    SuccessOrExit(err);\n+\n+    err = writer.Finalize();\n+    SuccessOrExit(err);\n+\n+exit:\n+    return err;\n+}\n+\n+/**\n+ * Process GetCertificateResponse message.\n+ *\n+ * This method processes Weave GetCertificateResponse structure encoded in the Weave TLV format.\n+ *\n+ * When processing of the GetCertificateResponse message is complete successfully, the method makes a call\n+ * to the application, via the ResponseReceived API event, to deliver the result.\n+ *\n+ * If processing of the GetCertificateResponse message fails, the method makes a call to the application,\n+ * via the CommunicationError API event, to report the error.\n+ *\n+ *  @param[in]  msgBuf               A pointer to the PacketBuffer object holding the GetCertificateResponse message.\n+ *\n+ *  @retval #WEAVE_NO_ERROR          If GetCertificateResponse message was successfully processed.\n+ */\n+WEAVE_ERROR WeaveCertProvEngine::ProcessGetCertificateResponse(PacketBuffer * msgBuf)\n+{\n+    WEAVE_ERROR err;\n+    TLVReader reader;\n+    TLVWriter writer;\n+    TLVType outerContainer;\n+    uint16_t dataLen = msgBuf->DataLength();\n+    uint16_t availableDataLen = msgBuf->AvailableDataLength();\n+    uint8_t * dataStart = msgBuf->Start();\n+    uint8_t * dataMove = dataStart + availableDataLen;\n+    uint8_t * cert;\n+    uint16_t certLen;\n+    uint8_t * relatedCerts = NULL;\n+    uint16_t relatedCertsLen = 0;\n+\n+    WeaveLogDetail(SecurityManager, \"WeaveCertProvEngine:ProcessGetCertificateResponse\");\n+\n+    // Move message data to the end of the message buffer.\n+    // This is done so the data can be manipulated in place without need to allocate additional\n+    // memory buffer. Specifically, this function changes context-specific tags to Security-profile\n+    // tags for device certificate structure and related certificates array.\n+    memmove(dataMove, dataStart, dataLen);\n+\n+    // Initialize a TLV reader to read the data that was moved to the end of the buffer.\n+    reader.Init(dataMove, dataLen);\n+\n+    // Initialize a TLV writer to the beginning of the buffer.\n+    writer.Init(dataStart, dataLen + availableDataLen);\n+\n+    err = reader.Next(kTLVType_Structure, AnonymousTag);\n+    SuccessOrExit(err);\n+\n+    err = reader.EnterContainer(outerContainer);\n+    SuccessOrExit(err);\n+\n+    err = reader.Next(kTLVType_Structure, ContextTag(kTag_GetCertRespMsg_OpDeviceCert));\n+    SuccessOrExit(err);\n+\n+    // Copy device certificate with new tag.\n+    err = writer.CopyContainer(ProfileTag(kWeaveProfile_Security, kTag_WeaveCertificate), reader);\n+    SuccessOrExit(err);\n+\n+    cert = dataStart;\n+    certLen = writer.GetLengthWritten();\n+\n+    err = reader.Next(kTLVType_Array, ContextTag(kTag_GetCertRespMsg_OpRelatedCerts));\n+\n+    // Optional Weave intermediate certificates list.\n+    if (err == WEAVE_NO_ERROR)\n+    {\n+        relatedCerts = cert + certLen;\n+\n+        // Copy device related certificates with new tag.\n+        err = writer.CopyContainer(ProfileTag(kWeaveProfile_Security, kTag_WeaveCertificateList), reader);\n+        SuccessOrExit(err);\n+\n+        relatedCertsLen = writer.GetLengthWritten() - certLen;\n+\n+        err = reader.Next();\n+    }\n+\n+    err = reader.VerifyEndOfContainer();\n+    SuccessOrExit(err);\n+\n+    err = reader.ExitContainer(outerContainer);\n+    SuccessOrExit(err);\n+\n+    err = reader.Next();\n+    VerifyOrExit(err == WEAVE_END_OF_TLV, err = WEAVE_ERROR_UNEXPECTED_TLV_ELEMENT);\n+    err = WEAVE_NO_ERROR;\n+\n+    VerifyOrExit(reader.GetLengthRead() == dataLen, err = WEAVE_ERROR_INVALID_MESSAGE_LENGTH);\n+\n+exit:\n+    {\n+        if (err != WEAVE_NO_ERROR)\n+        {\n+            // Deliver a CommunicationError API event to the application.\n+            DeliverCommunicationError(err);\n+        }\n+        else\n+        {\n+            InEventParam inParam;\n+            OutEventParam outParam;\n+            inParam.Clear();\n+            outParam.Clear();\n+            inParam.Source = this;\n+            inParam.ResponseReceived.ReplaceCert = true;\n+            inParam.ResponseReceived.Cert = cert;\n+            inParam.ResponseReceived.CertLen = certLen;\n+            inParam.ResponseReceived.RelatedCerts = relatedCerts;\n+            inParam.ResponseReceived.RelatedCertsLen = relatedCertsLen;\n+\n+            // Deliver a ResponseReceived API event to the application.\n+            mEventCallback(AppState, kEvent_ResponseReceived, inParam, outParam);\n+            err = outParam.ResponseReceived.Error;\n+        }\n+    }\n+\n+    return err;\n+}\n+\n+// ==================== Private Members ====================\n+\n+/**\n+ * Performs the work of initiating Binding preparation and sending a GetCertificateRequest message.\n+ */\n+WEAVE_ERROR WeaveCertProvEngine::SendGetCertificateRequest(void)\n+{\n+    WEAVE_ERROR err = WEAVE_NO_ERROR;\n+    PacketBuffer * msgBuf = NULL;\n+\n+    // Set the protocol callback on the binding object.  NOTE: This needs to happen after the\n+    // app has explicitly started the sending process by calling StartCertificateProvisioning().\n+    // Otherwise the client object might receive callbacks from the binding before its ready.\n+    // Even though it happens redundantly, we do it here to ensure it happens at the right point.\n+    mBinding->SetProtocolLayerCallback(HandleBindingEvent, this);\n+\n+    // If the binding is ready ...\n+    if (mBinding->IsReady())\n+    {\n+        // Allocate and initialize a new exchange context.\n+        err = mBinding->NewExchangeContext(mEC);\n+        SuccessOrExit(err);\n+        mEC->AppState = this;\n+        mEC->OnMessageReceived = HandleResponse;\n+        mEC->OnResponseTimeout = HandleResponseTimeout;\n+        mEC->OnKeyError = HandleKeyError;\n+        mEC->OnConnectionClosed = HandleConnectionClosed;\n+#if WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING\n+        mEC->OnAckRcvd = HandleAckRcvd;\n+        mEC->OnSendError = HandleSendError;\n+#endif // WEAVE_CONFIG_ENABLE_RELIABLE_MESSAGING\n+\n+        // Allocate buffer.\n+        msgBuf = PacketBuffer::New();\n+        VerifyOrExit(msgBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);\n+\n+        // Generate a GetCertificateRequest message.\n+        err = GenerateGetCertificateRequest(msgBuf, mReqType, mDoManufAttest);\n+        SuccessOrExit(err);\n+\n+        // Enter the RequestInProgress state.\n+        mState = kState_RequestInProgress;\n+\n+        // Send a GetCertificateRequest message to the peer.\n+        err = mEC->SendMessage(kWeaveProfile_Security, kMsgType_GetCertificateRequest, msgBuf, ExchangeContext::kSendFlag_ExpectResponse);\n+        msgBuf = NULL;\n+        SuccessOrExit(err);\n+    }\n+\n+    // Otherwise, if the binding needs to be prepared...\n+    else\n+    {\n+        // Enter the PreparingBinding state. Once binding preparation is complete, the binding will call back to\n+        // the WeaveCertProvEngine, which will result in SendGetCertificateRequest() being called again.\n+        mState = kState_PreparingBinding;\n+\n+        // If the binding is in a state where it can be prepared, ask the application to prepare it by delivering a\n+        // PrepareRequested API event via the binding's callback.  At some point the binding will call back to\n+        // WeaveCertProvEngine::HandleBindingEvent() signaling that preparation has completed (successfully or otherwise).\n+        // Note that this callback *may* happen synchronously within the RequestPrepare() method, in which case this\n+        // method (SendGetCertificateRequest()) will recurse.\n+        if (mBinding->CanBePrepared())\n+        {\n+            err = mBinding->RequestPrepare();\n+            SuccessOrExit(err);\n+        }\n+\n+        // Fail if the binding is in some state, other than Ready, that doesn't allow it to be prepared.\n+        else\n+        {\n+            VerifyOrExit(mBinding->IsPreparing(), err = WEAVE_ERROR_INCORRECT_STATE);\n+        }\n+    }\n+\n+exit:\n+    // Free the payload buffer if it hasn't been sent.\n+    if (msgBuf != NULL)\n+        PacketBuffer::Free(msgBuf);\n+\n+    if (err != WEAVE_NO_ERROR)\n+    {\n+        // Enter Idle state.\n+        mState = kState_Idle;\n+\n+        // Deliver a CommunicationError API event to the application. Note that this may result in the state\n+        // of the client object changing (e.g. as a result of the application calling AbortCertificateProvisioning()).\n+        // So the code here shouldn't presume anything about the current state after the callback.\n+        DeliverCommunicationError(err);\n+    }\n+\n+    return err;\n+}\n+\n+/**\n+ * Called when a GetCertificate exchange completes.\n+ */\n+void WeaveCertProvEngine::HandleRequestDone(void)\n+{\n+    // Clear the request state.\n+    mReqType = kReqType_NotSpecified;\n+    mDoManufAttest = false;\n+\n+    // Abort any in-progress exchange and release the exchange context.\n+    if (mEC != NULL)\n+    {\n+        mEC->Abort();\n+        mEC = NULL;\n+    }\n+\n+    // Set Idle state.\n+    mState = kState_Idle;\n+}\n+\n+/**\n+ * Deliver a CommunicationError API event to the application.\n+ */\n+void WeaveCertProvEngine::DeliverCommunicationError(WEAVE_ERROR err)\n+{\n+    InEventParam inParam;\n+    OutEventParam outParam;\n+\n+    inParam.Clear();\n+    outParam.Clear();\n+    inParam.Source = this;\n+    inParam.CommunicationError.Reason = err;\n+\n+    mEventCallback(AppState, kEvent_CommunicationError, inParam, outParam);\n+}\n+\n+/**\n+ * Process an event delivered from the binding associated with a WeaveCertProvEngine.\n+ */\n+void WeaveCertProvEngine::HandleBindingEvent(void * const appState, const Binding::EventType eventType, const Binding::InEventParam & inParam,\n+                                             Binding::OutEventParam & outParam)\n+{\n+    WeaveCertProvEngine * client = (WeaveCertProvEngine *)appState;\n+\n+    switch (eventType)\n+    {\n+    case Binding::kEvent_BindingReady:\n+\n+        // When the binding is ready, if the client is still in the PreparingBinding state,\n+        // initiate sending of a GetCertificateRequest.\n+        if (client->mState == kState_PreparingBinding)\n+        {\n+            client->mState = kState_Idle;\n+\n+            client->SendGetCertificateRequest();\n+        }\n+\n+        break;\n+\n+    case Binding::kEvent_PrepareFailed:\n+\n+        // If binding preparation fails and the client is still in the PreparingBinding state...\n+        if (client->mState == kState_PreparingBinding)\n+        {\n+            // Clean-up the request state and enter Idle state.\n+            client->HandleRequestDone();\n+\n+            // Deliver a CommunicationError API event to the application.\n+            client->DeliverCommunicationError(inParam.PrepareFailed.Reason);\n+        }\n+\n+        break;\n+\n+    default:\n+        Binding::DefaultEventHandler(appState, eventType, inParam, outParam);\n+    }\n+}\n+\n+/**\n+ * Called by the Weave messaging layer when a response is received on an GetCertificate exchange.\n+ */\n+void WeaveCertProvEngine::HandleResponse(ExchangeContext * ec, const IPPacketInfo * pktInfo, const WeaveMessageInfo * msgInfo, uint32_t profileId, uint8_t msgType, PacketBuffer * msgBuf)\n+{\n+    WeaveCertProvEngine * client = (WeaveCertProvEngine *)ec->AppState;\n+\n+    VerifyOrDie(client->mState == kState_RequestInProgress);\n+    VerifyOrDie(client->mEC == ec);\n+\n+    // Process status report message from the CA service.\n+    if (profileId == kWeaveProfile_Common && msgType == Common::kMsgType_StatusReport)\n+    {\n+        StatusReport statusReport;\n+        WEAVE_ERROR parseErr = StatusReport::parse(msgBuf, statusReport);\n+\n+        // Free the received message buffer so that it can be reused to initiate additional communication.\n+        PacketBuffer::Free(msgBuf);\n+        msgBuf = NULL;\n+\n+        SuccessOrExit(parseErr);\n+\n+        VerifyOrExit(statusReport.mProfileId == kWeaveProfile_Security, /* no-op */);\n+\n+        InEventParam inParam;\n+        OutEventParam outParam;\n+        inParam.Clear();\n+        outParam.Clear();\n+        inParam.Source = client;\n+\n+        if (statusReport.mStatusCode == Security::kStatusCode_NoNewCertRequired)\n+        {\n+            inParam.ResponseReceived.ReplaceCert = false;\n+\n+            // Deliver a ResponseReceived API event to the application.\n+            client->mEventCallback(client->AppState, kEvent_ResponseReceived, inParam, outParam);\n+        }\n+        else\n+        {\n+            inParam.CommunicationError.Reason = WEAVE_ERROR_STATUS_REPORT_RECEIVED;\n+            inParam.CommunicationError.RcvdStatusReport = &statusReport;\n+\n+            // Deliver a CommunicationError API event to the application.\n+            client->mEventCallback(client->AppState, kEvent_CommunicationError, inParam, outParam);\n+        }\n+    }\n+\n+    // Process GetCertificateResponse message from the CA service.\n+    else if (profileId == kWeaveProfile_Security && msgType == kMsgType_GetCertificateResponse)\n+    {\n+        // If the request is now complete, clear the request state and enter Idle state.\n+        client->HandleRequestDone();","path":"src/lib/profiles/security/WeaveCertProvisioning.cpp","position":608,"original_position":604,"commit_id":"9eec466fd230c3f013c0fe83b9ce15d55c31ab2b","original_commit_id":"2eba727ad7ed4db78cdb4c18db5db140d6e5beab","user":{"login":"emargolis","id":13021231,"node_id":"MDQ6VXNlcjEzMDIxMjMx","avatar_url":"https://avatars1.githubusercontent.com/u/13021231?v=4","gravatar_id":"","url":"https://api.github.com/users/emargolis","html_url":"https://github.com/emargolis","followers_url":"https://api.github.com/users/emargolis/followers","following_url":"https://api.github.com/users/emargolis/following{/other_user}","gists_url":"https://api.github.com/users/emargolis/gists{/gist_id}","starred_url":"https://api.github.com/users/emargolis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emargolis/subscriptions","organizations_url":"https://api.github.com/users/emargolis/orgs","repos_url":"https://api.github.com/users/emargolis/repos","events_url":"https://api.github.com/users/emargolis/events{/privacy}","received_events_url":"https://api.github.com/users/emargolis/received_events","type":"User","site_admin":false},"body":"done","created_at":"2020-01-09T00:25:46Z","updated_at":"2020-01-09T00:25:46Z","html_url":"https://github.com/openweave/openweave-core/pull/455#discussion_r364509206","pull_request_url":"https://api.github.com/repos/openweave/openweave-core/pulls/455","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/openweave/openweave-core/pulls/comments/364509206"},"html":{"href":"https://github.com/openweave/openweave-core/pull/455#discussion_r364509206"},"pull_request":{"href":"https://api.github.com/repos/openweave/openweave-core/pulls/455"}},"in_reply_to_id":363909109},"pull_request":{"url":"https://api.github.com/repos/openweave/openweave-core/pulls/455","id":352705223,"node_id":"MDExOlB1bGxSZXF1ZXN0MzUyNzA1MjIz","html_url":"https://github.com/openweave/openweave-core/pull/455","diff_url":"https://github.com/openweave/openweave-core/pull/455.diff","patch_url":"https://github.com/openweave/openweave-core/pull/455.patch","issue_url":"https://api.github.com/repos/openweave/openweave-core/issues/455","number":455,"state":"open","locked":false,"title":"Implemented Certificate Provisioning Protocol Engine.","user":{"login":"emargolis","id":13021231,"node_id":"MDQ6VXNlcjEzMDIxMjMx","avatar_url":"https://avatars1.githubusercontent.com/u/13021231?v=4","gravatar_id":"","url":"https://api.github.com/users/emargolis","html_url":"https://github.com/emargolis","followers_url":"https://api.github.com/users/emargolis/followers","following_url":"https://api.github.com/users/emargolis/following{/other_user}","gists_url":"https://api.github.com/users/emargolis/gists{/gist_id}","starred_url":"https://api.github.com/users/emargolis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/emargolis/subscriptions","organizations_url":"https://api.github.com/users/emargolis/orgs","repos_url":"https://api.github.com/users/emargolis/repos","events_url":"https://api.github.com/users/emargolis/events{/privacy}","received_events_url":"https://api.github.com/users/emargolis/received_events","type":"User","site_admin":false},"body":"  -- Defined abstract interface object (WeaveNodeOpAuthDelegate)\r\n     to which platform specific actions are delegated during\r\n     Weave node operational authentication.\r\n  -- Defined abstract interface object (WeaveNodeManufAttestDelegate)\r\n     to which platform specific actions are delegated during\r\n     Weave node manufacturer attestation.\r\n  -- Defined and implemented certificate provisioning engine, used to\r\n     get new Weave operational device certificate from the CA service.","created_at":"2019-12-13T03:27:07Z","updated_at":"2020-01-09T00:25:46Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6f39f16d22f0c251828e042e76eb7ead4dfa530e","assignee":null,"assignees":[],"requested_reviewers":[{"login":"gerickson","id":380979,"node_id":"MDQ6VXNlcjM4MDk3OQ==","avatar_url":"https://avatars2.githubusercontent.com/u/380979?v=4","gravatar_id":"","url":"https://api.github.com/users/gerickson","html_url":"https://github.com/gerickson","followers_url":"https://api.github.com/users/gerickson/followers","following_url":"https://api.github.com/users/gerickson/following{/other_user}","gists_url":"https://api.github.com/users/gerickson/gists{/gist_id}","starred_url":"https://api.github.com/users/gerickson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gerickson/subscriptions","organizations_url":"https://api.github.com/users/gerickson/orgs","repos_url":"https://api.github.com/users/gerickson/repos","events_url":"https://api.github.com/users/gerickson/events{/privacy}","received_events_url":"https://api.github.com/users/gerickson/received_events","type":"User","site_admin":false},{"login":"robszewczyk","id":4296188,"node_id":"MDQ6VXNlcjQyOTYxODg=","avatar_url":"https://avatars0.githubusercontent.com/u/4296188?v=4","gravatar_id":"","url":"https://api.github.com/users/robszewczyk","html_url":"https://github.com/robszewczyk","followers_url":"https://api.github.com/users/robszewczyk/followers","following_url":"https://api.github.com/users/robszewczyk/following{/other_user}","gists_url":"https://api.github.com/users/robszewczyk/gists{/gist_id}","starred_url":"https://api.github.com/users/robszewczyk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robszewczyk/subscriptions","organizations_url":"https://api.github.com/users/robszewczyk/orgs","repos_url":"https://api.github.com/users/robszewczyk/repos","events_url":"https://api.github.com/users/robszewczyk/events{/privacy}","received_events_url":"https://api.github.com/users/robszewczyk/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/openweave/openweave-core/pulls/455/commits","review_comments_url":"https://api.github.com/repos/openweave/openweave-core/pulls/455/comments","review_comment_url":"https://api.github.com/repos/openweave/openweave-core/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openweave/openweave-core/issues/455/comments","statuses_url":"https://api.github.com/repos/openweave/openweave-core/statuses/9eec466fd230c3f013c0fe83b9ce15d55c31ab2b","head":{"label":"openweave:feature/emargolis/cert-prov-protocol","ref":"feature/emargolis/cert-prov-protocol","sha":"9eec466fd230c3f013c0fe83b9ce15d55c31ab2b","user":{"login":"openweave","id":29963994,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5OTYzOTk0","avatar_url":"https://avatars2.githubusercontent.com/u/29963994?v=4","gravatar_id":"","url":"https://api.github.com/users/openweave","html_url":"https://github.com/openweave","followers_url":"https://api.github.com/users/openweave/followers","following_url":"https://api.github.com/users/openweave/following{/other_user}","gists_url":"https://api.github.com/users/openweave/gists{/gist_id}","starred_url":"https://api.github.com/users/openweave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openweave/subscriptions","organizations_url":"https://api.github.com/users/openweave/orgs","repos_url":"https://api.github.com/users/openweave/repos","events_url":"https://api.github.com/users/openweave/events{/privacy}","received_events_url":"https://api.github.com/users/openweave/received_events","type":"Organization","site_admin":false},"repo":{"id":101915019,"node_id":"MDEwOlJlcG9zaXRvcnkxMDE5MTUwMTk=","name":"openweave-core","full_name":"openweave/openweave-core","private":false,"owner":{"login":"openweave","id":29963994,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5OTYzOTk0","avatar_url":"https://avatars2.githubusercontent.com/u/29963994?v=4","gravatar_id":"","url":"https://api.github.com/users/openweave","html_url":"https://github.com/openweave","followers_url":"https://api.github.com/users/openweave/followers","following_url":"https://api.github.com/users/openweave/following{/other_user}","gists_url":"https://api.github.com/users/openweave/gists{/gist_id}","starred_url":"https://api.github.com/users/openweave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openweave/subscriptions","organizations_url":"https://api.github.com/users/openweave/orgs","repos_url":"https://api.github.com/users/openweave/repos","events_url":"https://api.github.com/users/openweave/events{/privacy}","received_events_url":"https://api.github.com/users/openweave/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/openweave/openweave-core","description":"openWeave is a home area network application protocol stack designed to enable asynchronous, symmetric, device-to-device, device-to-mobile and device-to-cloud communications for control path and data path messaging. ","fork":false,"url":"https://api.github.com/repos/openweave/openweave-core","forks_url":"https://api.github.com/repos/openweave/openweave-core/forks","keys_url":"https://api.github.com/repos/openweave/openweave-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openweave/openweave-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openweave/openweave-core/teams","hooks_url":"https://api.github.com/repos/openweave/openweave-core/hooks","issue_events_url":"https://api.github.com/repos/openweave/openweave-core/issues/events{/number}","events_url":"https://api.github.com/repos/openweave/openweave-core/events","assignees_url":"https://api.github.com/repos/openweave/openweave-core/assignees{/user}","branches_url":"https://api.github.com/repos/openweave/openweave-core/branches{/branch}","tags_url":"https://api.github.com/repos/openweave/openweave-core/tags","blobs_url":"https://api.github.com/repos/openweave/openweave-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openweave/openweave-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openweave/openweave-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/openweave/openweave-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openweave/openweave-core/statuses/{sha}","languages_url":"https://api.github.com/repos/openweave/openweave-core/languages","stargazers_url":"https://api.github.com/repos/openweave/openweave-core/stargazers","contributors_url":"https://api.github.com/repos/openweave/openweave-core/contributors","subscribers_url":"https://api.github.com/repos/openweave/openweave-core/subscribers","subscription_url":"https://api.github.com/repos/openweave/openweave-core/subscription","commits_url":"https://api.github.com/repos/openweave/openweave-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/openweave/openweave-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/openweave/openweave-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/openweave/openweave-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/openweave/openweave-core/contents/{+path}","compare_url":"https://api.github.com/repos/openweave/openweave-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openweave/openweave-core/merges","archive_url":"https://api.github.com/repos/openweave/openweave-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openweave/openweave-core/downloads","issues_url":"https://api.github.com/repos/openweave/openweave-core/issues{/number}","pulls_url":"https://api.github.com/repos/openweave/openweave-core/pulls{/number}","milestones_url":"https://api.github.com/repos/openweave/openweave-core/milestones{/number}","notifications_url":"https://api.github.com/repos/openweave/openweave-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openweave/openweave-core/labels{/name}","releases_url":"https://api.github.com/repos/openweave/openweave-core/releases{/id}","deployments_url":"https://api.github.com/repos/openweave/openweave-core/deployments","created_at":"2017-08-30T18:22:10Z","updated_at":"2020-01-08T00:13:39Z","pushed_at":"2020-01-09T00:25:37Z","git_url":"git://github.com/openweave/openweave-core.git","ssh_url":"git@github.com:openweave/openweave-core.git","clone_url":"https://github.com/openweave/openweave-core.git","svn_url":"https://github.com/openweave/openweave-core","homepage":null,"size":49685,"stargazers_count":143,"watchers_count":143,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":65,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":60,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":65,"open_issues":60,"watchers":143,"default_branch":"master"}},"base":{"label":"openweave:master","ref":"master","sha":"f65c03474f52ba6592d943d5ed2d050269ffebee","user":{"login":"openweave","id":29963994,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5OTYzOTk0","avatar_url":"https://avatars2.githubusercontent.com/u/29963994?v=4","gravatar_id":"","url":"https://api.github.com/users/openweave","html_url":"https://github.com/openweave","followers_url":"https://api.github.com/users/openweave/followers","following_url":"https://api.github.com/users/openweave/following{/other_user}","gists_url":"https://api.github.com/users/openweave/gists{/gist_id}","starred_url":"https://api.github.com/users/openweave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openweave/subscriptions","organizations_url":"https://api.github.com/users/openweave/orgs","repos_url":"https://api.github.com/users/openweave/repos","events_url":"https://api.github.com/users/openweave/events{/privacy}","received_events_url":"https://api.github.com/users/openweave/received_events","type":"Organization","site_admin":false},"repo":{"id":101915019,"node_id":"MDEwOlJlcG9zaXRvcnkxMDE5MTUwMTk=","name":"openweave-core","full_name":"openweave/openweave-core","private":false,"owner":{"login":"openweave","id":29963994,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI5OTYzOTk0","avatar_url":"https://avatars2.githubusercontent.com/u/29963994?v=4","gravatar_id":"","url":"https://api.github.com/users/openweave","html_url":"https://github.com/openweave","followers_url":"https://api.github.com/users/openweave/followers","following_url":"https://api.github.com/users/openweave/following{/other_user}","gists_url":"https://api.github.com/users/openweave/gists{/gist_id}","starred_url":"https://api.github.com/users/openweave/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openweave/subscriptions","organizations_url":"https://api.github.com/users/openweave/orgs","repos_url":"https://api.github.com/users/openweave/repos","events_url":"https://api.github.com/users/openweave/events{/privacy}","received_events_url":"https://api.github.com/users/openweave/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/openweave/openweave-core","description":"openWeave is a home area network application protocol stack designed to enable asynchronous, symmetric, device-to-device, device-to-mobile and device-to-cloud communications for control path and data path messaging. ","fork":false,"url":"https://api.github.com/repos/openweave/openweave-core","forks_url":"https://api.github.com/repos/openweave/openweave-core/forks","keys_url":"https://api.github.com/repos/openweave/openweave-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openweave/openweave-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openweave/openweave-core/teams","hooks_url":"https://api.github.com/repos/openweave/openweave-core/hooks","issue_events_url":"https://api.github.com/repos/openweave/openweave-core/issues/events{/number}","events_url":"https://api.github.com/repos/openweave/openweave-core/events","assignees_url":"https://api.github.com/repos/openweave/openweave-core/assignees{/user}","branches_url":"https://api.github.com/repos/openweave/openweave-core/branches{/branch}","tags_url":"https://api.github.com/repos/openweave/openweave-core/tags","blobs_url":"https://api.github.com/repos/openweave/openweave-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openweave/openweave-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openweave/openweave-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/openweave/openweave-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openweave/openweave-core/statuses/{sha}","languages_url":"https://api.github.com/repos/openweave/openweave-core/languages","stargazers_url":"https://api.github.com/repos/openweave/openweave-core/stargazers","contributors_url":"https://api.github.com/repos/openweave/openweave-core/contributors","subscribers_url":"https://api.github.com/repos/openweave/openweave-core/subscribers","subscription_url":"https://api.github.com/repos/openweave/openweave-core/subscription","commits_url":"https://api.github.com/repos/openweave/openweave-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/openweave/openweave-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/openweave/openweave-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/openweave/openweave-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/openweave/openweave-core/contents/{+path}","compare_url":"https://api.github.com/repos/openweave/openweave-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openweave/openweave-core/merges","archive_url":"https://api.github.com/repos/openweave/openweave-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openweave/openweave-core/downloads","issues_url":"https://api.github.com/repos/openweave/openweave-core/issues{/number}","pulls_url":"https://api.github.com/repos/openweave/openweave-core/pulls{/number}","milestones_url":"https://api.github.com/repos/openweave/openweave-core/milestones{/number}","notifications_url":"https://api.github.com/repos/openweave/openweave-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openweave/openweave-core/labels{/name}","releases_url":"https://api.github.com/repos/openweave/openweave-core/releases{/id}","deployments_url":"https://api.github.com/repos/openweave/openweave-core/deployments","created_at":"2017-08-30T18:22:10Z","updated_at":"2020-01-08T00:13:39Z","pushed_at":"2020-01-09T00:25:37Z","git_url":"git://github.com/openweave/openweave-core.git","ssh_url":"git@github.com:openweave/openweave-core.git","clone_url":"https://github.com/openweave/openweave-core.git","svn_url":"https://github.com/openweave/openweave-core","homepage":null,"size":49685,"stargazers_count":143,"watchers_count":143,"language":"C++","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":65,"mirror_url":null,"archived":false,"disabled":false,"open_issues_count":60,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":65,"open_issues":60,"watchers":143,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openweave/openweave-core/pulls/455"},"html":{"href":"https://github.com/openweave/openweave-core/pull/455"},"issue":{"href":"https://api.github.com/repos/openweave/openweave-core/issues/455"},"comments":{"href":"https://api.github.com/repos/openweave/openweave-core/issues/455/comments"},"review_comments":{"href":"https://api.github.com/repos/openweave/openweave-core/pulls/455/comments"},"review_comment":{"href":"https://api.github.com/repos/openweave/openweave-core/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openweave/openweave-core/pulls/455/commits"},"statuses":{"href":"https://api.github.com/repos/openweave/openweave-core/statuses/9eec466fd230c3f013c0fe83b9ce15d55c31ab2b"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"emargolis"}}