Challenge-Response API

The challenge-response API lets a device authenticate a peer that holds its master key. It is enabled with CONFIG_HUBBLE_CHALLENGE.

group Challenge-Response APIs

Hubble Challenge-Response APIs.

Lets the device authenticate a peer that holds its master key, for example the Hubble Cloud or a service acting on its behalf.

The application picks a nonce and builds a challenge from it with hubble_challenge_get, then sends the challenge to the peer over any transport. The challenge carries the device’s current EID in plain bytes, so the peer can look up the device and its key the same way it resolves an advertisement. The peer computes the response and sends it back, and the application checks it with hubble_challenge_response_check.

Challenge layout (HUBBLE_CHALLENGE_SIZE bytes):

| offset | size | field                                       |
|--------+------+---------------------------------------------|
| 0      | 1    | version (HUBBLE_CHALLENGE_VERSION)          |
| 1      | 4    | EID, same bytes as the BLE advertisement    |
| 5      | 16   | nonce supplied by the application           |

The response (HUBBLE_CHALLENGE_RESPONSE_SIZE bytes) is derived with the NIST SP 800-108 counter mode KDF, AES-CMAC as PRF, the same function the SDK uses for its other derived keys and values:

challenge_key = KDF(master_key, "ChallengeKey",
                    decimal(time_counter), key_len)
response      = KDF(challenge_key, "Response", challenge, 16)

where time_counter is the counter the EID was derived from.

The SDK keeps no state between the two calls. Replay protection is the application’s job: the nonce must be unpredictable, and a response must be accepted at most once for a given nonce.

Defines

HUBBLE_CHALLENGE_VERSION

Version of the challenge format.

HUBBLE_CHALLENGE_NONCE_SIZE

Size of the nonce carried in the challenge in bytes.

HUBBLE_CHALLENGE_SIZE

Size of a challenge in bytes.

HUBBLE_CHALLENGE_RESPONSE_SIZE

Size of a challenge response in bytes.

Functions

int hubble_challenge_get(const uint8_t *nonce, size_t nonce_len, uint8_t *challenge, size_t *len)

Build a challenge from a nonce.

Writes the challenge for the current time counter: version, current EID and nonce.

Parameters:
  • nonce – Nonce chosen by the application, it should come from a cryptographically secure random number generator.

  • nonce_len – Length of nonce in bytes, must be HUBBLE_CHALLENGE_NONCE_SIZE.

  • challenge – Output buffer of at least HUBBLE_CHALLENGE_SIZE bytes.

  • len – in: Size of challenge in bytes. out: Number of bytes written.

Return values:
  • 0 – Challenge built.

  • -EINVAL – A pointer is NULL, nonce_len is wrong, len is too small or no key is set.

  • <0 – Negative errno from the time counter or the crypto provider.

int hubble_challenge_response_check(const uint8_t *challenge, size_t challenge_len, const uint8_t *response, size_t response_len)

Check the response to a challenge.

Compares response with the value expected for challenge. The challenge must have been built by hubble_challenge_get in the current EID rotation period.

Parameters:
Return values:
  • 0 – The response matches, the peer holds the device key.

  • -EINVAL – A pointer is NULL, a length is wrong, the challenge version is unknown or no key is set.

  • -ETIMEDOUT – The EID rotated since the challenge was built, build a new one.

  • -EACCES – The response does not match.

  • <0 – Negative errno from the time counter or the crypto provider.