Software APIs
Macros | Typedefs | Enumerations | Functions
hardened.h File Reference

(f166105)

Data Types for use in Hardened Code. More...

#include <stdint.h>
#include "sw/device/lib/base/stdasm.h"

Go to the source code of this file.

Macros

#define HARDENED_UNIMP_SEQUENCE_()   "unimp; unimp; unimp; unimp;"
 
#define HARDENED_CHECK_OP_EQ_   "beq"
 
#define HARDENED_CHECK_OP_NE_   "bne"
 
#define HARDENED_CHECK_OP_LT_   "blt"
 
#define HARDENED_CHECK_OP_GT_   "bgt"
 
#define HARDENED_CHECK_OP_LE_   "ble"
 
#define HARDENED_CHECK_OP_GE_   "bge"
 
#define HARDENED_CHECK_(op_, a_, b_)
 
#define HARDENED_UNREACHABLE_()
 
#define HARDENED_UNREACHABLE()   HARDENED_UNREACHABLE_()
 Indicates that the following code is unreachable; it should never be reached at runtime. More...
 
#define HARDENED_CHECK_EQ(a_, b_)   HARDENED_CHECK_(HARDENED_CHECK_OP_EQ_, a_, b_)
 Compare two values in a way that is manifestly true: that is, under normal program execution, the comparison is a tautology. More...
 
#define HARDENED_CHECK_NE(a_, b_)   HARDENED_CHECK_(HARDENED_CHECK_OP_NE_, a_, b_)
 
#define HARDENED_CHECK_LT(a_, b_)   HARDENED_CHECK_(HARDENED_CHECK_OP_LT_, a_, b_)
 
#define HARDENED_CHECK_GT(a_, b_)   HARDENED_CHECK_(HARDENED_CHECK_OP_GT_, a_, b_)
 
#define HARDENED_CHECK_LE(a_, b_)   HARDENED_CHECK_(HARDENED_CHECK_OP_LE_, a_, b_)
 
#define HARDENED_CHECK_GE(a_, b_)   HARDENED_CHECK_(HARDENED_CHECK_OP_GE_, a_, b_)
 

Typedefs

typedef enum hardened_bool hardened_bool_t
 This is a boolean type for use in hardened contexts. More...
 
typedef enum hardened_byte_bool hardened_byte_bool_t
 A byte-sized hardened boolean. More...
 
typedef uint32_t ct_bool32_t
 A constant-time, 32-bit boolean value. More...
 
typedef uintptr_t ct_boolw_t
 A constant-time, pointer-sized boolean value. More...
 

Enumerations

enum  hardened_bool {
  kHardenedBoolTrue = 0x739u,
  kHardenedBoolFalse = 0x1d4u
}
 This is a boolean type for use in hardened contexts. More...
 
enum  hardened_byte_bool {
  kHardenedByteBoolTrue = 0xa5,
  kHardenedByteBoolFalse = 0x4b
}
 A byte-sized hardened boolean. More...
 

Functions

uint32_t launder32 (uint32_t val)
 
uintptr_t launderw (uintptr_t val)
 Launders the pointer-sized value val. More...
 
void barrier32 (uint32_t val)
 Creates a reordering barrier for val. More...
 
void barrierw (uintptr_t val)
 Creates a reordering barrier for val. More...
 
ct_bool32_t ct_sltz32 (int32_t a)
 Performs constant-time signed comparison to zero. More...
 
ct_bool32_t ct_sltu32 (uint32_t a, uint32_t b)
 Performs constant-time unsigned ascending comparison. More...
 
ct_bool32_t ct_seqz32 (uint32_t a)
 Performs constant-time zero equality. More...
 
ct_bool32_t ct_seq32 (uint32_t a, uint32_t b)
 Performs constant-time equality. More...
 
uint32_t ct_cmov32 (ct_bool32_t c, uint32_t a, uint32_t b)
 Performs a constant-time select. More...
 
ct_boolw_t ct_sltzw (intptr_t a)
 Performs constant-time signed comparison to zero. More...
 
ct_boolw_t ct_sltuw (uintptr_t a, uintptr_t b)
 Performs constant-time unsigned ascending comparison. More...
 
ct_boolw_t ct_seqzw (uintptr_t a)
 Performs constant-time zero equality. More...
 
ct_boolw_t ct_seqw (uintptr_t a, uintptr_t b)
 Performs constant-time equality. More...
 
uintptr_t ct_cmovw (ct_boolw_t c, uintptr_t a, uintptr_t b)
 Performs a constant-time select. More...
 

Detailed Description

Data Types for use in Hardened Code.

Definition in file hardened.h.

Macro Definition Documentation

◆ HARDENED_CHECK_

#define HARDENED_CHECK_ (   op_,
  a_,
  b_ 
)
Value:
asm volatile( \
op_ " %0, %1, .L_HARDENED_%=;" \
HARDENED_UNIMP_SEQUENCE_() \
".L_HARDENED_%=:;" \
::"r"(a_), "r"(b_))

Definition at line 506 of file hardened.h.

◆ HARDENED_CHECK_EQ

#define HARDENED_CHECK_EQ (   a_,
  b_ 
)    HARDENED_CHECK_(HARDENED_CHECK_OP_EQ_, a_, b_)

Compare two values in a way that is manifestly true: that is, under normal program execution, the comparison is a tautology.

If the comparison fails, we can deduce the device is under attack, so an illegal instruction will be executed. The manner in which the comparison is done is carefully constructed in assembly to minimize the possibility of adversarial faults.

There are six variants of this macro: one for each of the six comparison operations.

This macro is intended to be used along with launder32() to handle detected faults when implementing redundant checks, i.e. in places where the compiler could otherwise prove statically unreachable. For example:

if (launder32(x) == 0) {
HARDENED_CHECK_EQ(launder32(x), 0);
}

See launder32() for more details.

Definition at line 564 of file hardened.h.

◆ HARDENED_UNREACHABLE

#define HARDENED_UNREACHABLE ( )    HARDENED_UNREACHABLE_()

Indicates that the following code is unreachable; it should never be reached at runtime.

If it is reached anyways, an illegal instruction will be executed.

Definition at line 540 of file hardened.h.

◆ HARDENED_UNREACHABLE_

#define HARDENED_UNREACHABLE_ ( )
Value:
do { \
asm volatile(HARDENED_UNIMP_SEQUENCE_()); \
__builtin_unreachable(); \
} while (false)

Definition at line 514 of file hardened.h.

Typedef Documentation

◆ ct_bool32_t

typedef uint32_t ct_bool32_t

A constant-time, 32-bit boolean value.

Values of this type MUST be either all zero bits or all one bits, representing false and true respectively.

Although it is possible to convert an existing bool into a ct_bool32_t by writing -((ct_bool32_t) my_bool), we recommend against it

Definition at line 335 of file hardened.h.

◆ ct_boolw_t

typedef uintptr_t ct_boolw_t

A constant-time, pointer-sized boolean value.

Values of this type MUST be either all zero bits or all one bits.

Definition at line 432 of file hardened.h.

◆ hardened_bool_t

This is a boolean type for use in hardened contexts.

The intention is that this is used instead of <stdbool.h>'s #bool, where a higher hamming distance is required between the truthy and the falsey value.

The values below were chosen at random, with some specific restrictions. They have a Hamming Distance of 8, and they are 11-bit values so they can be materialized with a single instruction on RISC-V. They are also specifically not the complement of each other.

◆ hardened_byte_bool_t

A byte-sized hardened boolean.

This type is intended for cases where a byte-sized hardened boolean is required, e.g. for the entries of the CREATOR_SW_CFG_KEY_IS_VALID OTP item.

The values below were chosen to ensure that the hamming difference between them is greater than 5 and they are not bitwise complements of each other.

Enumeration Type Documentation

◆ hardened_bool

This is a boolean type for use in hardened contexts.

The intention is that this is used instead of <stdbool.h>'s #bool, where a higher hamming distance is required between the truthy and the falsey value.

The values below were chosen at random, with some specific restrictions. They have a Hamming Distance of 8, and they are 11-bit values so they can be materialized with a single instruction on RISC-V. They are also specifically not the complement of each other.

Enumerator
kHardenedBoolTrue 

The truthy value, expected to be used like #true.

kHardenedBoolFalse 

The falsey value, expected to be used like #false.

Definition at line 32 of file hardened.h.

◆ hardened_byte_bool

A byte-sized hardened boolean.

This type is intended for cases where a byte-sized hardened boolean is required, e.g. for the entries of the CREATOR_SW_CFG_KEY_IS_VALID OTP item.

The values below were chosen to ensure that the hamming difference between them is greater than 5 and they are not bitwise complements of each other.

Enumerator
kHardenedByteBoolTrue 

The truthy value.

kHardenedByteBoolFalse 

The falsy value.

Definition at line 52 of file hardened.h.

Function Documentation

◆ barrier32()

void barrier32 ( uint32_t  val)
inline

Creates a reordering barrier for val.

barrier32() takes an argument and discards it, while introducing an "impure" dependency on that value. This forces the compiler to schedule instructions such that the intermediate val actually appears in a register. Because it is impure, barrier32() operations will not be reordered past each other or MMIO operations, although they can be reordered past functions if LTO inlines them.

Most compilers will try to reorder arithmetic operations in such a way that they form large basic blocks, since modern microarchitectures can take advantage of instruction-level parallelism. Unfortunately, this means that instructions that we want to interleave with other instructions are likely to get separated; this includes static interleavings, loop-invariant code motion, and some kinds of unroll-and-jam.

For example, given

uint32_t product = 5;
foo();
product *= product;
foo();
product *= product;
foo();
product *= product;

A compiler will likely reorder this as

uint32_t product = 5;
foo();
foo();
foo();
product *= product;
product *= product;
product *= product;

The compiler is further entitled to constant-propagate product. barrier32() can be used to avoid this:

// NB: the initial value of `product` is laundered to prevent
// constant propagation, but only because it is a compile-time
// constant. Laundering the intermediates would also work.
uint32_t product = launder32(5);
barrier32(product);
barrier32(foo());
product *= product;
barrier32(product);
barrier32(foo());
product *= product;
barrier32(product);
barrier32(foo());
product *= product;
barrier32(product);

Note that we must place barriers on the result of the function calls, too, so that the compiler believes that there is a potential dependency between the return value of the function, and the followup value of product.

This is also useful for avoiding loop reordering:

for (int i = 0; i != n - 1; i = (i + kPrime) % n) {
// Stuff.
}

A sufficiently intelligent compiler might notice that it can linearize this loop; however, the barriers in each loop iteration force a particular order is observed.

Parameters
valA value to create a barrier for.

Definition at line 315 of file hardened.h.

◆ barrierw()

void barrierw ( uintptr_t  val)
inline

Creates a reordering barrier for val.

See barrier32() for detailed semantics.

Parameters
valA value to create a barrier for.

Definition at line 324 of file hardened.h.

◆ ct_cmov32()

uint32_t ct_cmov32 ( ct_bool32_t  c,
uint32_t  a,
uint32_t  b 
)
inline

Performs a constant-time select.

Returns a if c is true; otherwise, returns b.

This function should be used with one of the comparison functions above; do NOT create c using an if or ?: operation.

Parameters
cThe condition to test.
aThe value to return on true.
bThe value to return on false.
Returns
c ? a : b.

Definition at line 417 of file hardened.h.

◆ ct_cmovw()

uintptr_t ct_cmovw ( ct_boolw_t  c,
uintptr_t  a,
uintptr_t  b 
)
inline

Performs a constant-time select.

Returns a if c is true; otherwise, returns b.

This function should be used with one of the comparison functions above; do NOT create c using an if or ?: operation.

Parameters
cThe condition to test.
aThe value to return on true.
bThe value to return on false.
Returns
c ? a : b.

Definition at line 488 of file hardened.h.

◆ ct_seq32()

ct_bool32_t ct_seq32 ( uint32_t  a,
uint32_t  b 
)
inline

Performs constant-time equality.

Returns a == b as a constant-time boolean.

Returns
a == b.

Definition at line 399 of file hardened.h.

◆ ct_seqw()

ct_boolw_t ct_seqw ( uintptr_t  a,
uintptr_t  b 
)
inline

Performs constant-time equality.

Returns a == b as a constant-time boolean.

Returns
a == b.

Definition at line 473 of file hardened.h.

◆ ct_seqz32()

ct_bool32_t ct_seqz32 ( uint32_t  a)
inline

Performs constant-time zero equality.

Returns a == 0 as a constant-time boolean.

Returns
a == 0.

Definition at line 380 of file hardened.h.

◆ ct_seqzw()

ct_boolw_t ct_seqzw ( uintptr_t  a)
inline

Performs constant-time zero equality.

Returns a == 0 as a constant-time boolean.

Returns
a == 0.

Definition at line 464 of file hardened.h.

◆ ct_sltu32()

ct_bool32_t ct_sltu32 ( uint32_t  a,
uint32_t  b 
)
inline

Performs constant-time unsigned ascending comparison.

Returns a < b as a constant-time boolean.

Returns
a < b.

Definition at line 368 of file hardened.h.

◆ ct_sltuw()

ct_boolw_t ct_sltuw ( uintptr_t  a,
uintptr_t  b 
)
inline

Performs constant-time unsigned ascending comparison.

Returns a < b as a constant-time boolean.

Returns
a < b.

Definition at line 453 of file hardened.h.

◆ ct_sltz32()

ct_bool32_t ct_sltz32 ( int32_t  a)
inline

Performs constant-time signed comparison to zero.

Returns whether a < 0, as a constant-time boolean. In other words, this checks if a is negative, i.e., it's sign bit is set.

Returns
a < 0.

Definition at line 354 of file hardened.h.

◆ ct_sltzw()

ct_boolw_t ct_sltzw ( intptr_t  a)
inline

Performs constant-time signed comparison to zero.

Returns whether a < 0, as a constant-time boolean. In other words, this checks if a is negative, i.e., it's sign bit is set.

Returns
a < 0.

Definition at line 442 of file hardened.h.

◆ launderw()

uintptr_t launderw ( uintptr_t  val)
inline

Launders the pointer-sized value val.

See launder32() for detailed semantics.

Parameters
valA 32-bit integer to launder.
Returns
A 32-bit integer which will happen to have the same value as val at runtime.

Definition at line 223 of file hardened.h.