aboutsummaryrefslogtreecommitdiff
path: root/py11/types.py
blob: 4d0b27931eabba27833c94170e491d96fc84bc3a (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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# An attempt at a Python interface to PKCS 11 using the scary ctypes
# module from the Python standard library.

from ctypes import *

# This code is derived from the RSA PKCS #11 C header files, which say:
#
# License to copy and use this software is granted provided that it is
# identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
# (Cryptoki)" in all material mentioning or referencing this software.
#
# License is also granted to make and use derivative works provided that
# such works are identified as "derived from the RSA Security Inc. PKCS #11
# Cryptographic Token Interface (Cryptoki)" in all material mentioning or
# referencing the derived work.
#
# RSA Security Inc. makes no representations concerning either the
# merchantability of this software or the suitability of this software for
# any particular purpose. It is provided "as is" without express or implied
# warranty of any kind.

# This is not a complete set of PKCS #11 types, because the full set
# with all the optional mechanisms is tediously long and each
# structure type requires hand conversion.  Goal at the moment is to
# cover stuff we care about in the base specification.  Add other
# mechanism-specific stuff later as needed.

# Mapping beween C and Python at the lowest level isn't perfect
# because characters are integer types in C while they're strings in
# Python.  It looks like we want the string handling in most cases
# other than CK_BBOOL and CK_VERSION, map lowest-level PKCS #11 types
# accordingly.

CK_BYTE                                 = c_char
CK_CHAR                                 = CK_BYTE
CK_UTF8CHAR                             = CK_BYTE
CK_BBOOL                                = c_ubyte
CK_ULONG                                = c_ulong
CK_LONG                                 = c_long
CK_FLAGS                                = CK_ULONG
CK_VOID_PTR                             = POINTER(c_char)

CK_BYTE_PTR                             = POINTER(CK_BYTE)
CK_CHAR_PTR                             = POINTER(CK_CHAR)
CK_UTF8CHAR_PTR                         = POINTER(CK_UTF8CHAR)
CK_ULONG_PTR                            = POINTER(CK_ULONG)
CK_VOID_PTR_PTR                         = POINTER(CK_VOID_PTR)

class CK_VERSION (Structure):
  _fields_ = [("major",                 c_ubyte),
              ("minor",                 c_ubyte)]

CK_VERSION_PTR                          = POINTER(CK_VERSION)

class CK_INFO (Structure):
  _fields_ = [("cryptokiVersion",       CK_VERSION),
              ("manufacturerID",        CK_UTF8CHAR * 32),
              ("flags",                 CK_FLAGS),
              ("libraryDescription",    CK_UTF8CHAR * 32),
              ("libraryVersion",        CK_VERSION)]

CK_INFO_PTR                             = POINTER(CK_INFO)

CK_NOTIFICATION                         = CK_ULONG

CK_SLOT_ID                              = CK_ULONG

CK_SLOT_ID_PTR                          = POINTER(CK_SLOT_ID)

class CK_SLOT_INFO (Structure):
  _fields_ = [("slotDescription",       CK_UTF8CHAR * 64),
              ("manufacturerID",        CK_UTF8CHAR * 32),
              ("flags",                 CK_FLAGS),
              ("hardwareVersion",       CK_VERSION),
              ("firmwareVersion",       CK_VERSION)]

CK_SLOT_INFO_PTR                        = POINTER(CK_SLOT_INFO)

class CK_TOKEN_INFO (Structure):
  _fields_ = [("label",                 CK_UTF8CHAR * 32),
              ("manufacturerID",        CK_UTF8CHAR * 32),
              ("model",                 CK_UTF8CHAR * 16),
              ("serialNumber",          CK_CHAR * 16),
              ("flags",                 CK_FLAGS),
              ("ulMaxSessionCount",	CK_ULONG),
              ("ulSessionCount",	CK_ULONG),
              ("ulMaxRwSessionCount",	CK_ULONG),
              ("ulRwSessionCount",	CK_ULONG),
              ("ulMaxPinLen",           CK_ULONG),
              ("ulMinPinLen",           CK_ULONG),
              ("ulTotalPublicMemory",	CK_ULONG),
              ("ulFreePublicMemory",	CK_ULONG),
              ("ulTotalPrivateMemory",	CK_ULONG),
              ("ulFreePrivateMemory",	CK_ULONG),
              ("hardwareVersion",	CK_VERSION),
              ("firmwareVersion",	CK_VERSION),
              ("utcTime",               CK_CHAR * 16)]

CK_TOKEN_INFO_PTR                       = POINTER(CK_TOKEN_INFO)

CK_SESSION_HANDLE                       = CK_ULONG

CK_SESSION_HANDLE_PTR                   = POINTER(CK_SESSION_HANDLE)

CK_USER_TYPE                            = CK_ULONG

CK_STATE                                = CK_ULONG

class CK_SESSION_INFO (Structure):
  _fields_ = [("slotID",                CK_SLOT_ID),
              ("state",                 CK_STATE),
              ("flags",                 CK_FLAGS),
              ("ulDeviceError",         CK_ULONG)]

CK_SESSION_INFO_PTR                     = POINTER(CK_SESSION_INFO)

CK_OBJECT_HANDLE                        = CK_ULONG

CK_OBJECT_HANDLE_PTR                    = POINTER(CK_OBJECT_HANDLE)

CK_OBJECT_CLASS                         = CK_ULONG

CK_OBJECT_CLASS_PTR                     = POINTER(CK_OBJECT_CLASS)

CK_HW_FEATURE_TYPE                      = CK_ULONG

CK_KEY_TYPE                             = CK_ULONG

CK_CERTIFICATE_TYPE                     = CK_ULONG

CK_ATTRIBUTE_TYPE                       = CK_ULONG

class CK_ATTRIBUTE (Structure):
  _fields_ = [("type",                  CK_ATTRIBUTE_TYPE),
              ("pValue",                CK_VOID_PTR),
              ("ulValueLen",            CK_ULONG)]

CK_ATTRIBUTE_PTR                        = POINTER(CK_ATTRIBUTE)

class CK_DATE (Structure):
  _fields_ = [("year",                  CK_CHAR * 4),
              ("month",                 CK_CHAR * 2),
              ("day",                   CK_CHAR * 2)]

CK_MECHANISM_TYPE                       = CK_ULONG

CK_MECHANISM_TYPE_PTR                   = POINTER(CK_MECHANISM_TYPE)

class CK_MECHANISM (Structure):
  _fields_ = [("mechanism",             CK_MECHANISM_TYPE),
              ("pParameter",            CK_VOID_PTR),
              ("ulParameterLen",        CK_ULONG)]

CK_MECHANISM_PTR                        = POINTER(CK_MECHANISM)

class CK_MECHANISM_INFO (Structure):
  _fields_ = [("ulMinKeySize",          CK_ULONG),
              ("ulMaxKeySize",          CK_ULONG),
              ("flags",                 CK_FLAGS)]

CK_MECHANISM_INFO_PTR                   = POINTER(CK_MECHANISM_INFO)

CK_RV                                   = CK_ULONG

CK_NOTIFY                               = CFUNCTYPE(CK_RV, CK_SESSION_HANDLE, CK_NOTIFICATION, CK_VOID_PTR)

CK_CREATEMUTEX                          = CFUNCTYPE(CK_RV, CK_VOID_PTR_PTR)
CK_DESTROYMUTEX                         = CFUNCTYPE(CK_RV, CK_VOID_PTR)
CK_LOCKMUTEX                            = CFUNCTYPE(CK_RV, CK_VOID_PTR)
CK_UNLOCKMUTEX                          = CFUNCTYPE(CK_RV, CK_VOID_PTR)

class CK_C_INITIALIZE_ARGS (Structure):
  _fields_ = [("CreateMutex",           CK_CREATEMUTEX),
              ("DestroyMutex",          CK_DESTROYMUTEX),
              ("LockMutex",             CK_LOCKMUTEX),
              ("UnlockMutex",           CK_UNLOCKMUTEX),
              ("flags",                 CK_FLAGS),
              ("pReserved",             CK_VOID_PTR)]

CK_C_INITIALIZE_ARGS_PTR                = POINTER(CK_C_INITIALIZE_ARGS)
='n974' href='#n974'>974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
/*
 * rpc_client.c
 * ------------
 * Remote procedure call client-side private API implementation.
 *
 * Authors: Rob Austein, Paul Selkirk
 * Copyright (c) 2015-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 <assert.h>

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

/*
 * RPC calls.
 */

#define check(op) do { const hal_error_t _err_ = (op); if (_err_ != HAL_OK) return _err_; } while (0)

#define pad(n) (((n) + 3) & ~3)

#define nargs(n) ((n) * 4)

#if RPC_CLIENT != RPC_CLIENT_LOCAL

static hal_error_t get_version(uint32_t *version)
{
  uint8_t outbuf[nargs(1)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_GET_VERSION));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_int(&iptr, ilimit, version));
  }
  return rpc_ret;
}

static hal_error_t get_random(void *buffer, const size_t length)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2) + pad(length)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t rcvlen = length;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_GET_RANDOM));
  check(hal_xdr_encode_int(&optr, olimit, (uint32_t)length));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_buffer(&iptr, ilimit, buffer, &rcvlen));
    // XXX check rcvlen vs length
  }
  return rpc_ret;
}

static hal_error_t set_pin(const hal_client_handle_t client,
                           const hal_user_t user,
                           const char * const pin, const size_t pin_len)
{
  uint8_t outbuf[nargs(4) + pad(pin_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_SET_PIN));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, user));
  check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

/*
 * We may end up wanting to wrap a client-side cache around the
 * login()/logout()/logout_all() calls and reimplement is_logged_in()
 * on the client side using that cache, so that access checks don't
 * need to cross the RPC boundary.  Then again, we might not, if the
 * RPC call is fast enough, so implementing all before the RPC would
 * qualify as premature optimization.  There aren't all that many
 * things on the client side that would use this anyway, so the whole
 * question may be moot.
 *
 * For now, we leave all of these as plain RPC calls, but we may want
 * to revisit this if the is_logged_in() call turns into a bottleneck.
 */

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)
{
  uint8_t outbuf[nargs(4) + pad(pin_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGIN));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, user));
  check(hal_xdr_encode_buffer(&optr, olimit, (const uint8_t *)pin, pin_len));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

static hal_error_t logout(const hal_client_handle_t client)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGOUT));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

static hal_error_t logout_all(void)
{
  uint8_t outbuf[nargs(1)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_LOGOUT_ALL));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

static hal_error_t is_logged_in(const hal_client_handle_t client,
                                const hal_user_t user)
{
  uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_IS_LOGGED_IN));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, user));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

static hal_error_t hash_get_digest_len(const hal_digest_algorithm_t alg, size_t *length)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t len32;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN));
  check(hal_xdr_encode_int(&optr, olimit, alg));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_int(&iptr, ilimit, &len32));
    *length = (size_t)len32;
  }
  return rpc_ret;
}

static hal_error_t hash_get_digest_algorithm_id(const hal_digest_algorithm_t alg,
                                                uint8_t *id, size_t *len, const size_t len_max)
{
  uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2) + pad(len_max)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t len32 = len_max;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_DIGEST_LEN));
  check(hal_xdr_encode_int(&optr, olimit, alg));
  check(hal_xdr_encode_int(&optr, olimit, len_max));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_buffer(&iptr, ilimit, id, &len32));
    *len = len32;
  }
  return rpc_ret;
}

static hal_error_t hash_get_algorithm(const hal_hash_handle_t hash, hal_digest_algorithm_t *alg)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t alg32;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_GET_ALGORITHM));
  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_int(&iptr, ilimit, &alg32));
    *alg = (hal_digest_algorithm_t)alg32;
  }
  return rpc_ret;
}

static hal_error_t hash_initialize(const hal_client_handle_t client,
                                   const hal_session_handle_t session,
                                   hal_hash_handle_t *hash,
                                   const hal_digest_algorithm_t alg,
                                   const uint8_t * const key, const size_t key_len)
{
  uint8_t outbuf[nargs(5) + pad(key_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_INITIALIZE));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, session.handle));
  check(hal_xdr_encode_int(&optr, olimit, alg));
  check(hal_xdr_encode_buffer(&optr, olimit, key, key_len));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_int(&iptr, ilimit, &hash->handle));
  }
  return rpc_ret;
}

static hal_error_t hash_update(const hal_hash_handle_t hash,
                               const uint8_t * data, const size_t length)
{
  uint8_t outbuf[nargs(3) + pad(length)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_UPDATE));
  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
  check(hal_xdr_encode_buffer(&optr, olimit, data, length));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

static hal_error_t hash_finalize(const hal_hash_handle_t hash,
                                 uint8_t *digest, const size_t length)
{
  uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2) + pad(length)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t digest_len = length;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_HASH_FINALIZE));
  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
  check(hal_xdr_encode_int(&optr, olimit, length));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_buffer(&iptr, ilimit, digest, &digest_len));
    /* XXX check digest_len vs length */
  }
  return rpc_ret;
}

static hal_error_t pkey_remote_load(const hal_client_handle_t client,
                                    const hal_session_handle_t session,
                                    hal_pkey_handle_t *pkey,
                                    const hal_key_type_t type,
                                    const hal_curve_name_t curve,
                                    const uint8_t * const name, const size_t name_len,
                                    const uint8_t * const der, const size_t der_len,
                                    const hal_key_flags_t flags)
{
  uint8_t outbuf[nargs(8) + pad(name_len) + pad(der_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LOAD));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, session.handle));
  check(hal_xdr_encode_int(&optr, olimit, type));
  check(hal_xdr_encode_int(&optr, olimit, curve));
  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
  check(hal_xdr_encode_buffer(&optr, olimit, der, der_len));
  check(hal_xdr_encode_int(&optr, olimit, flags));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK)
    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));

  return rpc_ret;
}

static hal_error_t pkey_remote_find(const hal_client_handle_t client,
                                    const hal_session_handle_t session,
                                    hal_pkey_handle_t *pkey,
                                    const hal_key_type_t type,
                                    const uint8_t * const name, const size_t name_len,
                                    const hal_key_flags_t flags)
{
  uint8_t outbuf[nargs(6) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_FIND));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, session.handle));
  check(hal_xdr_encode_int(&optr, olimit, type));
  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
  check(hal_xdr_encode_int(&optr, olimit, flags));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK)
    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));

  return rpc_ret;
}

static hal_error_t pkey_remote_generate_rsa(const hal_client_handle_t client,
                                            const hal_session_handle_t session,
                                            hal_pkey_handle_t *pkey,
                                            const uint8_t * const name, const size_t name_len,
                                            const unsigned key_len,
                                            const uint8_t * const exp, const size_t exp_len,
                                            const hal_key_flags_t flags)
{
  uint8_t outbuf[nargs(7) + pad(name_len) + pad(exp_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_RSA));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, session.handle));
  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
  check(hal_xdr_encode_int(&optr, olimit, key_len));
  check(hal_xdr_encode_buffer(&optr, olimit, exp, exp_len));
  check(hal_xdr_encode_int(&optr, olimit, flags));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK)
    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));

  return rpc_ret;
}

static hal_error_t pkey_remote_generate_ec(const hal_client_handle_t client,
                                           const hal_session_handle_t session,
                                           hal_pkey_handle_t *pkey,
                                           const uint8_t * const name, const size_t name_len,
                                           const hal_curve_name_t curve,
                                           const hal_key_flags_t flags)
{
  uint8_t outbuf[nargs(6) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GENERATE_EC));
  check(hal_xdr_encode_int(&optr, olimit, client.handle));
  check(hal_xdr_encode_int(&optr, olimit, session.handle));
  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
  check(hal_xdr_encode_int(&optr, olimit, curve));
  check(hal_xdr_encode_int(&optr, olimit, flags));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK)
    check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));

  return rpc_ret;
}

static hal_error_t pkey_remote_close(const hal_pkey_handle_t pkey)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_CLOSE));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

static hal_error_t pkey_remote_delete(const hal_pkey_handle_t pkey)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_DELETE));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}

static hal_error_t pkey_remote_rename(const hal_pkey_handle_t pkey,
                                      const uint8_t * const name, const size_t name_len)
{
  uint8_t outbuf[nargs(3) + pad(name_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_RENAME));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_xdr_encode_buffer(&optr, olimit, name, name_len));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  return rpc_ret;
}


static hal_error_t pkey_remote_get_key_type(const hal_pkey_handle_t pkey,
                                            hal_key_type_t *type)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t type32;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_TYPE));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_int(&iptr, ilimit, &type32));
    *type = (hal_key_type_t)type32;
  }
  return rpc_ret;
}

static hal_error_t pkey_remote_get_key_flags(const hal_pkey_handle_t pkey,
                                             hal_key_flags_t *flags)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t flags32;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_KEY_FLAGS));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_int(&iptr, ilimit, &flags32));
    *flags = (hal_key_flags_t)flags32;
  }
  return rpc_ret;
}

static size_t pkey_remote_get_public_key_len(const hal_pkey_handle_t pkey)
{
  uint8_t outbuf[nargs(2)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t len32;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY_LEN));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_int(&iptr, ilimit, &len32));
    return (size_t)len32;
  }
  else
    return 0;
}

static hal_error_t pkey_remote_get_public_key(const hal_pkey_handle_t pkey,
                                              uint8_t *der, size_t *der_len, const size_t der_max)
{
  uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2) + pad(der_max)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t dlen32 = der_max;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_GET_PUBLIC_KEY));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_xdr_encode_int(&optr, olimit, der_max));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_buffer(&iptr, ilimit, der, &dlen32));
    *der_len = (size_t)dlen32;
  }
  return rpc_ret;
}

static hal_error_t pkey_remote_sign(const hal_session_handle_t session,
                                    const hal_pkey_handle_t pkey,
                                    const hal_hash_handle_t hash,
                                    const uint8_t * const input,  const size_t input_len,
                                    uint8_t * signature, size_t *signature_len, const size_t signature_max)
{
  uint8_t outbuf[nargs(6) + pad(input_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2) + pad(signature_max)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t slen32 = signature_max;
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_SIGN));
  check(hal_xdr_encode_int(&optr, olimit, session.handle));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
  check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
  check(hal_xdr_encode_int(&optr, olimit, signature_max));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  if (rpc_ret == HAL_OK) {
    check(hal_xdr_decode_buffer(&iptr, ilimit, signature, &slen32));
    *signature_len = (size_t)slen32;
  }
  return rpc_ret;
}

static hal_error_t pkey_remote_verify(const hal_session_handle_t session,
                                      const hal_pkey_handle_t pkey,
                                      const hal_hash_handle_t hash,
                                      const uint8_t * const input, const size_t input_len,
                                      const uint8_t * const signature, const size_t signature_len)
{
  uint8_t outbuf[nargs(6) + pad(input_len) + pad(signature_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(1)];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  hal_error_t rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_REMOTE_VERIFY));
  check(hal_xdr_encode_int(&optr, olimit, session.handle));
  check(hal_xdr_encode_int(&optr, olimit, pkey.handle));
  check(hal_xdr_encode_int(&optr, olimit, hash.handle));
  check(hal_xdr_encode_buffer(&optr, olimit, input, input_len));
  check(hal_xdr_encode_buffer(&optr, olimit, signature, signature_len));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
  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)
{
  uint32_t i32;

  check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->type = i32;
  check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->curve = i32;
  check(hal_xdr_decode_int(iptr, ilimit, &i32)); info->flags = i32;
  check(hal_xdr_decode_buffer(iptr, ilimit, (uint8_t *)&info->name[0], &i32)); info->name_len = i32;
  return HAL_OK;
}

static hal_error_t pkey_remote_list(hal_pkey_info_t *result,
                                    unsigned *result_len,
                                    const unsigned result_max,
                                    hal_key_flags_t flags)
{
  uint8_t outbuf[nargs(3)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
  uint8_t inbuf[nargs(2) + pad(result_max * sizeof(hal_pkey_info_t))];
  const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
  size_t ilen = sizeof(inbuf);
  uint32_t len;
  hal_error_t ret, rpc_ret;

  check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_LIST));
  check(hal_xdr_encode_int(&optr, olimit, result_max));
  check(hal_xdr_encode_int(&optr, olimit, flags));
  check(hal_rpc_send(outbuf, optr - outbuf));

  check(hal_rpc_recv(inbuf, &ilen));
  assert(ilen <= sizeof(inbuf));
  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) {
      if ((ret = hal_xdr_decode_pkey_info(&iptr, ilimit, &result[i])) != HAL_OK) {
        *result_len = 0;
        return ret;
      }
    }
  }
  return rpc_ret;
}

#if RPC_CLIENT == RPC_CLIENT_MIXED
/*
 * "Mixed" mode pkey operations, where the public key operation itself
 * takes place on the HSM but the hashing takes place locally.  If
 * we're given a hash context in this case, it's local, so we have to
 * pull the digest from the hash context and send that to the HSM.
 *
 * These methods are also responsible for dispatching pkey operations
 * to the local or remote key store based on the PROXIMATE flags.
 * These flags are only meaningful when operating in mixed mode.
 */

static inline const hal_rpc_pkey_dispatch_t *mixed_flags_dispatch(const hal_key_flags_t flags)
{
  if ((flags & HAL_KEY_FLAG_PROXIMATE) == 0)
    return &hal_rpc_remote_pkey_dispatch;
  else
    return &hal_rpc_local_pkey_dispatch;
}

static inline const hal_rpc_pkey_dispatch_t *mixed_handle_dispatch(const hal_pkey_handle_t pkey)
{
  if  ((pkey.handle & HAL_PKEY_HANDLE_PROXIMATE_FLAG) == 0)
    return &hal_rpc_remote_pkey_dispatch;
  else
    return &hal_rpc_local_pkey_dispatch;
}

static hal_error_t pkey_mixed_sign(const hal_session_handle_t session,
                                   const hal_pkey_handle_t pkey,
                                   const hal_hash_handle_t hash,
                                   const uint8_t * const input,  const size_t input_len,
                                   uint8_t * signature, size_t *signature_len, const size_t signature_max)
{
  if (input != NULL)
    return mixed_handle_dispatch(pkey)->sign(session, pkey, hash, input, input_len,
                                             signature, signature_len, signature_max);

  hal_digest_algorithm_t alg;
  size_t digest_len;
  hal_error_t err;

  if ((err = hal_rpc_hash_get_algorithm(hash, &alg))           != HAL_OK ||
      (err = hal_rpc_hash_get_digest_length(alg, &digest_len)) != HAL_OK)
    return err;

  uint8_t digest[digest_len];

  if ((err = hal_rpc_hash_finalize(hash, digest, digest_len)) != HAL_OK)
    return err;

  return mixed_handle_dispatch(pkey)->sign(session, pkey, hal_hash_handle_none, digest, digest_len,
                                           signature, signature_len, signature_max);
}

static hal_error_t pkey_mixed_verify(const hal_session_handle_t session,
                                     const hal_pkey_handle_t pkey,
                                     const hal_hash_handle_t hash,
                                     const uint8_t * const input, const size_t input_len,
                                     const uint8_t * const signature, const size_t signature_len)
{
  if (input != NULL)
    return mixed_handle_dispatch(pkey)->verify(session, pkey, hash, input, input_len,
                                               signature, signature_len);

  hal_digest_algorithm_t alg;
  size_t digest_len;
  hal_error_t err;

  if ((err = hal_rpc_hash_get_algorithm(hash, &alg))           != HAL_OK ||
      (err = hal_rpc_hash_get_digest_length(alg, &digest_len)) != HAL_OK)
    return err;

  uint8_t digest[digest_len];

  if ((err = hal_rpc_hash_finalize(hash, digest, digest_len)) != HAL_OK)
    return err;

  return mixed_handle_dispatch(pkey)->verify(session, pkey, hal_hash_handle_none,
                                             digest, digest_len, signature, signature_len);
}

static hal_error_t pkey_mixed_load(const hal_client_handle_t client,
				   const hal_session_handle_t session,
				   hal_pkey_handle_t *pkey,
				   const hal_key_type_t type,
				   const hal_curve_name_t curve,
				   const uint8_t * const name, const size_t name_len,
				   const uint8_t * const der, const size_t der_len,
				   const hal_key_flags_t flags)
{
  return mixed_flags_dispatch(flags)->load(client, session, pkey, type, curve,
                                           name, name_len, der, der_len, flags);
}

static hal_error_t pkey_mixed_find(const hal_client_handle_t client,
				   const hal_session_handle_t session,
				   hal_pkey_handle_t *pkey,
				   const hal_key_type_t type,
				   const uint8_t * const name, const size_t name_len,
				   const hal_key_flags_t flags)
{
  return mixed_flags_dispatch(flags)->find(client, session, pkey, type,
                                           name, name_len, flags);
}

static hal_error_t pkey_mixed_generate_rsa(const hal_client_handle_t client,
					   const hal_session_handle_t session,
					   hal_pkey_handle_t *pkey,
					   const uint8_t * const name, const size_t name_len,
					   const unsigned key_length,
					   const uint8_t * const public_exponent, const size_t public_exponent_len,
					   const hal_key_flags_t flags)
{
  return mixed_flags_dispatch(flags)->generate_rsa(client, session, pkey,
                                                   name, name_len, key_length,
                                                   public_exponent, public_exponent_len, flags);
}

static hal_error_t pkey_mixed_generate_ec(const hal_client_handle_t client,
					  const hal_session_handle_t session,
					  hal_pkey_handle_t *pkey,
					  const uint8_t * const name, const size_t name_len,
					  const hal_curve_name_t curve,
					  const hal_key_flags_t flags)
{
  return mixed_flags_dispatch(flags)->generate_ec(client, session, pkey, name, name_len, curve, flags);
}

static hal_error_t pkey_mixed_close(const hal_pkey_handle_t pkey)
{
  return mixed_handle_dispatch(pkey)->close(pkey);
}

static hal_error_t pkey_mixed_delete(const hal_pkey_handle_t pkey)
{
  return mixed_handle_dispatch(pkey)->delete(pkey);
}

static hal_error_t pkey_mixed_rename(const hal_pkey_handle_t pkey,
                                     const uint8_t * const name, const size_t name_len)
{
  return mixed_handle_dispatch(pkey)->rename(pkey, name, name_len);
}

static hal_error_t pkey_mixed_get_key_type(const hal_pkey_handle_t pkey,
					   hal_key_type_t *key_type)
{
  return mixed_handle_dispatch(pkey)->get_key_type(pkey, key_type);
}

static hal_error_t pkey_mixed_get_key_flags(const hal_pkey_handle_t pkey,
					    hal_key_flags_t *flags)
{
  return mixed_handle_dispatch(pkey)->get_key_flags(pkey, flags);
}

static size_t pkey_mixed_get_public_key_len(const hal_pkey_handle_t pkey)
{
  return mixed_handle_dispatch(pkey)->get_public_key_len(pkey);
}

static hal_error_t pkey_mixed_get_public_key(const hal_pkey_handle_t pkey,
					     uint8_t *der, size_t *der_len, const size_t der_max)
{
  return mixed_handle_dispatch(pkey)->get_public_key(pkey, der, der_len, der_max);
}

static hal_error_t pkey_mixed_list(hal_pkey_info_t *result,
				   unsigned *result_len,
				   const unsigned result_max,
                                   hal_key_flags_t flags)
{
  return mixed_flags_dispatch(flags)->list(result, result_len, result_max, flags);
}
#endif /* RPC_CLIENT == RPC_CLIENT_MIXED */

/*
 * Dispatch vectors.
 */

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

const hal_rpc_hash_dispatch_t hal_rpc_remote_hash_dispatch = {
  hash_get_digest_len,
  hash_get_digest_algorithm_id,
  hash_get_algorithm,
  hash_initialize,
  hash_update,
  hash_finalize
};

const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = {
  pkey_remote_load,
  pkey_remote_find,
  pkey_remote_generate_rsa,
  pkey_remote_generate_ec,
  pkey_remote_close,
  pkey_remote_delete,
  pkey_remote_rename,
  pkey_remote_get_key_type,
  pkey_remote_get_key_flags,
  pkey_remote_get_public_key_len,
  pkey_remote_get_public_key,
  pkey_remote_sign,
  pkey_remote_verify,
  pkey_remote_list
};

#if RPC_CLIENT == RPC_CLIENT_MIXED
const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
  pkey_mixed_load,
  pkey_mixed_find,
  pkey_mixed_generate_rsa,
  pkey_mixed_generate_ec,
  pkey_mixed_close,
  pkey_mixed_delete,
  pkey_mixed_rename,
  pkey_mixed_get_key_type,
  pkey_mixed_get_key_flags,
  pkey_mixed_get_public_key_len,
  pkey_mixed_get_public_key,
  pkey_mixed_sign,
  pkey_mixed_verify,
  pkey_mixed_list
};
#endif /* RPC_CLIENT == RPC_CLIENT_MIXED */

#endif /* RPC_CLIENT != RPC_CLIENT_LOCAL */


#if RPC_CLIENT == RPC_CLIENT_REMOTE
const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch;
const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_remote_hash_dispatch;
const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_remote_pkey_dispatch;
#endif

#if RPC_CLIENT == RPC_CLIENT_MIXED
const hal_rpc_misc_dispatch_t * hal_rpc_misc_dispatch = &hal_rpc_remote_misc_dispatch;
const hal_rpc_hash_dispatch_t * hal_rpc_hash_dispatch = &hal_rpc_local_hash_dispatch;
const hal_rpc_pkey_dispatch_t * hal_rpc_pkey_dispatch = &hal_rpc_mixed_pkey_dispatch;
#endif

hal_error_t hal_rpc_client_init(void)
{
#if RPC_CLIENT == RPC_CLIENT_LOCAL
  return HAL_OK;
#else
  return hal_rpc_client_transport_init();
#endif
}

hal_error_t hal_rpc_client_close(void)
{
#if RPC_CLIENT == RPC_CLIENT_LOCAL
  return HAL_OK;
#else
  return hal_rpc_client_transport_close();
#endif
}


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