aboutsummaryrefslogblamecommitdiff
path: root/ks.h
blob: ff6d38206707a19ba6c46c7c1cc2ab5ab719766d (plain) (tree)
















































































































































































































































                                                                                                                                
// Notes towards unified keystore code (drivers become just low-level
// "disk" I/O and perhaps a bit of local init/shutdown).
//
// Most of the structure definitions in ks_flash.c and ks_volatile.c
// become common and go in ks.h (or wherever, but probably be enough
// stuff that separate .h file might be easier to read).
//
// We already have
//
//     typedef struct hal_ks hal_ks_t;
//
// which we "subclass" to get ks_t (ks_volatile) and db_t (ks_flash).
// We can move more common stuff there.
//
// flash_block_t (etc) becomes ks_block_t (etc) as these data
// structures will be used by all keystores, not just flash.
//
// We might want to fold hal_ks_index_t into hal_ks_t as everything
// will be using it.  Then again, it's relatively harmless as it is, a
// bit more verbose trading for a bit more isolation.  Probably go for
// less verbose, for readability.
//
// Each keystore will still have some weird private stuff, like the
// RAM for the keys themselves in the volatile case and the PIN stuff
// in the flash case.
//
// The ks_flash cache, however, probably wants to become common code.
// Yes we could get a bit more efficient if we skipped caching in the
// volatile case, but that's not our bottleneck and there are some
// cases where the code relies on knowing that mucking with the cache
// copy is harmless until we write the block to "disk", don't want to
// mess with that, so keep the flash model for volatile.  Cache size
// will need to become another hal_ks_t field.
//
// Don't remember exactly where we're doing the "subclassing" casts,
// should be easy enough to find...except that ks_flash is mostly
// ignoring that argument and using the static db variable directly.
// ks_volatile may be closer to write on this point, as it already had
// ks_to_ksv().  But most of the code will be in a driver-agnostic
// ks.c (or whatever) and will be calling functions that care through
// the driver, maybe this doesn't matter very much.
//
// Tedious though it sounds, might be simplest just to check each
// function in ks_*.c to see whether it moves to ks.[ch] or becomes
// something called by the new lower-level driver API.  Need a sketch
// of the lower-level driver API, chicken and egg there but probably
// is init(), shutdown(), block_read(), block_deprecate(),
// block_zero(), block_erase(), block_erase_maybe(), block-write().
// Possible that some of these don't really need to be driver, was
// mostly basing this on which things in ks_flash touch flash
// directly-ish via the keystore_*() functions.
//
// Would be nice if we can make the API regular enough (inline
// functions?) that user need not really care which functions are
// driver-specific and which are layered on top, but that may be
// impractical (or silly).
//
// Hmm, hal_ks_open() and hal_ks_close() don't quite fit new model,
// what was I thinking there?  Not much, existing implementations just
// use that to get back a (hal_ks_t*), so really just checking the
// binding between driver and keystore object.
//
// I think this boils down to another instance of the confusion
// between what in Python would be Keystore.__new__() and
// Keystore.__init__().  This even sort of fits with the weird `alloc`
// parameter in ks_init().
//
// Maybe we can trust C memory initialization enough to use a zeroed
// static variable as test for whether a keystore has been
// initialized, and just have the low-level (driver) methods check
// that and fail if trying to use an uninitialized keystore?
//
// Pythonesque view might be the right way to handle ks_init(0 and
// ks_shutdown() too: in most cases we have inline functions which
// call the driver function, but for these methods the subclass needs
// to extend the abstract method, which translates, in C, to the
// generic method calling the driver method of the same name at the
// right time.  Not quite what Python does but close enough.


#ifndef _KS_H_
#define _KS_H_

#include "hal.h"
#include "hal_internal.h"

/*
 * Size of a keystore "block".
 *
 * This must be an integer multiple of the flash subsector size, among
 * other reasons because that's the minimum erasable unit.
 */

#ifndef HAL_KS_BLOCK_SIZE
#define HAL_KS_BLOCK_SIZE       (KEYSTORE_SUBSECTOR_SIZE * 1)
#endif

/*
 * Known block states.
 *
 * C does not guarantee any particular representation for enums, so
 * including enums directly in the block header isn't safe.  Instead,
 * we use an access method which casts when reading from the header.
 * Writing to the header isn't a problem, because C does guarantee
 * that enum is compatible with *some* integer type, it just doesn't
 * specify which one.
 */

typedef enum {
  KS_BLOCK_TYPE_ERASED  = 0xFF, /* Pristine erased block (candidate for reuse) */
  KS_BLOCK_TYPE_ZEROED  = 0x00, /* Zeroed block (recently used) */
  KS_BLOCK_TYPE_KEY     = 0x55, /* Block contains key material */
  KS_BLOCK_TYPE_PIN     = 0xAA, /* Block contains PINs */
  KS_BLOCK_TYPE_UNKNOWN = -1,   /* Internal code for "I have no clue what this is" */
} ks_block_type_t;

/*
 * Block status.
 */

typedef enum {
  KS_BLOCK_STATUS_LIVE      = 0x66, /* This is a live block */
  KS_BLOCK_STATUS_TOMBSTONE = 0x44, /* This is a tombstone left behind during an update  */
  KS_BLOCK_STATUS_UNKNOWN   = -1,   /* Internal code for "I have no clue what this is" */
} ks_block_status_t;

/*
 * Common header for all keystore block types.
 * A few of these fields are deliberately omitted from the CRC.
 */

typedef struct {
  uint8_t               block_type;
  uint8_t               block_status;
  hal_crc32_t           crc;
} ks_block_header_t;

/*
 * Key block.  Tail end of "der" field (after der_len) used for attributes.
 */

typedef struct {
  ks_block_header_t     header;
  hal_uuid_t            name;
  hal_key_type_t        type;
  hal_curve_name_t      curve;
  hal_key_flags_t       flags;
  size_t                der_len;
  unsigned              attributes_len;
  uint8_t               der[];  /* Must be last field -- C99 "flexible array member" */
} ks_blockkey_block_t;

#define SIZEOF_KS_BLOCKKEY_BLOCK_DER \
  (HAL_KS_BLOCK_SIZE - offsetof(ks_blockkey_block_t, der))

/*
 * PIN block.  Also includes space for backing up the KEK when
 * HAL_MKM_FLASH_BACKUP_KLUDGE is enabled.
 */

typedef struct {
  ks_block_header_t     header;
  hal_ks_pin_t          wheel_pin;
  hal_ks_pin_t          so_pin;
  hal_ks_pin_t          user_pin;
#if HAL_MKM_FLASH_BACKUP_KLUDGE
  uint32_t              kek_set;
  uint8_t               kek[KEK_LENGTH];
#endif
} ks_blockpin_block_t;

#define FLASH_KEK_SET   0x33333333

/*
 * One keystore block.
 */

typedef union {
  uint8_t               bytes[HAL_KS_BLOCK_SIZE];
  ks_block_header_t     header;
  ks_blockkey_block_t   key;
  ks_blockpin_block_t   pin;
} ks_block_t;

/*
 * In-memory cache.
 */

typedef struct {
  unsigned              blockno;
  unsigned              lru;
  ks_block_t            block;
} ks_cache_block_t;

/*
 * Medium-specific driver and in-memory database.
 *
 * The top-level structure is a static variable; the arrays are
 * allocated at runtime using hal_allocate_static_memory() because
 * they can get kind of large.
 *
 * Driver-specific stuff is handled by a form of subclassing: the
 * driver embeds the hal_ks_t structure at the head of whatever else
 * it needs, and performs (controlled, type-safe) casts as needed.
 */

typedef struct hal_ks_driver    hal_ks_driver_t;
typedef struct hal_ks           hal_ks_t;

struct hal_ks {
  const hal_ks_driver_t *driver;
  unsigned size;                /* Blocks in keystore */
  unsigned used;                /* How many blocks are in use */
  uint16_t *index;              /* Index/freelist array */
  hal_uuid_t *names;            /* Keyname array */
  unsigned cache_lru;           /* Cache LRU counter */
  unsigned cache_size;          /* Size (how many blocks) in cache */
  ks_cache_block_t *cache;      /* Cache */
  int per_session;              /* Whether objects have per-session semantics (PKCS #11, sigh) */
};

struct hal_ks_driver {
  hal_error_t (*init)           (hal_ks_t *, const int alloc);
  hal_error_t (*shutdown)       (hal_ks_t *);
  hal_error_t (*read)           (hal_ks_t *, const unsigned blockno, ks_block_t *);
  hal_error_t (*write)          (hal_ks_t *, const unsigned blockno, ks_block_t *)
  hal_error_t (*deprecate)      (hal_ks_t *, const unsigned blockno);
  hal_error_t (*zero)           (hal_ks_t *, const unsigned blockno);
  hal_error_t (*erase)          (hal_ks_t *, const unsigned blockno);
  hal_error_t (*erase_maybe)    (hal_ks_t *, const unsigned blockno);
  hal_error_t (*get_owner)      (hal_ks_t *, const unsigned blockno,       hal_client_handle_t *,       hal_session_handle_t *);
  hal_error_t (*set_owner)      (hal_ks_t *, const unsigned blockno, const hal_client_handle_t,   const hal_session_handle_t);
};

#endif /* _KS_H_ */

/*
 * Local variables:
 * indent-tabs-mode: nil
 * End:
 */