Skip to content

Instantly share code, notes, and snippets.

@michpappas
Created May 1, 2018 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save michpappas/cdc983a576c67a92a178b2f70343ae0d to your computer and use it in GitHub Desktop.
Save michpappas/cdc983a576c67a92a178b2f70343ae0d to your computer and use it in GitHub Desktop.
/*
* Copyright 2017, Linaro Ltd and contributors
* SPDX-License-Identifier: Apache-2.0
*/
#define S96_AT_STATUS_OK 0x00
#define S96_AT_STATUS_CHECKMAC_FAIL 0x01
#define S96_AT_STATUS_EXEC_ERROR 0x0f
#define S96AT_CHALLENGE_LEN 32
#define S96AT_HMAC_LEN 32
#define S96AT_MAC_LEN 32
#define S96AT_NONCE_PASSTHRU_LEN 32
#define S96AT_RANDOM_LEN 32
#define S96AT_SHA_LEN 32
/* Nonce flags */
#define S96AT_FLAG_UPDATE_SEED 0x00
#define S96AT_FLAG_NO_UPDATE_SEED 0x01
/* MAC / CheckMAC / HMAC flags */
#define S96AT_FLAG_USE_OTP_LOW_BYTES 0x00 /* Use OTP[0:7] */
#define S96AT_FLAG_USE_OTP_HIGH_BYTES 0x01 /* Use OTP[8:10] */
#define S96AT_FLAG_USE_SN_LOW_BYTES 0x02 /* Use OTP[2:3] */
#define S96AT_FLAG_USE_SN_HIGH_BYTES 0x04 /* Use OTP[4:7] */
/* Check a MAC generated by ATSHA208A / ATECC508A
*
* Generates a MAC and compares it with the value stored in the mac buffer.
* This is normally used to verify a MAC generated using s96at_get_mac()
* during a host-client communication.
*
* For more information on the input parameters see s96at_get_mac()
*
* Upon success S96AT_STATUS_OK is returned. A failed comparison
* returns S96_STATUS_CHECKMAC_FAIL.
*/
int s96at_check_mac(struct io_interface *ioif, uint8_t slotid,
uint8_t challenge[S96AT_CHALLENGE_LEN], uint32_t flags,
uint8_t random[S96AT_RANDOM_LEN], uint8_t mac[S96AT_MAC_LEN]);
/* Derive a key
*
* Derives a new key by combining the value stored in a slot with a nonce
* and storing its SHA256 hash into the target slot. Depending on how the
* target slot is configured, this function will use the appropriate input
* key:
* - For slots configured into Create mode, the parent key is used.
* - For slots configured into Rolling mode, the current key is used.
*
* If required by the configuration, an authorizing MAC is sent along
* too.
*/
int s96at_derive_key(struct io_interface *ioif, uint8_t slotid);
/* Generate a digest
*
* Generate a SHA-256 digest combining the value stored in TempKey with
* a value stored in the device. The input value is defined by the zone
* and slot parameters. The value of data must be NULL.
*
* For keys configured as CheckOnly, it is possible to generate the
* digest using the value stored in the data buffer instead of a value
* stored in the device. This is normally used to generate euphemeral
* keys. When this operation is required, a pointer must be passed to the
* data parameter pointing to a buffer that contains the input data. In
* this case, the zone and slotid values are ignored.
*
* In both cases, the generated digest is stored in TempKey and it can
* be used to combine the Nonce with an additional value before executing
* the MAC / CheckMAC / HMAC commands.
*/
int s96at_gen_digest(struct io_interface *ioif, uint8_t zone, uint8_t slotid,
uint8_t data[4]);
/* Generate an HMAC-SHA256
*
* Generates an HMAC-SHA256. The HMAC is generated by first running
* Nonce in Random mode to combine the input challenge with a random
* number. That number is then combined along with the key stored
* in slotid to generate an HMAC. The resulting HMAC and the value
* produced by the RNG are written to the mac and random buffers
* respectively.
*
* Flags control whether other intput values should be included in
* the hashed message. These are:
*
* S96AT_FLAG_USE_OTP_LOW_BYTES Use OTP[0:7]
* S96AT_FLAG_USE_OTP_HIGH_BYTES Use OTP[8:10]
* S96AT_FLAG_USE_SN_LOW_BYTES Use OTP[2:3]
* S96AT_FLAG_USE_SN_HIGH_BYTES Use OTP[4:7]
*
* If challenge is NULL, it is assumed that TempKey has already
* been populated and only the MAC command is sent to the device.
*
* Notice that this function does not execute GenDig after running Nonce.
* To achieve that functionality, a Nonce followed by GenMac must be
* executed manually to populate TempKey and challenge must be set to NULL.
* The random buffer is then not populated.
*/
int s96at_get_hmac(struct io_interface *ioif, uint8_t slotid,
uint8_t challenge[S96AT_CHALLENGE_LEN], uint32_t flags,
uint8_t random[S96AT_RANDOM_LEN], uint8_t hmac[S96AT_HMAC_LEN]);
/* Get the lock status of the Config Zone
*
* Reads the lock status of the Config Zone into lock_config.
* Possible values:
* - S96AT_LOCK_CONFIG_LOCKED
* - S96AT_LOCK_CONFIG_UNLOCKED
*/
int s96at_get_lock_config(struct io_interface *ioif, uint8_t *lock_config);
/* Get the lock status of the Data Zone
*
* Reads the lock status of the Data Zone into lock_data.
* Possible values:
* - S96AT_LOCK_DATA_LOCKED
* - S96AT_LOCK_DATA_UNLOCKED
*/
int s96at_get_lock_data(struct io_interface *ioif, uint8_t *lock_data);
/* Get the lock status of the OTP Zone
*
* Reads the lock status of the OTP Zone into lock_otp.
* Possible values:
* - S96AT_LOCK_OTP_LOCKED
* - S96AT_LOCK_OTP_UNLOCKED
*/
int s96at_get_lock_otp(struct io_interface *ioif, uint8_t *lock_otp);
/* Generate a MAC
*
* Generates a MAC. The MAC is generated by first running Nonce in
* Random mode to combine the input challenge with a random number.
* That number is then combined along with the key stored in slotid
* to generate a MAC. The resulting HMAC and the value produced by
* the RNG are written to the mac and random buffers respectively.
*
* Flags control whether other intput values should be included in
* the hashed message. These are:
*
* S96AT_FLAG_USE_OTP_LOW_BYTES Use OTP[0:7]
* S96AT_FLAG_USE_OTP_HIGH_BYTES Use OTP[8:10]
* S96AT_FLAG_USE_SN_LOW_BYTES Use OTP[2:3]
* S96AT_FLAG_USE_SN_HIGH_BYTES Use OTP[4:7]
*
* If challenge is NULL, it is assumed that TempKey has already
* been populated and only the MAC command is sent to the device.
*
* Notice that this function does not execute GenDig after running Nonce.
* To achieve that functionality, a Nonce followed by GenMac must be
* executed manually to populate TempKey and challenge must be set to NULL.
* The random buffer is then not populated.
*/
int s96at_get_mac(struct io_interface *ioif, uint8_t slotid,
uint8_t challenge[S96AT_CHALLENGE_LEN], uint32_t flags,
uint8_t random[S96AT_RANDOM_LEN], uint8_t mac[S96AT_MAC_LEN]);
/* Generate a nonce
*
* Generates a nonce. If data is NULL, operate in Pass-Through Mode.
* The input value in the data buffer is stored directly in TempKey.
*
* If data is not NULL then operate in Random Mode, ie combine the
* input value with a random number and store the resulting hash
* in TempKey.
*
* When Random Mode is used, the default behaviour is to update
* the seed before generating the random number. This behaviour
* can be overriden by passing the S96AT_FLAG_NO_UPDATE_SEED flag.
*
* Stores the value produced by the RNG in buf.
*/
int s96at_get_nonce(struct io_interface *ioif, uint8_t data[S96AT_NONCE_PASSTHRU_LEN],
uint8_t random[S96AT_RANDOM_LEN], uint32_t flags);
/* Get the OTP Mode
*
* Reads the OTP Mode into otp_mode. Possible values are:
* - S96AT_OTP_MODE_CONSUMPTION
* - S96AT_OTP_MODE_LEGACY
* - S96AT_OTP_MODE_READ_ONLY
*/
int s96at_get_otp_mode(struct io_interface *ioif, uint8_t *opt_mode);
/* Send Pause command
*
* Upon receiving the Pause command, devices with Selector byte in the
* EEPROM not matching the selector parameter will enter the Idle State.
*/
int s96at_pause(struct io_interface *ioif, uint8_t selector);
/* Generate a random number
*
* Random numbers are generated by combining the output of a hardware RNG
* with a seed value. The generated number is stored in random buffer.
*
* Before generating a new number, the interal seed is updated by default.
* This can be overriden by passing the S96AT_FLAG_NO_UPDATE_SEED flag.
*/
int s96at_get_random(struct io_interface *ioif,
/* Get the Serial Number
*
* Reads the Serial Number into buf. The buffer must be
* at least S96AT_SERIALNUM_LEN long.
*/
int s96at_get_serialnbr(struct io_interface *ioif, );
/* Generate a hash (SHA-256)
*
* Input data must have a valid padding as described in FIPS-180:
*
* https://csrc.nist.gov/publications/detail/fips/180/2/archive/2002-08-01
*
* The resulting hash is stored in the hash buffer.
*/
int s96at_get_sha(uint8_t *data, size_t size, uint8_t hash[SHA_LEN]);
/* Read the Config Zone
*
* Reads the Config Zone into buf. The buffer must be
* at least S96AT_ZONE_CONFIG_SIZE long.
*/
int s96at_get_zone_config(uint8_t *buf, size_t size);
/* Lock the Config Zone
*
* Locks the Config Zone. After the configuration is locked, the Data and
* OTP areas can be programmed.
*
* Notice that locking is a one-time operation.
*/
int s96at_lock_config(struct io_interface *ioif);
/* Lock the Data / OTP Zone
*
* Locks the Data and OTP Zones. The values of the slots in each zone must
* be programmed before locking. Once the Data / OTP zones are locked, the
* values stored can be read and written according to the policy specified
* in the configuration of each slot.
*
* Notice that locking is a one-time operation.
*/
int s96at_lock_data(struct io_interface *ioif);
/* Program the Config Zone
*
* Programs the Config Zone with the values stored in buf. The buffer must be
* of S96AT_CONFIG_SIZE length.
*/
int s96at_program_config(struct io_interface *ioif, uint8_t *buf);
/* Program the Data Zone
*
* Programs the Data Zone with the values stored in buf. The buffer must be
* of S96AT_DATA_SIZE length.
*/
int s96at_program_data(struct io_interface *ioif, uint8_t *buf);
/* Program the OTP Zone
*
* Programs the OTP Zone with the values stored in buf. The buffer must be
* of S96AT_OTP_SIZE length.
*/
int s96at_program_otp(struct io_interface *ioif, uint8_t *buf);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment