aboutsummaryrefslogblamecommitdiff
path: root/modexp.c
blob: f097f33ea5dfde95919a6910fb8af6d5276fdeeb (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                       

                                   
  




                                                                           
  


                                                                         
  


                                                                           
  










                                                                           



                   

                   
                
                         





























                                                                         

                                                       









                                               
                                                


  


                                                                    

   

                                                         

                                                  
 



                                           
                                 
                                                                         




                


                                                                    

   

                                                         

                                                          
 



                                           
                                 
                                                                          







                            
                                        
                                                                                     



                                                                                      

                  















                                                                       















                                                                                   
    











                                                                      

     
                                        
                                                                
 
                                
                                                                      
 
                         
                                                               
 
                                         
                           
 
                                        
                                 
 
                         
                                                               

                                       
                                                                       

                        
                                                                

                         
                           
 
                       
                                 
 
                      
                                                                 
 
                      







                        
/*
 * modexp.c
 * ----------
 * Wrapper around Cryptech ModExp core.
 *
 * This doesn't do full RSA, that's another module.  This module's job
 * is just the I/O to get bits in and out of the ModExp core, including
 * compensating for a few known bugs that haven't been resolved yet.
 *
 * If at some point the interface to the ModExp core becomes simple
 * enough that this module is no longer needed, it will go away.
 *
 * 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 <stdio.h>
#include <stdint.h>
#include <assert.h>

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

/*
 * Whether we want debug output.
 */

static int debug = 0;

void hal_modexp_set_debug(const int onoff)
{
  debug = onoff;
}

/*
 * Check a result, report on failure if debugging, pass failures up
 * the chain.
 */

#define check(_expr_)                                                   \
  do {                                                                  \
    hal_error_t _err = (_expr_);                                        \
    if (_err != HAL_OK && debug)                                        \
      printf("%s failed: %s\n", #_expr_, hal_error_string(_err));       \
    if (_err != HAL_OK)                                                 \
      return _err;                                                      \
  } while (0)

/*
 * Set an ordinary register.
 */

static hal_error_t set_register(const hal_core_t *core,
                                const hal_addr_t addr,
                                uint32_t value)
{
  uint8_t w[4];
  int i;

  for (i = 3; i >= 0; i--) {
    w[i] = value & 0xFF;
    value >>= 8;
  }

  return hal_io_write(core, addr, w, sizeof(w));
}

/*
 * Get value of a data buffer.  We reverse the order of 32-bit words
 * in the buffer during the transfer to match what the modexps6 core
 * expects.
 */

static hal_error_t get_buffer(const hal_core_t *core,
                              const hal_addr_t data_addr,
                              uint8_t *value,
                              const size_t length)
{
  size_t i;

  assert(value != NULL && length % 4 == 0);

  for (i = 0; i < length; i += 4)
    check(hal_io_read(core, data_addr + i/4, &value[length - 4 - i], 4));

  return HAL_OK;
}

/*
 * Set value of a data buffer.  We reverse the order of 32-bit words
 * in the buffer during the transfer to match what the modexps6 core
 * expects.
 */

static hal_error_t set_buffer(const hal_core_t *core,
                              const hal_addr_t data_addr,
                              const uint8_t * const value,
                              const size_t length)
{
  size_t i;

  assert(value != NULL && length % 4 == 0);

  for (i = 0; i < length; i += 4)
    check(hal_io_write(core, data_addr + i/4, &value[length - 4 - i], 4));

  return HAL_OK;
}

/*
 * Run one modexp operation.
 */

hal_error_t hal_modexp(hal_core_t *core,
                       const uint8_t * const msg, const size_t msg_len, /* Message */
                       const uint8_t * const exp, const size_t exp_len, /* Exponent */
                       const uint8_t * const mod, const size_t mod_len, /* Modulus */
                       uint8_t *result, const size_t result_len)
{
  hal_error_t err;

  /*
   * All pointers must be set, neither message nor exponent may be
   * longer than modulus, result buffer must not be shorter than
   * modulus, and all input lengths must be a multiple of four.
   *
   * The multiple-of-four restriction is a pain, but the rest of the
   * HAL code currently enforces the same restriction, and allowing
   * arbitrary lengths would require some tedious shuffling to deal
   * with alignment issues, so it's not worth trying to fix only here.
   */

  if (msg == NULL || exp == NULL || mod == NULL || result == NULL ||
      msg_len > mod_len || exp_len > mod_len || result_len < mod_len ||
      ((msg_len | exp_len | mod_len) & 3) != 0)
    return HAL_ERROR_BAD_ARGUMENTS;

  if (((err = hal_core_alloc(MODEXPS6_NAME, &core)) == HAL_ERROR_CORE_NOT_FOUND) &&
      ((err = hal_core_alloc(MODEXPA7_NAME, &core)) != HAL_OK))
    return err;

#undef  check
#define check(_expr_)                                                   \
  do {                                                                  \
    hal_error_t _err = (_expr_);                                        \
    if (_err != HAL_OK && debug)                                        \
      printf("%s failed: %s\n", #_expr_, hal_error_string(_err));       \
    if (_err != HAL_OK) {                                               \
      hal_core_free(core);                                              \
      return _err;                                                      \
    }                                                                   \
  } while (0)

  /*
   * We probably ought to take the mode (fast vs constant-time) as an
   * argument, but for the moment we just guess that really short
   * exponent means we're using the public key and can use fast mode,
   * all other cases are something to do with the private key and
   * therefore must use constant-time mode.
   *
   * Unclear whether it's worth trying to figure out exactly how long
   * the operands are: assuming a multiple of eight is safe, but makes
   * a bit more work for the core; checking to see how many bits are
   * really set leaves the core sitting idle while the main CPU does
   * these checks.  No way to know which is faster without testing;
   * take simple approach for the moment.
   */

  /* Select mode (1 = fast, 0 = safe) */
  check(set_register(core, MODEXPS6_ADDR_MODE, (exp_len <= 4)));

  /* Set modulus size in bits */
  check(set_register(core, MODEXPS6_ADDR_MODULUS_WIDTH, mod_len * 8));

  /* Write new modulus */
  check(set_buffer(core, MODEXPS6_ADDR_MODULUS, mod, mod_len));

  /* Pre-calcuate speed-up coefficient */
  check(hal_io_init(core));

  /* Wait for calculation to complete */
  check(hal_io_wait_ready(core));

  /* Write new message */
  check(set_buffer(core, MODEXPS6_ADDR_MESSAGE, msg, msg_len));

  /* Set new exponent length in bits */
  check(set_register(core, MODEXPS6_ADDR_EXPONENT_WIDTH, exp_len * 8));

  /* Set new exponent */
  check(set_buffer(core, MODEXPS6_ADDR_EXPONENT, exp, exp_len));

  /* Start calculation */
  check(hal_io_next(core));

  /* Wait for result */
  check(hal_io_wait_valid(core));

  /* Extract result */
  check(get_buffer(core, MODEXPS6_ADDR_RESULT, result, mod_len));

  hal_core_free(core);
  return HAL_OK;
}

/*
 * Local variables:
 * indent-tabs-mode: nil
 * End:
 */
lockno); hal_error_t (*erase_maybe) (hal_ks_t *ks, const unsigned blockno); hal_error_t (*set_owner) (hal_ks_t *ks, const unsigned blockno, const hal_client_handle_t client, const hal_session_handle_t session); hal_error_t (*test_owner) (hal_ks_t *ks, const unsigned blockno, const hal_client_handle_t client, const hal_session_handle_t session); hal_error_t (*copy_owner) (hal_ks_t *ks, const unsigned source, const unsigned target); hal_error_t (*logout) (hal_ks_t *ks, const hal_client_handle_t client); }; /* * Wrappers around keystore driver methods. * * hal_ks_init() and hal_ks_logout() are missing here because we * expose them to the rest of libhal. */ static inline hal_error_t hal_ks_block_read(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->read == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->read(ks, blockno, block); } static inline hal_error_t hal_ks_block_write(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t *block) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->write == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->write(ks, blockno, block); } static inline hal_error_t hal_ks_block_deprecate(hal_ks_t *ks, const unsigned blockno) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->deprecate == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->deprecate(ks, blockno); } static inline hal_error_t hal_ks_block_zero(hal_ks_t *ks, const unsigned blockno) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->zero == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->zero(ks, blockno); } static inline hal_error_t hal_ks_block_erase(hal_ks_t *ks, const unsigned blockno) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->erase == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->erase(ks, blockno); } static inline hal_error_t hal_ks_block_erase_maybe(hal_ks_t *ks, const unsigned blockno) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->erase_maybe == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->erase_maybe(ks, blockno); } static inline hal_error_t hal_ks_block_set_owner(hal_ks_t *ks, const unsigned blockno, const hal_client_handle_t client, const hal_session_handle_t session) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->set_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->set_owner(ks, blockno, client, session); } static inline hal_error_t hal_ks_block_test_owner(hal_ks_t *ks, const unsigned blockno, const hal_client_handle_t client, const hal_session_handle_t session) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->test_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->test_owner(ks, blockno, client, session); } static inline hal_error_t hal_ks_block_copy_owner(hal_ks_t *ks, const unsigned source, const unsigned target) { return ks == NULL || ks->driver == NULL ? HAL_ERROR_BAD_ARGUMENTS : ks->driver->copy_owner == NULL ? HAL_ERROR_NOT_IMPLEMENTED : ks->driver->copy_owner(ks, source, target); } /* * Type safe casts. */ static inline hal_ks_block_type_t hal_ks_block_get_type(const hal_ks_block_t * const block) { return block == NULL ? HAL_KS_BLOCK_TYPE_UNKNOWN : (hal_ks_block_type_t) block->header.block_type; } static inline hal_ks_block_status_t hal_ks_block_get_status(const hal_ks_block_t * const block) { return block == NULL ? HAL_KS_BLOCK_STATUS_UNKNOWN : (hal_ks_block_status_t) block->header.block_status; } /* * Keystore utilities. Some or all of these may end up static within ks.c. */ extern hal_error_t hal_ks_alloc_common(hal_ks_t *ks, const unsigned ks_blocks, const unsigned cache_blocks, void **extra, const size_t extra_len); extern hal_error_t hal_ks_init_common(hal_ks_t *ks); extern hal_crc32_t hal_ks_block_calculate_crc(const hal_ks_block_t * const block); extern hal_error_t hal_ks_index_heapsort(hal_ks_t *ks); extern hal_error_t hal_ks_index_find(hal_ks_t *ks, const hal_uuid_t * const name, unsigned *blockno, int *hint); extern hal_error_t hal_ks_index_add(hal_ks_t *ks, const hal_uuid_t * const name, unsigned *blockno, int *hint); extern hal_error_t hal_ks_index_delete(hal_ks_t *ks, const hal_uuid_t * const name, unsigned *blockno, int *hint); extern hal_error_t hal_ks_index_replace(hal_ks_t *ks, const hal_uuid_t * const name, unsigned *blockno, int *hint); extern hal_error_t hal_ks_index_fsck(hal_ks_t *ks); extern const size_t hal_ks_attribute_header_size; extern hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes, const size_t bytes_len, hal_pkey_attribute_t *attributes, const unsigned attributes_len, size_t *total_len); extern hal_error_t hal_ks_attribute_delete(uint8_t *bytes, const size_t bytes_len, hal_pkey_attribute_t *attributes, unsigned *attributes_len, size_t *total_len, const uint32_t type); extern hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len, hal_pkey_attribute_t *attributes, unsigned *attributes_len, size_t *total_len, const uint32_t type, const uint8_t * const value, const size_t value_len); extern hal_ks_block_t *hal_ks_cache_pick_lru(hal_ks_t *ks); extern hal_ks_block_t *hal_ks_cache_find_block(const hal_ks_t * const ks, const unsigned blockno); extern void hal_ks_cache_mark_used(hal_ks_t *ks, const hal_ks_block_t * const block, const unsigned blockno); extern void hal_ks_cache_release(hal_ks_t *ks, const hal_ks_block_t * const block); extern hal_error_t hal_ks_block_read_cached(hal_ks_t *ks, const unsigned blockno, hal_ks_block_t **block); extern hal_error_t hal_ks_block_update(hal_ks_t *ks, const unsigned b1, hal_ks_block_t *block, const hal_uuid_t * const uuid, int *hint); #endif /* _KS_H_ */ /* * Local variables: * indent-tabs-mode: nil * End: */