aboutsummaryrefslogtreecommitdiff
path: root/rpc_misc.c
blob: cf5e4a0914b7991b32435bf2ed07534efaca7f43 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
#!/bin/sh

OPENOCD=openocd

# location of OpenOCD Board .cfg files (only used with 'make flash-target')
#
# This path is from Ubuntu 14.04.
#
OPENOCD_BOARD_DIR=/usr/share/openocd/scripts/board

# Configuration (cfg) file containing programming directives for OpenOCD
#
# If you are using an STLINK v2.0 from an STM32 F4 DISCOVERY board,
# set this variable to "stm32f4discovery.cfg".
#
# If you are using an STLINK v2.1 from an STM32 F4 NUCLEO board,
# set this variable to "st_nucleo_f401re.cfg".
#
# If you are using something else, look for a matching configuration file in
# the OPENOCD_BOARD_DIR directory.
#
OPENOCD_PROC_FILE=stm32f4discovery.cfg
if [ "x`lsusb -d 0483:374b`" != "x" ]; then
    for fn in st_nucleo_f4.cfg st_nucleo_f401re.cfg; do
        if [ -f "$OPENOCD_BOARD_DIR/$fn" ]; then
	 
/*
 * rpc_misc.c
 * ----------
 * RPC interface to TRNG and PIN functions
 *
 * Authors: Rob Austein
 * Copyright (c) 2015, NORDUnet A/S All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the NORDUnet nor the names of its contributors may
 *   be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <assert.h>

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

static hal_error_t get_version(uint32_t *version)
{
  *version = RPC_VERSION;
  return HAL_OK;
}

static hal_error_t get_random(void *buffer, const size_t length)
{
  assert(buffer != NULL && length > 0);

  return hal_get_random(NULL, buffer, length);
}

/*
 * PINs, salt, and iteration count live in the keystore.
 *
 * We also need a client table in conventional memory (here, probably)
 * to record login status.
 *
 * The USER and SO PINs correspond to PKCS #11.
 *
 * The WHEEL PIN is the one that's allowed to change the SO PIN.
 *
 * It's a bit unclear how we should manage changes to the WHEEL PIN.
 * Implementing a factory default would be easy enough (just
 * pre-compute and compile in a const hal_ks_pin_t), question is
 * whether doing so provides anything useful.  Certainly adds no real
 * security, question is whether it would help prevent accidently
 * bricking the HSM right out of the shrink wrap.
 *
 * More interesting question is whether we should ever allow the WHEEL
 * PIN to be changed a second time without toasting the keystore.
 */

typedef struct {
  hal_client_handle_t handle;
  hal_user_t logged_in;
} client_slot_t;

#ifndef HAL_PIN_MINIMUM_ITERATIONS
#define HAL_PIN_MINIMUM_ITERATIONS 10000
#endif

#ifndef HAL_PIN_DEFAULT_ITERATIONS
#define HAL_PIN_DEFAULT_ITERATIONS 20000
#endif

static uint32_t hal_pin_default_iterations = HAL_PIN_DEFAULT_ITERATIONS;

#ifndef HAL_STATIC_CLIENT_STATE_BLOCKS
#define HAL_STATIC_CLIENT_STATE_BLOCKS	10
#endif

#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
static client_slot_t client_handle[HAL_STATIC_CLIENT_STATE_BLOCKS];
#endif

/*
 * Client handles are supplied by the application, we don't get to
 * pick them, we just store them and associate a login state with
 * them.  HAL_USER_NONE indicates an empty slot in the table.
 */

static inline client_slot_t *alloc_slot(void)
{
  client_slot_t *slot = NULL;
  hal_critical_section_start();

#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
  for (int i = 0; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
    if (client_handle[i].logged_in == HAL_USER_NONE)
      slot = &client_handle[i];
#endif

  hal_critical_section_end();
  return slot;
}

static inline client_slot_t *find_handle(const hal_client_handle_t handle)
{
  client_slot_t *slot = NULL;
  hal_critical_section_start();

#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
  for (int i = 0; slot == NULL && i < sizeof(client_handle)/sizeof(*client_handle); i++)
    if (client_handle[i].logged_in != HAL_USER_NONE && client_handle[i].handle.handle == handle.handle)
      slot = &client_handle[i];
#endif

  hal_critical_section_end();
  return slot;
}

static hal_error_t login(const hal_client_handle_t client,
                         const hal_user_t user,
                         const char * const pin, const size_t pin_len)
{
  assert(pin != NULL && pin_len != 0);
  assert(user == HAL_USER_NORMAL || user == HAL_USER_SO || user == HAL_USER_WHEEL);

  const hal_ks_pin_t *p;
  hal_error_t err;

  if ((err = hal_get_pin(user, &p)) != HAL_OK)
    return err;

  uint8_t buf[sizeof(p->pin)];
  const uint32_t iterations = p->iterations == 0 ? hal_pin_default_iterations : p->iterations;

  if ((err = hal_pbkdf2(NULL, hal_hash_sha256, (const uint8_t *) pin, pin_len,
                        p->salt, sizeof(p->salt), buf, sizeof(buf), iterations)) != HAL_OK)
    return err;

  unsigned diff = 0;
  for (int i = 0; i < sizeof(buf); i++)
    diff |= buf[i] ^ p->pin[i];

  if (diff != 0)
    return HAL_ERROR_PIN_INCORRECT;

  client_slot_t *slot = find_handle(client);

  if (slot == NULL && (slot = alloc_slot()) == NULL)
    return HAL_ERROR_NO_CLIENT_SLOTS_AVAILABLE;

  slot->handle = client;
  slot->logged_in = user;

  return HAL_OK;
}

static hal_error_t is_logged_in(const hal_client_handle_t client,
                                const hal_user_t user)
{
  assert(user == HAL_USER_NORMAL || user == HAL_USER_SO || user == HAL_USER_WHEEL);

  client_slot_t *slot = find_handle(client);

  if (slot == NULL || slot->logged_in != user)
    return HAL_ERROR_FORBIDDEN;

  return HAL_OK;
}

static hal_error_t logout(const hal_client_handle_t client)
{
  client_slot_t *slot = find_handle(client);

  if (slot != NULL)
    slot->logged_in = HAL_USER_NONE;

  return HAL_OK;
}

static hal_error_t logout_all(void)
{
#if HAL_STATIC_CLIENT_STATE_BLOCKS > 0
  for (int i = 0; i < sizeof(client_handle)/sizeof(*client_handle); i++)
    client_handle[i].logged_in = HAL_USER_NONE;
#endif

  return HAL_OK;
}

static hal_error_t set_pin(const hal_client_handle_t client,
                           const hal_user_t user,
                           const char * const newpin, const size_t newpin_len)
{
  assert(newpin != NULL && newpin_len >= hal_rpc_min_pin_length && newpin_len <= hal_rpc_max_pin_length);

  if ((user != HAL_USER_NORMAL || is_logged_in(client, HAL_USER_SO) != HAL_OK) &&
      is_logged_in(client, HAL_USER_WHEEL) != HAL_OK)
    return HAL_ERROR_FORBIDDEN;

  const hal_ks_pin_t *pp;
  hal_error_t err;

  if ((err = hal_get_pin(user, &pp)) != HAL_OK)
    return err;

  hal_ks_pin_t p = *pp;

  p.iterations = hal_pin_default_iterations;

  if ((err = hal_get_random(NULL, p.salt, sizeof(p.salt)))      != HAL_OK ||
      (err = hal_pbkdf2(NULL, hal_hash_sha256,
                        (const uint8_t *) newpin, newpin_len,
                        p.salt, sizeof(p.salt),
                        p.pin,  sizeof(p.pin), p.iterations))   != HAL_OK ||
      (err = hal_set_pin(user, &p))                             != HAL_OK)
    return err;

  return HAL_OK;
}

hal_error_t hal_set_pin_default_iterations(const hal_client_handle_t client,
                                           const uint32_t iterations)
{
  if ((is_logged_in(client, HAL_USER_WHEEL) != HAL_OK) &&
      (is_logged_in(client, HAL_USER_SO) != HAL_OK))
    return HAL_ERROR_FORBIDDEN;

  /* should probably store this in flash somewhere */
  hal_pin_default_iterations = (iterations == 0) ? HAL_PIN_DEFAULT_ITERATIONS : iterations;
  return HAL_OK;
}

const hal_rpc_misc_dispatch_t hal_rpc_local_misc_dispatch = {
  .set_pin      = set_pin,
  .login        = login,
  .logout       = logout,
  .logout_all   = logout_all,
  .is_logged_in = is_logged_in,
  .get_random   = get_random,
  .get_version  = get_version
};

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