This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

What does this "prov_utils_confirmation_check" function do??

Hi, a little background information first, when debugging ble mesh example 0.9.x:

devzone.nordicsemi.com/.../

I'm now kinda having a massive problem with this function:

bool prov_utils_confirmation_check(const prov_common_ctx_t * p_ctx)
{
uint8_t confirmation_key[NRF_MESH_KEY_SIZE];

/* ConfirmationKey = k1(ECDHSecret, ConfirmationSalt, "prck") */
enc_k1(p_ctx->shared_secret,
       NRF_MESH_ECDH_SHARED_SECRET_SIZE,
       p_ctx->confirmation_salt,
       CONFIRMATION_KEY_INFO, CONFIRMATION_KEY_INFO_LENGTH,
       confirmation_key);

uint8_t random_and_auth[PROV_RANDOM_LEN + PROV_AUTH_LEN];
memcpy(&random_and_auth[0], p_ctx->peer_random, PROV_RANDOM_LEN);
memcpy(&random_and_auth[PROV_RANDOM_LEN], p_ctx->auth_value, PROV_AUTH_LEN);

/* Confirmation value = AES-CMAC(ConfirmationKey, LocalRandom || AuthValue) */
uint8_t confirmation[PROV_CONFIRMATION_LEN];
enc_aes_cmac(confirmation_key,
             random_and_auth,
             PROV_RANDOM_LEN + PROV_AUTH_LEN,
             confirmation);

//int result = memcmp(confirmation, p_ctx->peer_confirmation, sizeof(confirmation)) == 0;
  int result = memcmp(confirmation, p_ctx->peer_confirmation, sizeof(confirmation));
	return result;
}

My question are these:

#Question No.1

The function in question gets called in :

case PROV_PDU_TYPE_RANDOM

But what does this case mean? Why would there be a "RANDOM" payload unit? I completely failed to get the point. For encryption purposes?

#Question No.2

I'm completely lost on these lines:

uint8_t random_and_auth[PROV_RANDOM_LEN + PROV_AUTH_LEN];
memcpy(&random_and_auth[0], p_ctx->peer_random, PROV_RANDOM_LEN);
memcpy(&random_and_auth[PROV_RANDOM_LEN], p_ctx->auth_value, PROV_AUTH_LEN);

And

memcmp(confirmation, p_ctx->peer_confirmation, sizeof(confirmation));

The only possible explanation I can think of is this:

  1. Provisioner send me (provisionee) a random payload (thus "case PROV_PDU_TYPE_RANDOM") which somehow I knew what it is.
  2. In the same payload, provisioner also managed to slip in some confirmation information.
  3. I perform an encryption operation based on the confirmation information provisoner sent me, and come up independently with my own results.
  4. I compare the results with the result I should GET which provisioner sent me and see if the two are completely identical. If they are, then great I can proceed further because no future problem will emerge in our encrypted communications, if not, then I stop because I will not properly decode whatever message provisioner send me.

Is my guess correct? If not, what is it really for?

The result of this function is consistently "-86", can anyone shed some light???

Parents
  • Hi Mitch,

    I would look at the Provisioning documentation or the provisioning protocol in the Mesh Profile specification if you want to understand the provisioning process better.

    In short, the confirmation check is to check that the provisioner/provisionee authenticated correctly against its peer, i.e., that the ECDH key exchange was successful and correctly authenticates against the OOB data. The below figure from Wikipedia explains it pretty well. The secret colours in the figure is the private keys and the common paint the OOB data.

    Key exchange

    Specifically to the issue you're facing, my best guess is that there is an error in handling one of the provisioning events. The Light Control example uses static OOB data. Is this the same for both of your nodes?

    Hope this helps,
    Thomas

Reply
  • Hi Mitch,

    I would look at the Provisioning documentation or the provisioning protocol in the Mesh Profile specification if you want to understand the provisioning process better.

    In short, the confirmation check is to check that the provisioner/provisionee authenticated correctly against its peer, i.e., that the ECDH key exchange was successful and correctly authenticates against the OOB data. The below figure from Wikipedia explains it pretty well. The secret colours in the figure is the private keys and the common paint the OOB data.

    Key exchange

    Specifically to the issue you're facing, my best guess is that there is an error in handling one of the provisioning events. The Light Control example uses static OOB data. Is this the same for both of your nodes?

    Hope this helps,
    Thomas

Children
  • Hello @thomasstenersen, I read through (what I believed to be) the relevant code and nothing seems to be out of the ordinary, except for a disparity in "num_elements". The code is as follows:

    #Provisionee: nrf_mesh_prov_oob_caps_t capabilities = {0}; capabilities.num_elements = ACCESS_ELEMENT_COUNT; capabilities.algorithms = NRF_MESH_PROV_ALGORITHM_FIPS_P256EC; capabilities.oob_static_types = NRF_MESH_PROV_OOB_STATIC_TYPE_SUPPORTED;

    ERROR_CHECK(nrf_mesh_prov_generate_keys(public_key, private_key));
    ERROR_CHECK(nrf_mesh_prov_init(&m_prov_ctx, public_key, private_key, &capabilities));
    

    #Provisioner:

  • code:

    nrf_mesh_prov_oob_caps_t capabilities = {0};
    capabilities.algorithms = NRF_MESH_PROV_ALGORITHM_FIPS_P256EC;
    capabilities.oob_static_types = NRF_MESH_PROV_OOB_STATIC_TYPE_SUPPORTED;
    ERROR_CHECK(nrf_mesh_prov_init(&m_prov_ctx, m_public_key, m_private_key, &capabilities));
    ERROR_CHECK(nrf_mesh_prov_provision(&m_prov_ctx, p_uuid, &prov_data, NRF_MESH_PROV_BEARER_ADV));
    m_prov_state = PROV_STATE_PROV;
    

    As you can see, both enabled OOB Auth. Could it be they aren't using the keys they SHOULD be using?

  • Have a look at the handling of the NRF_MESH_EVT_PROV_CAPS_RECEIVEDon the provisioner and the NRF_MESH_EVT_PROV_STATIC_REQUEST on both. Is the STATIC_AUTH_DATA identical?

    From examples/light_control/client/src/provisioner.c:

        case NRF_MESH_EVT_PROV_STATIC_REQUEST:
        {
            uint8_t static_data[16] = STATIC_AUTH_DATA;
            ERROR_CHECK(nrf_mesh_prov_auth_data_provide(p_evt->params.prov_static_request.p_context, static_data, 16));
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Static authentication data provided\n");
            break;
        }
    
    • Thomas
  • Hello Thomas, in the case of "NRF_MESH_EVT_PROV_CAPS_RECEIVED", I'm not sure what you wanted me to check and there is no "STATIC_AUTH_DATA";

    the static auth data for provisioner is this:

    #define STATIC_AUTH_DATA {0}
    

    and for provisionee is this:

    #define STATIC_AUTH_DATA { 0xc7, 0xf7, 0x9b, 0xec, 0x9c, 0xf9, 0x74, 0xdd, 0xb9, 0x62, 0xbd, 0x9f, 0xd1, 0x72, 0xdd, 0x73 }
    

    looks like you found the problem? What should I do next? Copy provisionee's to provisioners and make them the same???

  • LOL I feel like a fool, in your original post, by "are they the same" you mean are the auth data the same, I thought you meant "are they both using OOB auth" hahaha.

Related