[Cryptech-Commits] [sw/libhal] 02/08: Checkpoint along the way to adding keystore attribute support.

git at cryptech.is git at cryptech.is
Sun Oct 16 20:23:42 UTC 2016


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch ksng
in repository sw/libhal.

commit db32574d6c85bb48a2f01d80eec6e241152704ff
Author: Rob Austein <sra at hactrn.net>
AuthorDate: Fri Oct 7 17:32:14 2016 -0400

    Checkpoint along the way to adding keystore attribute support.
    
    This is mostly to archive a commit where PKCS #11 "make test" still
    works after converting the ks_volatile code to use SDRAM allocated at
    startup instead of (large) static variables.
    
    The attribute code itself is incomplete at this point.
---
 Makefile       |   2 +-
 hal.h          |  33 ++++++++++
 hal_internal.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++
 ks_attribute.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ks_flash.c     |  56 ++++++++++++++--
 ks_volatile.c  | 136 ++++++++++++++++++++++++++++++--------
 rpc_api.c      |  50 ++++++++++++++
 rpc_client.c   | 152 ++++++++++++++++++++++++++++++++++++++++--
 rpc_pkey.c     |  94 +++++++++++++++++++++++++-
 rpc_server.c   | 153 +++++++++++++++++++++++++++++++++++++++---
 10 files changed, 1003 insertions(+), 51 deletions(-)

diff --git a/Makefile b/Makefile
index b4c6086..afde6c4 100644
--- a/Makefile
+++ b/Makefile
@@ -118,7 +118,7 @@ endif
 #
 # The mmap keystore hasn't been rewritten for the new API yet.
 
-KS_OBJ = ks_index.o ks_volatile.o
+KS_OBJ = ks_index.o ks_attribute.o ks_volatile.o
 
 ifeq "${KS}" "mmap"
   KS_OBJ += ks_mmap.o
diff --git a/hal.h b/hal.h
index e94f3b8..5b4de69 100644
--- a/hal.h
+++ b/hal.h
@@ -147,6 +147,7 @@
   DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_BAD_CRC,          "Bad CRC in keystore")                          \
   DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE,   "Unsupported keystore block type")              \
   DEFINE_HAL_ERROR(HAL_ERROR_KEYSTORE_LOST_DATA,        "Keystore appears to have lost data")           \
+  DEFINE_HAL_ERROR(HAL_ERROR_BAD_ATTRIBUTE_LENGTH,      "Bad attribute length")                         \
   END_OF_HAL_ERROR_LIST
 
 /* Marker to forestall silly line continuation errors */
@@ -735,6 +736,8 @@ extern size_t hal_rpc_pkey_get_public_key_len(const hal_pkey_handle_t pkey);
 extern hal_error_t hal_rpc_pkey_get_public_key(const hal_pkey_handle_t pkey,
                                                uint8_t *der, size_t *der_len, const size_t der_max);
 
+#warning Um, why do hal_rpc_pkey_sign() and hal_rpc_pkey_verify() take session arguments?
+
 extern hal_error_t hal_rpc_pkey_sign(const hal_session_handle_t session,
                                      const hal_pkey_handle_t pkey,
                                      const hal_hash_handle_t hash,
@@ -760,6 +763,36 @@ extern hal_error_t hal_rpc_pkey_list(hal_pkey_info_t *result,
                                      const unsigned result_max,
                                      hal_key_flags_t flags);
 
+typedef struct {
+  uint32_t type;
+  size_t length;
+  const uint8_t *value;
+} hal_rpc_pkey_attribute_t;
+
+extern hal_error_t hal_rpc_pkey_match(const hal_key_type_t type,
+                                      const hal_curve_name_t curve,
+                                      const hal_key_flags_t flags,
+                                      hal_rpc_pkey_attribute_t *attributes,
+                                      const unsigned attributes_len,
+                                      hal_uuid_t *result,
+                                      unsigned *result_len,
+                                      const unsigned result_max,
+                                      hal_uuid_t *previous_uuid);
+
+extern hal_error_t hal_rpc_pkey_set_attribute(const hal_pkey_handle_t pkey,
+                                              const uint32_t type,
+                                              const uint8_t * const value,
+                                              const size_t value_len);
+
+extern hal_error_t hal_rpc_pkey_get_attribute(const hal_pkey_handle_t pkey,
+                                              const uint32_t type,
+                                              uint8_t *value,
+                                              size_t *value_len,
+                                              const size_t value_max);
+
+extern hal_error_t hal_rpc_pkey_delete_attribute(const hal_pkey_handle_t pkey,
+                                                 const uint32_t type);
+
 extern hal_error_t hal_rpc_client_init(void);
 
 extern hal_error_t hal_rpc_client_close(void);
diff --git a/hal_internal.h b/hal_internal.h
index 11f9898..0d40922 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -242,6 +242,30 @@ typedef struct {
                        const unsigned result_max,
                        hal_key_flags_t flags);
 
+  hal_error_t (*match)(const hal_key_type_t type,
+                       const hal_curve_name_t curve,
+                       const hal_key_flags_t flags,
+                       hal_rpc_pkey_attribute_t *attributes,
+                       const unsigned attributes_len,
+                       hal_uuid_t *result,
+                       unsigned *result_len,
+                       const unsigned result_max,
+                       hal_uuid_t *previous_uuid);
+
+  hal_error_t (*set_attribute)(const hal_pkey_handle_t pkey,
+                               const uint32_t type,
+                               const uint8_t * const value,
+                               const size_t value_len);
+
+  hal_error_t (*get_attribute)(const hal_pkey_handle_t pkey,
+                               const uint32_t type,
+                               uint8_t *value,
+                               size_t *value_len,
+                               const size_t value_max);
+
+  hal_error_t (*delete_attribute)(const hal_pkey_handle_t pkey,
+                                  const uint32_t type);
+
 } hal_rpc_pkey_dispatch_t;
 
 
@@ -470,6 +494,35 @@ struct hal_ks_driver {
 		      hal_pkey_info_t *result,
 		      unsigned *result_len,
 		      const unsigned result_max);
+
+  hal_error_t (*match)(hal_ks_t *ks,
+                       const hal_key_type_t type,
+                       const hal_curve_name_t curve,
+                       const hal_key_flags_t flags,
+                       hal_rpc_pkey_attribute_t *attributes,
+                       const unsigned attributes_len,
+                       hal_uuid_t *result,
+                       unsigned *result_len,
+                       const unsigned result_max,
+                       hal_uuid_t *previous_uuid);
+
+  hal_error_t (*set_attribute)(hal_ks_t *ks,
+                               hal_pkey_slot_t *slot,
+                               const uint32_t type,
+                               const uint8_t * const value,
+                               const size_t value_len);
+
+  hal_error_t (*get_attribute)(hal_ks_t *ks,
+                               hal_pkey_slot_t *slot,
+                               const uint32_t type,
+                               uint8_t *value,
+                               size_t *value_len,
+                               const size_t value_max);
+
+  hal_error_t (*delete_attribute)(hal_ks_t *ks,
+                                  hal_pkey_slot_t *slot,
+                                  const uint32_t type);
+
 };
 
 
@@ -563,6 +616,59 @@ static inline hal_error_t hal_ks_list(hal_ks_t *ks,
   return ks->driver->list(ks, result, result_len, result_max);
 }
 
+static inline hal_error_t hal_ks_match(hal_ks_t *ks,
+                                       const hal_key_type_t type,
+                                       const hal_curve_name_t curve,
+                                       const hal_key_flags_t flags,
+                                       hal_rpc_pkey_attribute_t *attributes,
+                                       const unsigned attributes_len,
+                                       hal_uuid_t *result,
+                                       unsigned *result_len,
+                                       const unsigned result_max,
+                                       hal_uuid_t *previous_uuid)
+{
+  if (ks == NULL || ks->driver == NULL || ks->driver->match == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  return ks->driver->match(ks, type, curve, flags, attributes, attributes_len,
+                           result, result_len, result_max, previous_uuid);
+}
+
+static inline  hal_error_t hal_ks_set_attribute(hal_ks_t *ks,
+                                                hal_pkey_slot_t *slot,
+                                                const uint32_t type,
+                                                const uint8_t * const value,
+                                                const size_t value_len)
+{
+  if (ks == NULL || ks->driver == NULL || ks->driver->set_attribute == NULL || slot == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  return ks->driver->set_attribute(ks, slot, type, value, value_len);
+}
+
+static inline hal_error_t hal_ks_get_attribute(hal_ks_t *ks,
+                               hal_pkey_slot_t *slot,
+                               const uint32_t type,
+                               uint8_t *value,
+                               size_t *value_len,
+                               const size_t value_max)
+{
+  if (ks == NULL || ks->driver == NULL || ks->driver->get_attribute == NULL || slot == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  return ks->driver->get_attribute(ks, slot, type, value, value_len, value_max);
+}
+
+static inline hal_error_t hal_ks_delete_attribute(hal_ks_t *ks,
+                                  hal_pkey_slot_t *slot,
+                                  const uint32_t type)
+{
+  if (ks == NULL || ks->driver == NULL || ks->driver->delete_attribute == NULL || slot == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  return ks->driver->delete_attribute(ks, slot, type);
+}
+
 /*
  * Keystore index.  This is intended to be usable by both memory-based
  * (in-memory, mmap(), ...) keystores and keystores based on raw flash.
@@ -676,6 +782,69 @@ extern hal_error_t hal_ks_index_replace(hal_ks_index_t *ksi,
                                         int *hint);
 
 /*
+ * Keystore attribute utilities, for use by keystore drivers.
+ *
+ * Basic model here is probably to replace the "der" block in a key
+ * object with a byte array.  We could use padding to get alignment,
+ * but it's probably easier just to do this DNS style, pulling a
+ * 16-bit length and 32-bit attribute type out of the byte array
+ * directly.  Well, maybe.  I guess if we cast the uint8_t* to a
+ * structure pointer we could use the structure to pull out the header
+ * fields, but that has portability issues, particulary if the
+ * compiler gets tetchy about type punning.
+ *
+ * Unclear whether we should treat the key DER specially.  Might just
+ * give it an attribute code of 0xFFFFFFFF and treat it same as
+ * everything else, just always first for convenience.  This assumes
+ * that PKCS #11 will never use 0xFFFFFFFF, which is a bit risky, but
+ * maybe the code just treats it a little bit specially and knows to
+ * skip over the key DER when looking for attributes, etc.
+ *
+ * We probably don't want to let attributes span block boundaries.  We
+ * probably do want to attempt to fit a new attribute into the first
+ * available space which can hold it.  In theory, taken together, this
+ * means we will only have to update multiple blocks when required to
+ * add a new block (in which case the max_blocks count changes).  Most
+ * of this only applies to flash, for volatile we can use as much
+ * memory as we like, although even there we might want smaller chunks
+ * to avoid wasting huge tracts of space that don't end up being used.
+ * But maybe that's just a configuration thing for the volatile
+ * keystore(s).
+ *
+ * If we have to rewrite a block at all we might as well compact it,
+ * so fragmentation in that sense is a non-issue.  Might need to
+ * collapse blocks when deletion has freed up enough space, but that
+ * might be something we handle directly in ks_flash rather than in
+ * the ks_attribute code.
+ *
+ * We need some way of figuring out how many attributes there are.
+ * Options are a marker (like the IPv4 END-OF-OPTIONS option) or a
+ * count in the header.  Count is simpler and lets us pre-allocate
+ * arrays so probably go with that.
+ */
+
+extern hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes,
+                                         const size_t bytes_len,
+                                         hal_rpc_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_rpc_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_rpc_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);
+
+/*
  * RPC lowest-level send and receive routines. These are blocking, and
  * transport-specific (sockets, USB).
  */
@@ -725,6 +894,10 @@ typedef enum {
     RPC_FUNC_PKEY_VERIFY,
     RPC_FUNC_PKEY_LIST,
     RPC_FUNC_PKEY_RENAME,
+    RPC_FUNC_PKEY_MATCH,
+    RPC_FUNC_PKEY_SET_ATTRIBUTE,
+    RPC_FUNC_PKEY_GET_ATTRIBUTE,
+    RPC_FUNC_PKEY_DELETE_ATTRIBUTE,
 } rpc_func_num_t;
 
 #define RPC_VERSION 0x01010000          /* 1.1.0.0 */
diff --git a/ks_attribute.c b/ks_attribute.c
new file mode 100644
index 0000000..248f98d
--- /dev/null
+++ b/ks_attribute.c
@@ -0,0 +1,205 @@
+/*
+ * ks_attribute.c
+ * --------------
+ * Keystore attribute API.  This is internal within libhal.
+ *
+ * Copyright (c) 2016, 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 <string.h>
+#include <assert.h>
+
+#include "hal.h"
+#include "hal_internal.h"
+
+/*
+ * Read and write attribute headers (type and length).  We could do
+ * this with a structure type and casts, but that has portability
+ * issues, and doing it this way just isn't expensive enough to worry about.
+ */
+
+#define HEADER_LEN      (4 + 2)
+
+static inline hal_error_t read_header(const uint8_t * const bytes, const size_t bytes_len,
+                                      uint32_t *attribute_type, size_t *attribute_len)
+{
+  if (bytes == NULL || bytes_len < HEADER_LEN || attribute_type == NULL || attribute_len == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  *attribute_type = ((bytes[0] << 24) |
+                     (bytes[1] << 16) |
+                     (bytes[2] <<  8) |
+                     (bytes[3] <<  0));
+  *attribute_len  = ((bytes[4] <<  8) |
+                     (bytes[5] <<  0));
+
+  return HAL_OK;
+}
+
+static inline hal_error_t write_header(uint8_t *bytes, const size_t bytes_len,
+                                       const uint32_t attribute_type, const size_t attribute_len)
+{
+  if (bytes == NULL || bytes_len < HEADER_LEN)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  bytes[0] = (attribute_type >> 24) & 0xFF;
+  bytes[1] = (attribute_type >> 16) & 0xFF;
+  bytes[2] = (attribute_type >>  8) & 0xFF;
+  bytes[3] = (attribute_type >>  0) & 0xFF;
+  bytes[4] = (attribute_len  >>  8) & 0xFF;
+  bytes[5] = (attribute_len  >>  0) & 0xFF;
+
+  return HAL_OK;
+}
+
+hal_error_t hal_ks_attribute_scan(const uint8_t * const bytes, const size_t bytes_len,
+                                  hal_rpc_pkey_attribute_t *attributes, const unsigned attributes_len,
+                                  size_t *total_len)
+{
+  if (bytes == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  const uint8_t *b = bytes;
+  const uint8_t * const end = bytes + bytes_len;
+
+  for (int i = 0; i < attributes_len; i++) {
+    uint32_t type;
+    size_t length;
+    hal_error_t err = read_header(b, end - b, &type, &length);
+    if (err != HAL_OK)
+      return err;
+    b += HEADER_LEN;
+    if (attributes != NULL) {
+      attributes[i].type   = type;
+      attributes[i].length = length;
+      attributes[i].value  = b;
+    }
+    b += length;
+    if (b > end)
+      return HAL_ERROR_BAD_ATTRIBUTE_LENGTH;
+  }
+
+  if (total_len != NULL)
+    *total_len = b - bytes;
+
+  return HAL_OK;
+}
+
+/*
+ * Given scan(), delete() and insert() should be relatively simple.
+ *
+ * delete() does a scan to find the attribute it wants to delete, and,
+ * if found, uses memmove() to copy the rest down.
+ *
+ * insert() does a delete to get rid of old value, if any, then does
+ * another scan, checks length what we want to insert against
+ * total_len returned by the scan, and either appends the new
+ * attribute or returns error code saying it couldn't.
+ */
+
+hal_error_t hal_ks_attribute_delete(uint8_t *bytes, const size_t bytes_len,
+                                    hal_rpc_pkey_attribute_t *attributes, unsigned *attributes_len,
+                                    size_t *total_len,
+                                    const uint32_t type)
+{
+  if (bytes == NULL || attributes == NULL || attributes_len == NULL || total_len == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  int i = 0;
+
+  while (i < *attributes_len && attributes[i].type != type)
+    i++;
+
+  if (i == *attributes_len)
+    return HAL_OK;
+
+  const size_t delete_length = HEADER_LEN + attributes[i].length;
+  const size_t delete_offset = attributes[i].value - HEADER_LEN - bytes;
+
+  if (delete_offset + delete_length > *total_len)
+    return HAL_ERROR_IMPOSSIBLE;
+
+  memmove(bytes + delete_offset,
+          bytes + delete_offset + delete_length,
+          *total_len - delete_length - delete_offset);
+
+  *total_len -= delete_length;
+
+  memmove(&attributes[i], &attributes[i + 1], *attributes_len - i - 1);
+
+  --*attributes_len;
+
+  return HAL_OK;
+}
+
+hal_error_t hal_ks_attribute_insert(uint8_t *bytes, const size_t bytes_len,
+                                   hal_rpc_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)
+
+{
+  if (bytes == NULL || attributes == NULL || attributes_len == NULL ||
+      total_len == NULL || value == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  hal_error_t err
+    = hal_ks_attribute_delete(bytes, bytes_len, attributes, attributes_len, total_len, type);
+
+  if (err != HAL_OK)
+    return err;
+
+  if (*total_len + HEADER_LEN + value_len > bytes_len)
+    return HAL_ERROR_RESULT_TOO_LONG;
+
+  uint8_t *b = bytes + *total_len;
+
+  if ((err = write_header(b, bytes_len - *total_len, type, value_len)) != HAL_OK)
+    return err;
+
+  b += HEADER_LEN;
+
+  memcpy(b, value, value_len);
+
+  *total_len += HEADER_LEN + value_len;
+
+  attributes[*attributes_len].type   = type;
+  attributes[*attributes_len].length = value_len;
+  attributes[*attributes_len].value  = b;
+
+  ++*attributes_len;
+
+  return HAL_OK;
+}
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/ks_flash.c b/ks_flash.c
index 475dcde..5b3f718 100644
--- a/ks_flash.c
+++ b/ks_flash.c
@@ -174,10 +174,9 @@ typedef struct {
 const static hal_uuid_t pin_uuid = {{0}};
 
 /*
- * The in-memory database almost certainly should be a pointer to
- * allocated SDRAM rather than compile-time data space.  Well,
- * the arrays should be, anyway, it might be reasonable to keep
- * the top level structure here.  Worry about that later.
+ * The in-memory database structure itself is small, but the arrays it
+ * points to are large enough that they come from SDRAM allocated at
+ * startup.
  */
 
 static db_t db;
@@ -201,7 +200,7 @@ static inline flash_block_status_t block_get_status(const flash_block_t * const
 /*
  * Pick unused or least-recently-used slot in our in-memory cache.
  *
- * Updating lru values is caller's problem: if caller is using cache
+ * Updating lru values is caller's problem: if caller is using a cache
  * slot as a temporary buffer and there's no point in caching the
  * result, leave the lru values alone and the right thing will happen.
  */
@@ -432,7 +431,6 @@ static hal_error_t block_erase(const unsigned blockno)
 
 /*
  * Erase a flash block if it hasn't already been erased.
- * We have to disable fast read for this to work properly.
  * May not be necessary, trying to avoid unnecessary wear.
  *
  * Unclear whether there's any sane reason why this needs to be
@@ -1033,6 +1031,46 @@ static hal_error_t ks_list(hal_ks_t *ks,
   return HAL_OK;
 }
 
+static hal_error_t ks_match(hal_ks_t *ks,
+                            const hal_key_type_t type,
+                            const hal_curve_name_t curve,
+                            const hal_key_flags_t flags,
+                            hal_rpc_pkey_attribute_t *attributes,
+                            const unsigned attributes_len,
+                            hal_uuid_t *result,
+                            unsigned *result_len,
+                            const unsigned result_max,
+                            hal_uuid_t *previous_uuid)
+{
+#warning NIY
+}
+
+static  hal_error_t ks_set_attribute(hal_ks_t *ks,
+                                     hal_pkey_slot_t *slot,
+                                     const uint32_t type,
+                                     const uint8_t * const value,
+                                     const size_t value_len)
+{
+#warning NIY
+}
+
+static  hal_error_t ks_get_attribute(hal_ks_t *ks,
+                                     hal_pkey_slot_t *slot,
+                                     const uint32_t type,
+                                     uint8_t *value,
+                                     size_t *value_len,
+                                     const size_t value_max)
+{
+#warning NIY
+}
+
+static hal_error_t ks_delete_attribute(hal_ks_t *ks,
+                                       hal_pkey_slot_t *slot,
+                                       const uint32_t type)
+{
+#warning NIY
+}
+
 const hal_ks_driver_t hal_ks_token_driver[1] = {{
   ks_init,
   ks_shutdown,
@@ -1041,7 +1079,11 @@ const hal_ks_driver_t hal_ks_token_driver[1] = {{
   ks_store,
   ks_fetch,
   ks_delete,
-  ks_list
+  ks_list,
+  ks_match,
+  ks_set_attribute,
+  ks_get_attribute,
+  ks_delete_attribute
 }};
 
 /*
diff --git a/ks_volatile.c b/ks_volatile.c
index 29793a4..daaef41 100644
--- a/ks_volatile.c
+++ b/ks_volatile.c
@@ -48,12 +48,10 @@
 #define HAL_STATIC_PKEY_STATE_BLOCKS 0
 #endif
 
-#ifndef HAL_STATIC_KS_VOLATILE_SLOTS
-#define HAL_STATIC_KS_VOLATILE_SLOTS HAL_STATIC_PKEY_STATE_BLOCKS
+#ifndef HAL_KS_VOLATILE_SLOTS
+#define HAL_KS_VOLATILE_SLOTS HAL_STATIC_PKEY_STATE_BLOCKS
 #endif
 
-#if HAL_STATIC_KS_VOLATILE_SLOTS > 0
-
 /*
  * In-memory keystore database.  This should also be usable for
  * mmap(), if and when we get around to rewriting that driver (and in
@@ -70,9 +68,7 @@ typedef struct {
 
 typedef struct {
   hal_ks_index_t        ksi;
-  uint16_t              _index[HAL_STATIC_KS_VOLATILE_SLOTS];
-  hal_ks_name_t         _names[HAL_STATIC_KS_VOLATILE_SLOTS];
-  ks_key_t              keys[HAL_STATIC_KS_VOLATILE_SLOTS];
+  ks_key_t              *keys;
 } db_t;
 
 /*
@@ -87,7 +83,14 @@ typedef struct {
   db_t *db;                 /* Which memory-based keystore database */
 } ks_t;
 
-static db_t volatile_db;
+/*
+ * If we also supported mmap, there would be a separate definition for
+ * HAL_KS_MMAP_SLOTS above, and the bulk of the code would be under a
+ * conditional testing whether either HAL_KS_*_SLOTS were nonzero.
+ */
+
+#if HAL_KS_VOLATILE_SLOTS > 0
+
 static ks_t volatile_ks;
 
 static inline ks_t *ks_to_ksv(hal_ks_t *ks)
@@ -95,9 +98,39 @@ static inline ks_t *ks_to_ksv(hal_ks_t *ks)
   return (ks_t *) ks;
 }
 
-static hal_error_t ks_init(db_t *db)
+static inline void *gnaw(uint8_t **mem, size_t *len, const size_t size)
+{
+  if (mem == NULL || *mem == NULL || len == NULL || size > *len)
+    return NULL;
+  void *ret = *mem;
+  *mem += size;
+  *len -= size;
+  return ret;
+}
+
+static hal_error_t ks_init(const hal_ks_driver_t * const driver,
+                           ks_t *ksv,
+                           uint8_t *mem,
+                           size_t len)
 {
-  assert(db != NULL);
+  if (ksv == NULL || mem == NULL)
+    return HAL_ERROR_IMPOSSIBLE;
+
+  memset(ksv, 0, sizeof(*ksv));
+  memset(mem, 0, len);
+
+  if ((ksv->db = gnaw(&mem, &len, sizeof(*ksv->db))) == NULL ||
+      (ksv->db->ksi.index = gnaw(&mem, &len,
+                                 sizeof(*ksv->db->ksi.index) * HAL_KS_VOLATILE_SLOTS)) == NULL ||
+      (ksv->db->ksi.names = gnaw(&mem, &len,
+                                 sizeof(*ksv->db->ksi.names) * HAL_KS_VOLATILE_SLOTS)) == NULL ||
+      (ksv->db->keys      = gnaw(&mem, &len,
+                                 sizeof(*ksv->db->keys)      * HAL_KS_VOLATILE_SLOTS)) == NULL)
+    return HAL_ERROR_IMPOSSIBLE;
+
+  ksv->ks.driver     = driver;
+  ksv->db->ksi.size  = HAL_KS_VOLATILE_SLOTS;
+  ksv->db->ksi.used  = 0;
 
   /*
    * Set up keystore with empty index and full free list.
@@ -105,34 +138,31 @@ static hal_error_t ks_init(db_t *db)
    * just populate the free list in block numerical order.
    */
 
-  db->ksi.size  = HAL_STATIC_KS_VOLATILE_SLOTS;
-  db->ksi.used  = 0;
-  db->ksi.index = db->_index;
-  db->ksi.names = db->_names;
-
-  for (int i = 0; i < HAL_STATIC_KS_VOLATILE_SLOTS; i++)
-    db->_index[i] = i;
+  for (int i = 0; i < HAL_KS_VOLATILE_SLOTS; i++)
+    ksv->db->ksi.index[i] = i;
 
-  const hal_error_t err = hal_ks_index_setup(&db->ksi);
-
-  if (err != HAL_OK)
-    db->ksi.size = 0;           /* Mark uninitialized if setup failed */
-
-  return err;
+  return hal_ks_index_setup(&ksv->db->ksi);
 }
 
 static hal_error_t ks_volatile_init(const hal_ks_driver_t * const driver)
 {
-  volatile_ks.ks.driver = driver;
-  volatile_ks.db = &volatile_db;
-  return ks_init(volatile_ks.db);
+  const size_t len = (sizeof(*volatile_ks.db) +
+                      sizeof(*volatile_ks.db->ksi.index) * HAL_KS_VOLATILE_SLOTS +
+                      sizeof(*volatile_ks.db->ksi.names) * HAL_KS_VOLATILE_SLOTS +
+                      sizeof(*volatile_ks.db->keys)      * HAL_KS_VOLATILE_SLOTS);
+
+  uint8_t *mem = hal_allocate_static_memory(len);
+
+  if (mem == NULL)
+    return HAL_ERROR_ALLOCATION_FAILURE;
+
+  return ks_init(driver, &volatile_ks, mem, len);
 }
 
 static hal_error_t ks_volatile_shutdown(const hal_ks_driver_t * const driver)
 {
   if (volatile_ks.ks.driver != driver)
     return HAL_ERROR_KEYSTORE_ACCESS;
-  memset(&volatile_ks, 0, sizeof(volatile_ks));
   return HAL_OK;
 }
 
@@ -303,6 +333,50 @@ static hal_error_t ks_list(hal_ks_t *ks,
   return HAL_OK;
 }
 
+static hal_error_t ks_match(hal_ks_t *ks,
+                            const hal_key_type_t type,
+                            const hal_curve_name_t curve,
+                            const hal_key_flags_t flags,
+                            hal_rpc_pkey_attribute_t *attributes,
+                            const unsigned attributes_len,
+                            hal_uuid_t *result,
+                            unsigned *result_len,
+                            const unsigned result_max,
+                            hal_uuid_t *previous_uuid)
+{
+#warning NIY
+  return HAL_ERROR_IMPOSSIBLE;
+}
+
+static  hal_error_t ks_set_attribute(hal_ks_t *ks,
+                                     hal_pkey_slot_t *slot,
+                                     const uint32_t type,
+                                     const uint8_t * const value,
+                                     const size_t value_len)
+{
+#warning NIY
+  return HAL_ERROR_IMPOSSIBLE;
+}
+
+static  hal_error_t ks_get_attribute(hal_ks_t *ks,
+                                     hal_pkey_slot_t *slot,
+                                     const uint32_t type,
+                                     uint8_t *value,
+                                     size_t *value_len,
+                                     const size_t value_max)
+{
+#warning NIY
+  return HAL_ERROR_IMPOSSIBLE;
+}
+
+static hal_error_t ks_delete_attribute(hal_ks_t *ks,
+                                       hal_pkey_slot_t *slot,
+                                       const uint32_t type)
+{
+#warning NIY
+  return HAL_ERROR_IMPOSSIBLE;
+}
+
 const hal_ks_driver_t hal_ks_volatile_driver[1] = {{
   ks_volatile_init,
   ks_volatile_shutdown,
@@ -311,10 +385,14 @@ const hal_ks_driver_t hal_ks_volatile_driver[1] = {{
   ks_store,
   ks_fetch,
   ks_delete,
-  ks_list
+  ks_list,
+  ks_match,
+  ks_set_attribute,
+  ks_get_attribute,
+  ks_delete_attribute
 }};
 
-#endif /* HAL_STATIC_KS_VOLATILE_SLOTS > 0 */
+#endif /* HAL_KS_VOLATILE_SLOTS > 0 */
 
 /*
  * Local variables:
diff --git a/rpc_api.c b/rpc_api.c
index a8dc89d..022dc62 100644
--- a/rpc_api.c
+++ b/rpc_api.c
@@ -338,6 +338,56 @@ hal_error_t hal_rpc_pkey_list(hal_pkey_info_t *result,
   return hal_rpc_pkey_dispatch->list(result, result_len, result_max, flags);
 }
 
+hal_error_t hal_rpc_pkey_match(const hal_key_type_t type,
+                               const hal_curve_name_t curve,
+                               const hal_key_flags_t flags,
+                               hal_rpc_pkey_attribute_t *attributes,
+                               const unsigned attributes_len,
+                               hal_uuid_t *result,
+                               unsigned *result_len,
+                               const unsigned result_max,
+                               hal_uuid_t *previous_uuid)
+{
+  if ((attributes == NULL && attributes_len > 0) || previous_uuid == NULL ||
+      result == NULL || result_len == NULL || result_max == 0)
+    return HAL_ERROR_BAD_ARGUMENTS;
+
+  if (attributes != NULL)
+    for (int i = 0; i < attributes_len; i++)
+      if (attributes[i].value == NULL)
+        return HAL_ERROR_BAD_ARGUMENTS;
+
+  return hal_rpc_pkey_dispatch->match(type, curve, flags, attributes, attributes_len,
+                                      result, result_len, result_max, previous_uuid);
+}
+
+hal_error_t hal_rpc_pkey_set_attribute(const hal_pkey_handle_t pkey,
+                                       const uint32_t type,
+                                       const uint8_t * const value,
+                                       const size_t value_len)
+{
+  if (value == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+  return hal_rpc_pkey_dispatch->set_attribute(pkey, type, value, value_len);
+}
+
+hal_error_t hal_rpc_pkey_get_attribute(const hal_pkey_handle_t pkey,
+                                       const uint32_t type,
+                                       uint8_t *value,
+                                       size_t *value_len,
+                                       const size_t value_max)
+{
+  if (value == NULL || value_len == NULL)
+    return HAL_ERROR_BAD_ARGUMENTS;
+  return hal_rpc_pkey_dispatch->get_attribute(pkey, type, value, value_len, value_max);
+}
+
+hal_error_t hal_rpc_pkey_delete_attribute(const hal_pkey_handle_t pkey,
+                                          const uint32_t type)
+{
+  return hal_rpc_pkey_dispatch->delete_attribute(pkey, type);
+}
+
 /*
  * Local variables:
  * indent-tabs-mode: nil
diff --git a/rpc_client.c b/rpc_client.c
index b4184d4..a56052d 100644
--- a/rpc_client.c
+++ b/rpc_client.c
@@ -740,7 +740,8 @@ static hal_error_t pkey_remote_verify(const hal_session_handle_t session,
   return rpc_ret;
 }
 
-static hal_error_t hal_xdr_decode_pkey_info(const uint8_t **iptr, const uint8_t * const ilimit, hal_pkey_info_t *info)
+static hal_error_t hal_xdr_decode_pkey_info(const uint8_t **iptr, const uint8_t * const ilimit,
+                                            hal_pkey_info_t *info)
 {
   uint32_t u32;
 
@@ -778,10 +779,9 @@ static hal_error_t pkey_remote_list(hal_pkey_info_t *result,
 
   check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
   if (rpc_ret == HAL_OK) {
-    int i;
     check(hal_xdr_decode_int(&iptr, ilimit, &len));
     *result_len = len;
-    for (i = 0; i < len; ++i) {
+    for (int i = 0; i < len; ++i) {
       if ((ret = hal_xdr_decode_pkey_info(&iptr, ilimit, &result[i])) != HAL_OK) {
         *result_len = 0;
         return ret;
@@ -791,6 +791,140 @@ static hal_error_t pkey_remote_list(hal_pkey_info_t *result,
   return rpc_ret;
 }
 
+static hal_error_t pkey_remote_match(const hal_key_type_t type,
+                                     const hal_curve_name_t curve,
+                                     const hal_key_flags_t flags,
+                                     hal_rpc_pkey_attribute_t *attributes,
+                                     const unsigned attributes_len,
+                                     hal_uuid_t *result,
+                                     unsigned *result_len,
+                                     const unsigned result_max,
+                                     hal_uuid_t *previous_uuid)
+{
+  size_t attributes_buffer_len = 0;
+  if (attributes != NULL)
+    for (int i = 0; i < attributes_len; i++)
+      attributes_buffer_len += attributes[i].length;
+
+  uint8_t outbuf[nargs(8 + attributes_len * 2) + pad(attributes_buffer_len) + pad(sizeof(hal_uuid_t))];
+  uint8_t *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+  uint8_t inbuf[nargs(5) + pad(result_max * sizeof(hal_uuid_t)) + pad(sizeof(hal_uuid_t))];
+  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+  hal_client_handle_t dummy_client = {0};
+  hal_error_t rpc_ret;
+
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_MATCH));
+  check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, type));
+  check(hal_xdr_encode_int(&optr, olimit, curve));
+  check(hal_xdr_encode_int(&optr, olimit, flags));
+  check(hal_xdr_encode_int(&optr, olimit, attributes_len));
+  if (attributes != NULL) {
+    for (int i = 0; i < attributes_len; i++) {
+      check(hal_xdr_encode_int(&optr, olimit, attributes[i].type));
+      check(hal_xdr_encode_buffer(&optr, olimit, attributes[i].value, attributes[i].length));
+    }
+  }
+  check(hal_xdr_encode_int(&optr, olimit, result_max));
+  check(hal_xdr_encode_buffer(&optr, olimit, previous_uuid->uuid, sizeof(previous_uuid->uuid)));
+  check(hal_rpc_send(outbuf, optr - outbuf));
+
+  check(read_matching_packet(RPC_FUNC_PKEY_MATCH, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+  if (rpc_ret == HAL_OK) {
+    uint32_t array_len, uuid_len;
+    *result_len = 0;
+    check(hal_xdr_decode_int(&iptr, ilimit, &array_len));
+    for (int i = 0; i < array_len; ++i) {
+      check(hal_xdr_decode_buffer(&iptr, ilimit, result[i].uuid, &uuid_len));
+      if (uuid_len != sizeof(result[i].uuid))
+        return HAL_ERROR_KEY_NAME_TOO_LONG;
+    }
+    check(hal_xdr_decode_buffer(&iptr, ilimit, previous_uuid->uuid, &uuid_len));
+    if (uuid_len != sizeof(previous_uuid->uuid))
+      return HAL_ERROR_KEY_NAME_TOO_LONG;
+    *result_len = array_len;
+  }
+  return rpc_ret;
+}
+
+static hal_error_t pkey_remote_set_attribute(const hal_pkey_handle_t pkey,
+                                             const uint32_t type,
+                                             const uint8_t * const value,
+                                             const size_t value_len)
+{
+  uint8_t outbuf[nargs(5) + pad(value_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+  uint8_t inbuf[nargs(3)];
+  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+  hal_client_handle_t dummy_client = {0};
+  hal_error_t rpc_ret;
+
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_SET_ATTRIBUTE));
+  check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_xdr_encode_int(&optr, olimit, type));
+  check(hal_xdr_encode_buffer(&optr, olimit, value, value_len));
+  check(hal_rpc_send(outbuf, optr - outbuf));
+
+  check(read_matching_packet(RPC_FUNC_PKEY_SET_ATTRIBUTE, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+  return rpc_ret;
+}
+
+static hal_error_t pkey_remote_get_attribute(const hal_pkey_handle_t pkey,
+                                             const uint32_t type,
+                                             uint8_t *value,
+                                             size_t *value_len,
+                                             const size_t value_max)
+{
+  uint8_t outbuf[nargs(5)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+  uint8_t inbuf[nargs(4) + pad(value_max)];
+  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+  uint32_t vlen32 = value_max;
+  hal_client_handle_t dummy_client = {0};
+  hal_error_t rpc_ret;
+
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_ATTRIBUTE));
+  check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_xdr_encode_int(&optr, olimit, type));
+  check(hal_xdr_encode_int(&optr, olimit, vlen32));
+  check(hal_rpc_send(outbuf, optr - outbuf));
+
+  check(read_matching_packet(RPC_FUNC_PKEY_GET_ATTRIBUTE, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+  if (rpc_ret == HAL_OK) {
+    check(hal_xdr_decode_buffer(&iptr, ilimit, value, &vlen32));
+    *value_len = (size_t) vlen32;
+  }
+
+  return rpc_ret;
+}
+
+static hal_error_t pkey_remote_delete_attribute(const hal_pkey_handle_t pkey,
+                                                const uint32_t type)
+{
+  uint8_t outbuf[nargs(4)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+  uint8_t inbuf[nargs(3)];
+  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+  hal_client_handle_t dummy_client = {0};
+  hal_error_t rpc_ret;
+
+  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_DELETE_ATTRIBUTE));
+  check(hal_xdr_encode_int(&optr, olimit, dummy_client.handle));
+  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
+  check(hal_xdr_encode_int(&optr, olimit, type));
+  check(hal_rpc_send(outbuf, optr - outbuf));
+
+  check(read_matching_packet(RPC_FUNC_PKEY_DELETE_ATTRIBUTE, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+  return rpc_ret;
+}
+
 #if RPC_CLIENT == RPC_CLIENT_MIXED
 
 /*
@@ -918,7 +1052,11 @@ const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = {
   pkey_remote_get_public_key,
   pkey_remote_sign,
   pkey_remote_verify,
-  pkey_remote_list
+  pkey_remote_list,
+  pkey_remote_match,
+  pkey_remote_set_attribute,
+  pkey_remote_get_attribute,
+  pkey_remote_delete_attribute
 };
 
 #if RPC_CLIENT == RPC_CLIENT_MIXED
@@ -935,7 +1073,11 @@ const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
   pkey_remote_get_public_key,
   pkey_mixed_sign,
   pkey_mixed_verify,
-  pkey_remote_list
+  pkey_remote_list,
+  pkey_remote_match,
+  pkey_remote_set_attribute,
+  pkey_remote_get_attribute,
+  pkey_remote_delete_attribute
 };
 #endif /* RPC_CLIENT == RPC_CLIENT_MIXED */
 
diff --git a/rpc_pkey.c b/rpc_pkey.c
index cf0975b..207d980 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -867,6 +867,94 @@ static hal_error_t pkey_local_list(hal_pkey_info_t *result,
   return err;
 }
 
+static hal_error_t pkey_local_match(const hal_key_type_t type,
+                                    const hal_curve_name_t curve,
+                                    const hal_key_flags_t flags,
+                                    hal_rpc_pkey_attribute_t *attributes,
+                                    const unsigned attributes_len,
+                                    hal_uuid_t *result,
+                                    unsigned *result_len,
+                                    const unsigned result_max,
+                                    hal_uuid_t *previous_uuid)
+{
+  hal_ks_t *ks = NULL;
+  hal_error_t err;
+
+  if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
+      (err = hal_ks_match(ks, type, curve, flags, attributes, attributes_len,
+                          result, result_len, result_max, previous_uuid)) == HAL_OK)
+    err = hal_ks_close(ks);
+  else if (ks != NULL)
+    (void) hal_ks_close(ks);
+
+  return err;
+}
+
+static hal_error_t pkey_local_set_attribute(const hal_pkey_handle_t pkey,
+                                            const uint32_t type,
+                                            const uint8_t * const value,
+                                            const size_t value_len)
+{
+  hal_pkey_slot_t *slot = find_handle(pkey);
+
+  if (slot == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  hal_ks_t *ks = NULL;
+  hal_error_t err;
+
+  if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+      (err = hal_ks_set_attribute(ks, slot, type, value, value_len)) == HAL_OK)
+    err = hal_ks_close(ks);
+  else if (ks != NULL)
+    (void) hal_ks_close(ks);
+
+  return err;
+}
+
+static hal_error_t pkey_local_get_attribute(const hal_pkey_handle_t pkey,
+                                            const uint32_t type,
+                                            uint8_t *value,
+                                            size_t *value_len,
+                                            const size_t value_max)
+{
+  hal_pkey_slot_t *slot = find_handle(pkey);
+
+  if (slot == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  hal_ks_t *ks = NULL;
+  hal_error_t err;
+
+  if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+      (err = hal_ks_get_attribute(ks, slot, type, value, value_len, value_max)) == HAL_OK)
+    err = hal_ks_close(ks);
+  else if (ks != NULL)
+    (void) hal_ks_close(ks);
+
+  return err;
+}
+
+static hal_error_t pkey_local_delete_attribute(const hal_pkey_handle_t pkey,
+                                               const uint32_t type)
+{
+  hal_pkey_slot_t *slot = find_handle(pkey);
+
+  if (slot == NULL)
+    return HAL_ERROR_KEY_NOT_FOUND;
+
+  hal_ks_t *ks = NULL;
+  hal_error_t err;
+
+  if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
+      (err = hal_ks_delete_attribute(ks, slot, type)) == HAL_OK)
+    err = hal_ks_close(ks);
+  else if (ks != NULL)
+    (void) hal_ks_close(ks);
+
+  return err;
+}
+
 const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
   pkey_local_load,
   pkey_local_find,
@@ -880,7 +968,11 @@ const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
   pkey_local_get_public_key,
   pkey_local_sign,
   pkey_local_verify,
-  pkey_local_list
+  pkey_local_list,
+  pkey_local_match,
+  pkey_local_set_attribute,
+  pkey_local_get_attribute,
+  pkey_local_delete_attribute
 };
 
 /*
diff --git a/rpc_server.c b/rpc_server.c
index 22e354a..5f3502f 100644
--- a/rpc_server.c
+++ b/rpc_server.c
@@ -560,8 +560,8 @@ static hal_error_t pkey_get_public_key(const uint8_t **iptr, const uint8_t * con
     return ret;
 }
 
-static hal_error_t pkey_remote_sign(const uint8_t **iptr, const uint8_t * const ilimit,
-                                    uint8_t **optr, const uint8_t * const olimit)
+static hal_error_t pkey_sign(const uint8_t **iptr, const uint8_t * const ilimit,
+                             uint8_t **optr, const uint8_t * const olimit)
 {
     hal_client_handle_t client __attribute__((unused));
     hal_session_handle_t session;
@@ -596,8 +596,8 @@ static hal_error_t pkey_remote_sign(const uint8_t **iptr, const uint8_t * const
     return ret;
 }
 
-static hal_error_t pkey_remote_verify(const uint8_t **iptr, const uint8_t * const ilimit,
-                                      uint8_t **optr, const uint8_t * const olimit)
+static hal_error_t pkey_verify(const uint8_t **iptr, const uint8_t * const ilimit,
+                               uint8_t **optr, const uint8_t * const olimit)
 {
     hal_client_handle_t client __attribute__((unused));
     hal_session_handle_t session;
@@ -655,9 +655,8 @@ static hal_error_t pkey_list(const uint8_t **iptr, const uint8_t * const ilimit,
     ret = hal_rpc_local_pkey_dispatch.list(result, &result_len, result_max, flags);
 
     if (ret == HAL_OK) {
-        int i;
         check(hal_xdr_encode_int(optr, olimit, result_len));
-        for (i = 0; i < result_len; ++i) {
+        for (int i = 0; i < result_len; ++i) {
             if ((ret = hal_xdr_encode_pkey_info(optr, olimit, &result[i])) != HAL_OK) {
                 *optr = optr_orig;
                 break;
@@ -668,6 +667,132 @@ static hal_error_t pkey_list(const uint8_t **iptr, const uint8_t * const ilimit,
     return ret;
 }
 
+#warning Which RPC pkey functions take session looks kind of messed up
+// list() and match() probably should take session, sign() and verify() probably should not
+
+static hal_error_t pkey_match(const uint8_t **iptr, const uint8_t * const ilimit,
+                              uint8_t **optr, const uint8_t * const olimit)
+{
+    hal_client_handle_t client;
+    uint32_t type, curve, attributes_len, result_max, previous_uuid_len;
+    const uint8_t *previous_uuid_ptr;
+    hal_key_flags_t flags;
+    hal_error_t ret;
+
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &type));
+    check(hal_xdr_decode_int(iptr, ilimit, &curve));
+    check(hal_xdr_decode_int(iptr, ilimit, &flags));
+    check(hal_xdr_decode_int(iptr, ilimit, &attributes_len));
+
+    hal_rpc_pkey_attribute_t attributes[attributes_len > 0 ? attributes_len : 1];
+
+    for (int i = 0; i < attributes_len; i++) {
+        hal_rpc_pkey_attribute_t *a = &attributes[i];
+        uint32_t value_len;
+        check(hal_xdr_decode_int(iptr, ilimit, &a->type));
+        check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &a->value, &value_len));
+        a->length = value_len;
+    }
+
+    check(hal_xdr_decode_int(iptr, ilimit, &result_max));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &previous_uuid_ptr, &previous_uuid_len));
+
+    if (previous_uuid_len != sizeof(hal_uuid_t))
+        return HAL_ERROR_KEY_NAME_TOO_LONG;
+
+    hal_uuid_t result[result_max];
+    unsigned result_len;
+
+    ret = hal_rpc_local_pkey_dispatch.match(type, curve, flags, attributes, attributes_len,
+                                            result, &result_len, result_max,
+                                            (hal_uuid_t *) previous_uuid_ptr);
+
+    if (ret == HAL_OK) {
+        uint8_t *optr_orig = *optr;
+        check(hal_xdr_encode_int(optr, olimit, result_len));
+        for (int i = 0; i < result_len; ++i) {
+            if ((ret = hal_xdr_encode_buffer(optr, olimit, result[i].uuid,
+                                             sizeof(result[i].uuid))) != HAL_OK) {
+                *optr = optr_orig;
+                break;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static hal_error_t pkey_set_attribute(const uint8_t **iptr, const uint8_t * const ilimit,
+                                      uint8_t **optr, const uint8_t * const olimit)
+{
+    hal_client_handle_t client;
+    hal_pkey_handle_t pkey;
+    uint32_t type;
+    const uint8_t *value;
+    uint32_t value_len;
+    hal_error_t ret;
+
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &type));
+    check(hal_xdr_decode_buffer_in_place(iptr, ilimit, &value, &value_len));
+
+    ret = hal_rpc_local_pkey_dispatch.set_attribute(pkey, type, value, value_len);
+
+    return ret;
+}
+
+static hal_error_t pkey_get_attribute(const uint8_t **iptr, const uint8_t * const ilimit,
+                                      uint8_t **optr, const uint8_t * const olimit)
+{
+    hal_client_handle_t client;
+    hal_pkey_handle_t pkey;
+    uint32_t type;
+    size_t value_len;
+    uint32_t value_max;
+    uint8_t *optr_orig = *optr;
+    hal_error_t ret;
+
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &type));
+    check(hal_xdr_decode_int(iptr, ilimit, &value_max));
+    if (value_max > olimit - *optr - 4)
+        return HAL_ERROR_RPC_PACKET_OVERFLOW;
+
+    *optr += 4;
+    ret = hal_rpc_local_pkey_dispatch.get_attribute(pkey, type, *optr, &value_len, value_max);
+
+    if (ret == HAL_OK) {
+        *optr = optr_orig;
+        check(hal_xdr_encode_int(optr, olimit, value_len));
+        *optr += pad(value_len);
+    }
+    else {
+        *optr = optr_orig;
+    }
+
+    return ret;
+}
+
+static hal_error_t pkey_delete_attribute(const uint8_t **iptr, const uint8_t * const ilimit,
+                                         uint8_t **optr, const uint8_t * const olimit)
+{
+    hal_client_handle_t client;
+    hal_pkey_handle_t pkey;
+    uint32_t type;
+    hal_error_t ret;
+
+    check(hal_xdr_decode_int(iptr, ilimit, &client.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &pkey.handle));
+    check(hal_xdr_decode_int(iptr, ilimit, &type));
+
+    ret = hal_rpc_local_pkey_dispatch.delete_attribute(pkey, type);
+
+    return ret;
+}
+
 hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ilen,
                                     uint8_t * const obuf, size_t * const olen)
 {
@@ -753,14 +878,26 @@ hal_error_t hal_rpc_server_dispatch(const uint8_t * const ibuf, const size_t ile
         ret = pkey_get_public_key(&iptr, ilimit, &optr, olimit);
         break;
     case RPC_FUNC_PKEY_SIGN:
-        ret = pkey_remote_sign(&iptr, ilimit, &optr, olimit);
+        ret = pkey_sign(&iptr, ilimit, &optr, olimit);
         break;
     case RPC_FUNC_PKEY_VERIFY:
-        ret = pkey_remote_verify(&iptr, ilimit, &optr, olimit);
+        ret = pkey_verify(&iptr, ilimit, &optr, olimit);
         break;
     case RPC_FUNC_PKEY_LIST:
         ret = pkey_list(&iptr, ilimit, &optr, olimit);
         break;
+    case RPC_FUNC_PKEY_MATCH:
+        ret = pkey_match(&iptr, ilimit, &optr, olimit);
+        break;
+    case RPC_FUNC_PKEY_SET_ATTRIBUTE:
+        ret = pkey_set_attribute(&iptr, ilimit, &optr, olimit);
+        break;
+    case RPC_FUNC_PKEY_GET_ATTRIBUTE:
+        ret = pkey_get_attribute(&iptr, ilimit, &optr, olimit);
+        break;
+    case RPC_FUNC_PKEY_DELETE_ATTRIBUTE:
+        ret = pkey_delete_attribute(&iptr, ilimit, &optr, olimit);
+        break;
     default:
         ret = HAL_ERROR_RPC_BAD_FUNCTION;
         break;



More information about the Commits mailing list