aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--asn1.c83
-rw-r--r--asn1_internal.h6
-rw-r--r--ecdsa.c25
-rw-r--r--hal.h19
-rw-r--r--hal_internal.h28
-rw-r--r--rpc_api.c24
-rw-r--r--rpc_client.c81
-rw-r--r--rpc_pkey.c292
8 files changed, 505 insertions, 53 deletions
diff --git a/asn1.c b/asn1.c
index 1d7e628..3ca8fc8 100644
--- a/asn1.c
+++ b/asn1.c
@@ -52,7 +52,7 @@
#include <assert.h>
#include "hal.h"
-
+#include "hal_internal.h"
#include "asn1_internal.h"
#define INIT_FP_INT {{{0}}}
@@ -67,6 +67,16 @@ const size_t hal_asn1_oid_rsaEncryption_len = sizeof(hal_asn1_oid_rsaEncryption
const uint8_t hal_asn1_oid_ecPublicKey[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 };
const size_t hal_asn1_oid_ecPublicKey_len = sizeof(hal_asn1_oid_ecPublicKey);
+#if KEK_LENGTH == (bitsToBytes(128))
+const uint8_t hal_asn1_oid_aesKeyWrap[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x08 };
+const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
+#endif
+
+#if KEK_LENGTH == (bitsToBytes(256))
+const uint8_t hal_asn1_oid_aesKeyWrap[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x30 };
+const size_t hal_asn1_oid_aesKeyWrap_len = sizeof(hal_asn1_oid_aesKeyWrap);
+#endif
+
/*
* Encode tag and length fields of an ASN.1 object.
*
@@ -482,8 +492,7 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
const uint8_t **pubkey, size_t *pubkey_len,
const uint8_t *const der, const size_t der_len)
{
- if (alg_oid == NULL || alg_oid_len == NULL || curve_oid == NULL || curve_oid_len == NULL ||
- pubkey == NULL || pubkey_len == NULL || der == NULL)
+ if (der == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
const uint8_t * const der_end = der + der_len;
@@ -510,12 +519,16 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
d += hlen;
if (vlen > algid_end - d)
return HAL_ERROR_ASN1_PARSE_FAILED;
- *alg_oid = d;
- *alg_oid_len = vlen;
+ if (alg_oid != NULL)
+ *alg_oid = d;
+ if (alg_oid_len != NULL)
+ *alg_oid_len = vlen;
d += vlen;
- *curve_oid = NULL;
- *curve_oid_len = 0;
+ if (curve_oid != NULL)
+ *curve_oid = NULL;
+ if (curve_oid_len != NULL)
+ *curve_oid_len = 0;
if (d < algid_end) {
switch (*d) {
@@ -526,8 +539,10 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
d += hlen;
if (vlen > algid_end - d)
return HAL_ERROR_ASN1_PARSE_FAILED;
- *curve_oid = d;
- *curve_oid_len = vlen;
+ if (curve_oid != NULL)
+ *curve_oid = d;
+ if (curve_oid_len != NULL)
+ *curve_oid_len = vlen;
d += vlen;
break;
@@ -551,8 +566,11 @@ hal_error_t hal_asn1_decode_spki(const uint8_t **alg_oid, size_t *alg_oid_len,
d += hlen;
if (vlen >= algid_end - d || vlen == 0 || *d != 0x00)
return HAL_ERROR_ASN1_PARSE_FAILED;
- *pubkey = ++d;
- *pubkey_len = --vlen;
+ ++d; --vlen;
+ if (pubkey != NULL)
+ *pubkey = d;
+ if (pubkey_len != NULL)
+ *pubkey_len = vlen;
d += vlen;
if (d != der_end)
@@ -721,6 +739,49 @@ hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t **alg_oi
}
/*
+ * Attempt to guess what kind of key we're looking at.
+ */
+
+hal_error_t hal_asn1_guess_key_type(hal_key_type_t *type,
+ hal_curve_name_t *curve,
+ const uint8_t *const der, const size_t der_len)
+{
+ if (type == NULL || curve == NULL || der == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
+
+ const uint8_t *alg_oid, *curve_oid;
+ size_t alg_oid_len, curve_oid_len;
+ hal_error_t err;
+ int public = 0;
+
+ err = hal_asn1_decode_pkcs8_privatekeyinfo(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len, NULL, 0, der, der_len);
+
+ if (err == HAL_ERROR_ASN1_PARSE_FAILED &&
+ (err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len, NULL, 0, der, der_len)) == HAL_OK)
+ public = 1;
+
+ if (err != HAL_OK)
+ return err;
+
+ if (alg_oid_len == hal_asn1_oid_rsaEncryption_len && memcmp(alg_oid, hal_asn1_oid_rsaEncryption, alg_oid_len) == 0) {
+ *type = public ? HAL_KEY_TYPE_RSA_PUBLIC : HAL_KEY_TYPE_RSA_PRIVATE;
+ *curve = HAL_CURVE_NONE;
+ return HAL_OK;
+ }
+
+ if (alg_oid_len == hal_asn1_oid_ecPublicKey_len && memcmp(alg_oid, hal_asn1_oid_ecPublicKey, alg_oid_len) == 0) {
+ *type = public ? HAL_KEY_TYPE_EC_PUBLIC : HAL_KEY_TYPE_EC_PRIVATE;
+ if ((err = hal_ecdsa_oid_to_curve(curve, curve_oid, curve_oid_len)) != HAL_OK)
+ *curve = HAL_CURVE_NONE;
+ return err;
+ }
+
+ *type = HAL_KEY_TYPE_NONE;
+ *curve = HAL_CURVE_NONE;
+ return HAL_ERROR_UNSUPPORTED_KEY;
+}
+
+/*
* Local variables:
* indent-tabs-mode: nil
* End:
diff --git a/asn1_internal.h b/asn1_internal.h
index c337d4b..fe2f293 100644
--- a/asn1_internal.h
+++ b/asn1_internal.h
@@ -99,6 +99,9 @@ extern const size_t hal_asn1_oid_rsaEncryption_len;
extern const uint8_t hal_asn1_oid_ecPublicKey[];
extern const size_t hal_asn1_oid_ecPublicKey_len;
+extern const uint8_t hal_asn1_oid_aesKeyWrap[];
+extern const size_t hal_asn1_oid_aesKeyWrap_len;
+
/*
* Transcoding functions.
*/
@@ -145,6 +148,9 @@ extern hal_error_t hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(const uint8_t *
const uint8_t **data, size_t *data_len,
const uint8_t *const der, const size_t der_len);
+extern hal_error_t hal_asn1_guess_key_type(hal_key_type_t *type, hal_curve_name_t *curve,
+ const uint8_t *const der, const size_t der_len);
+
#endif /* _HAL_ASN1_INTERNAL_H_ */
/*
diff --git a/ecdsa.c b/ecdsa.c
index 8a31504..3fc1462 100644
--- a/ecdsa.c
+++ b/ecdsa.c
@@ -258,20 +258,21 @@ static const ecdsa_curve_t * const get_curve(const hal_curve_name_t curve)
}
}
-static inline const ecdsa_curve_t * oid_to_curve(hal_curve_name_t *curve_name,
- const uint8_t * const oid,
- const size_t oid_len)
+hal_error_t hal_ecdsa_oid_to_curve(hal_curve_name_t *curve_name,
+ const uint8_t * const oid,
+ const size_t oid_len)
{
- assert(curve_name != NULL && oid != NULL);
+ if (curve_name == NULL || oid == NULL)
+ return HAL_ERROR_BAD_ARGUMENTS;
- const ecdsa_curve_t *curve = NULL;
*curve_name = HAL_CURVE_NONE;
+ const ecdsa_curve_t *curve;
while ((curve = get_curve(++*curve_name)) != NULL)
if (oid_len == curve->oid_len && memcmp(oid, curve->oid, oid_len) == 0)
- return curve;
+ return HAL_OK;
- return NULL;
+ return HAL_ERROR_UNSUPPORTED_KEY;
}
/*
@@ -1395,7 +1396,7 @@ hal_error_t hal_ecdsa_private_key_from_der(hal_ecdsa_key_t **key_,
if (alg_oid_len != hal_asn1_oid_ecPublicKey_len ||
memcmp(alg_oid, hal_asn1_oid_ecPublicKey, alg_oid_len) != 0 ||
- oid_to_curve(&key->curve, curve_oid, curve_oid_len) == NULL)
+ hal_ecdsa_oid_to_curve(&key->curve, curve_oid, curve_oid_len) != HAL_OK)
return HAL_ERROR_ASN1_PARSE_FAILED;
if ((err = hal_asn1_decode_header(ASN1_SEQUENCE, privkey, privkey_len, &hlen, &vlen)) != HAL_OK)
@@ -1516,19 +1517,19 @@ hal_error_t hal_ecdsa_public_key_from_der(hal_ecdsa_key_t **key_,
const uint8_t *alg_oid = NULL, *curve_oid = NULL, *pubkey = NULL;
size_t alg_oid_len, curve_oid_len, pubkey_len;
- const ecdsa_curve_t *curve;
hal_error_t err;
- if ((err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len, &pubkey, &pubkey_len,
+ if ((err = hal_asn1_decode_spki(&alg_oid, &alg_oid_len, &curve_oid, &curve_oid_len,
+ &pubkey, &pubkey_len,
der, der_len)) != HAL_OK)
return err;
if (alg_oid == NULL || curve_oid == NULL || pubkey == NULL ||
alg_oid_len != hal_asn1_oid_ecPublicKey_len ||
memcmp(alg_oid, hal_asn1_oid_ecPublicKey, alg_oid_len) != 0 ||
- (curve = oid_to_curve(&key->curve, curve_oid, curve_oid_len)) == NULL ||
+ hal_ecdsa_oid_to_curve(&key->curve, curve_oid, curve_oid_len) != HAL_OK ||
pubkey_len < 3 || (pubkey_len & 1) == 0 || pubkey[0] != 0x04 ||
- pubkey_len / 2 != fp_unsigned_bin_size(unconst_fp_int(curve->q)))
+ pubkey_len / 2 != fp_unsigned_bin_size(unconst_fp_int(get_curve(key->curve)->q)))
return HAL_ERROR_ASN1_PARSE_FAILED;
const uint8_t * const Qx = pubkey + 1;
diff --git a/hal.h b/hal.h
index 29b4dab..38a8330 100644
--- a/hal.h
+++ b/hal.h
@@ -505,6 +505,10 @@ extern const size_t hal_ecdsa_key_t_size;
extern void hal_ecdsa_set_debug(const int onoff);
+extern hal_error_t hal_ecdsa_oid_to_curve(hal_curve_name_t *curve,
+ const uint8_t * const oid,
+ const size_t oid_len);
+
extern hal_error_t hal_ecdsa_key_load_private(hal_ecdsa_key_t **key,
void *keybuf, const size_t keybuf_len,
const hal_curve_name_t curve,
@@ -725,6 +729,7 @@ typedef uint32_t hal_key_flags_t;
#define HAL_KEY_FLAG_USAGE_DATAENCIPHERMENT (1 << 2)
#define HAL_KEY_FLAG_TOKEN (1 << 3)
#define HAL_KEY_FLAG_PUBLIC (1 << 4)
+#define HAL_KEY_FLAG_EXPORTABLE (1 << 5)
/*
* hal_pkey_attribute_t.length would be size_t, except that we also
@@ -821,6 +826,20 @@ extern hal_error_t hal_rpc_pkey_get_attributes(const hal_pkey_handle_t pkey,
uint8_t *attributes_buffer,
const size_t attributes_buffer_len);
+extern hal_error_t hal_rpc_pkey_export(const hal_pkey_handle_t pkey,
+ const hal_pkey_handle_t kekek,
+ uint8_t *pkcs8, size_t *pkcs8_len, const size_t pkcs8_max,
+ uint8_t *kek, size_t *kek_len, const size_t kek_max);
+
+extern hal_error_t hal_rpc_pkey_import(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const hal_pkey_handle_t kekek,
+ const uint8_t * const pkcs8, const size_t pkcs8_len,
+ const uint8_t * const kek, const size_t kek_len,
+ const hal_key_flags_t flags);
+
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 65f6ae7..8130801 100644
--- a/hal_internal.h
+++ b/hal_internal.h
@@ -269,6 +269,20 @@ typedef struct {
uint8_t *attributes_buffer,
const size_t attributes_buffer_len);
+ hal_error_t (*export)(const hal_pkey_handle_t pkey_handle,
+ const hal_pkey_handle_t kekek_handle,
+ uint8_t *pkcs8, size_t *pkcs8_len, const size_t pkcs8_max,
+ uint8_t *kek, size_t *kek_len, const size_t kek_max);
+
+ hal_error_t (*import)(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const hal_pkey_handle_t kekek_handle,
+ const uint8_t * const pkcs8, const size_t pkcs8_len,
+ const uint8_t * const kek, const size_t kek_len,
+ const hal_key_flags_t flags);
+
} hal_rpc_pkey_dispatch_t;
@@ -459,11 +473,11 @@ struct hal_ks_driver {
hal_error_t (*store)(hal_ks_t *ks,
hal_pkey_slot_t *slot,
- const uint8_t * const der, const size_t der_len);
+ const uint8_t * const der, const size_t der_len);
hal_error_t (*fetch)(hal_ks_t *ks,
hal_pkey_slot_t *slot,
- uint8_t *der, size_t *der_len, const size_t der_max);
+ uint8_t *der, size_t *der_len, const size_t der_max);
hal_error_t (*delete)(hal_ks_t *ks,
hal_pkey_slot_t *slot);
@@ -537,7 +551,7 @@ static inline hal_error_t hal_ks_shutdown(const hal_ks_driver_t * const driver)
}
static inline hal_error_t hal_ks_open(const hal_ks_driver_t * const driver,
- hal_ks_t **ks)
+ hal_ks_t **ks)
{
if (driver == NULL || ks == NULL)
return HAL_ERROR_BAD_ARGUMENTS;
@@ -863,6 +877,8 @@ typedef enum {
RPC_FUNC_PKEY_GET_KEY_CURVE,
RPC_FUNC_PKEY_SET_ATTRIBUTES,
RPC_FUNC_PKEY_GET_ATTRIBUTES,
+ RPC_FUNC_PKEY_EXPORT,
+ RPC_FUNC_PKEY_IMPORT,
} rpc_func_num_t;
#define RPC_VERSION 0x01010000 /* 1.1.0.0 */
@@ -898,7 +914,7 @@ typedef enum {
*/
#ifndef HAL_CLIENT_SERIAL_DEFAULT_DEVICE
-#define HAL_CLIENT_SERIAL_DEFAULT_DEVICE "/dev/ttyUSB0"
+#define HAL_CLIENT_SERIAL_DEFAULT_DEVICE "/dev/ttyUSB0"
#endif
#ifndef HAL_CLIENT_SERIAL_DEFAULT_SPEED
@@ -909,8 +925,8 @@ typedef enum {
* Names of environment variables for setting the above in RPC clients.
*/
-#define HAL_CLIENT_SERIAL_DEVICE_ENVVAR "CRYPTECH_RPC_CLIENT_SERIAL_DEVICE"
-#define HAL_CLIENT_SERIAL_SPEED_ENVVAR "CRYPTECH_RPC_CLIENT_SERIAL_SPEED"
+#define HAL_CLIENT_SERIAL_DEVICE_ENVVAR "CRYPTECH_RPC_CLIENT_SERIAL_DEVICE"
+#define HAL_CLIENT_SERIAL_SPEED_ENVVAR "CRYPTECH_RPC_CLIENT_SERIAL_SPEED"
#endif /* _HAL_INTERNAL_H_ */
diff --git a/rpc_api.c b/rpc_api.c
index 6ffd7a0..099ffcd 100644
--- a/rpc_api.c
+++ b/rpc_api.c
@@ -381,6 +381,30 @@ hal_error_t hal_rpc_pkey_get_attributes(const hal_pkey_handle_t pkey,
attributes_buffer, attributes_buffer_len);
}
+hal_error_t hal_rpc_pkey_export(const hal_pkey_handle_t pkey,
+ const hal_pkey_handle_t kekek,
+ uint8_t *pkcs8, size_t *pkcs8_len, const size_t pkcs8_max,
+ uint8_t *kek, size_t *kek_len, const size_t kek_max)
+{
+ if (pkcs8 == NULL || pkcs8_len == NULL || kek == NULL || kek_len == NULL || kek_max <= KEK_LENGTH)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return hal_rpc_pkey_dispatch->export(pkey, kekek, pkcs8, pkcs8_len, pkcs8_max, kek, kek_len, kek_max);
+}
+
+hal_error_t hal_rpc_pkey_import(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const hal_pkey_handle_t kekek,
+ const uint8_t * const pkcs8, const size_t pkcs8_len,
+ const uint8_t * const kek, const size_t kek_len,
+ const hal_key_flags_t flags)
+{
+ if (pkey == NULL || name == NULL || pkcs8 == NULL || kek == NULL || kek_len <= 2)
+ return HAL_ERROR_BAD_ARGUMENTS;
+ return hal_rpc_pkey_dispatch->import(client, session, pkey, name, kekek, pkcs8, pkcs8_len, kek, kek_len, flags);
+}
+
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/rpc_client.c b/rpc_client.c
index 4adf247..5729b6f 100644
--- a/rpc_client.c
+++ b/rpc_client.c
@@ -915,6 +915,78 @@ static hal_error_t pkey_remote_get_attributes(const hal_pkey_handle_t pkey,
return rpc_ret;
}
+static hal_error_t pkey_remote_export(const hal_pkey_handle_t pkey,
+ const hal_pkey_handle_t kekek,
+ uint8_t *pkcs8, size_t *pkcs8_len, const size_t pkcs8_max,
+ uint8_t *kek, size_t *kek_len, const size_t kek_max)
+{
+ uint8_t outbuf[nargs(6)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(pkcs8_max) + pad(kek_max)];
+ 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_EXPORT));
+ 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, kekek.handle));
+ check(hal_xdr_encode_int(&optr, olimit, pkcs8_max));
+ check(hal_xdr_encode_int(&optr, olimit, kek_max));
+ check(hal_rpc_send(outbuf, optr - outbuf));
+
+ check(read_matching_packet(RPC_FUNC_PKEY_EXPORT, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+ check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+ if (rpc_ret == HAL_OK) {
+ uint32_t len;
+ len = pkcs8_max;
+ check(hal_xdr_decode_buffer(&iptr, ilimit, pkcs8, &len));
+ *pkcs8_len = (size_t) len;
+ len = kek_max;
+ check(hal_xdr_decode_buffer(&iptr, ilimit, kek, &len));
+ *kek_len = (size_t) len;
+ }
+ return rpc_ret;
+}
+
+static hal_error_t pkey_remote_import(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const hal_pkey_handle_t kekek,
+ const uint8_t * const pkcs8, const size_t pkcs8_len,
+ const uint8_t * const kek, const size_t kek_len,
+ const hal_key_flags_t flags)
+{
+ uint8_t outbuf[nargs(7) + pad(pkcs8_len) + pad(kek_len)], *optr = outbuf, *olimit = outbuf + sizeof(outbuf);
+ uint8_t inbuf[nargs(5) + pad(sizeof(name->uuid))];
+ const uint8_t *iptr = inbuf, *ilimit = inbuf + sizeof(inbuf);
+ uint32_t name_len = sizeof(name->uuid);
+ hal_error_t rpc_ret;
+
+ check(hal_xdr_encode_int(&optr, olimit, RPC_FUNC_PKEY_IMPORT));
+ 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, kekek.handle));
+ check(hal_xdr_encode_buffer(&optr, olimit, pkcs8, pkcs8_len));
+ check(hal_xdr_encode_buffer(&optr, olimit, kek, kek_len));
+ check(hal_xdr_encode_int(&optr, olimit, flags));
+ check(hal_rpc_send(outbuf, optr - outbuf));
+
+ check(read_matching_packet(RPC_FUNC_PKEY_IMPORT, inbuf, sizeof(inbuf), &iptr, &ilimit));
+
+ check(hal_xdr_decode_int(&iptr, ilimit, &rpc_ret));
+
+ if (rpc_ret == HAL_OK) {
+ check(hal_xdr_decode_int(&iptr, ilimit, &pkey->handle));
+ check(hal_xdr_decode_buffer(&iptr, ilimit, name->uuid, &name_len));
+ if (name_len != sizeof(name->uuid))
+ return HAL_ERROR_KEY_NAME_TOO_LONG;
+ }
+
+ return rpc_ret;
+}
+
#if RPC_CLIENT == RPC_CLIENT_MIXED
/*
@@ -1043,7 +1115,9 @@ const hal_rpc_pkey_dispatch_t hal_rpc_remote_pkey_dispatch = {
.verify = pkey_remote_verify,
.match = pkey_remote_match,
.set_attributes = pkey_remote_set_attributes,
- .get_attributes = pkey_remote_get_attributes
+ .get_attributes = pkey_remote_get_attributes,
+ .export = pkey_remote_export,
+ .import = pkey_remote_import
};
#if RPC_CLIENT == RPC_CLIENT_MIXED
@@ -1063,7 +1137,9 @@ const hal_rpc_pkey_dispatch_t hal_rpc_mixed_pkey_dispatch = {
.verify = pkey_mixed_verify,
.match = pkey_remote_match,
.set_attributes = pkey_remote_set_attributes,
- .get_attributes = pkey_remote_get_attributes
+ .get_attributes = pkey_remote_get_attributes,
+ .export = pkey_remote_export,
+ .import = pkey_remote_import
};
#endif /* RPC_CLIENT == RPC_CLIENT_MIXED */
@@ -1100,7 +1176,6 @@ hal_error_t hal_rpc_client_close(void)
#endif
}
-
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/rpc_pkey.c b/rpc_pkey.c
index 48072ce..aff833b 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -117,10 +117,10 @@ static inline hal_pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
*
* That's almost the rule that PKCS #11 follows for so-called
* "private" objects (CKA_PRIVATE = CK_TRUE), but PKCS #11 has a more
- * model which not only allows wider visibility to "public" objects
- * (CKA_PRIVATE = CK_FALSE) but also allows write access to "public
- * session" (CKA_PRIVATE = CK_FALSE, CKA_TOKEN = CK_FALSE) objects
- * regardless of login state.
+ * complex model which not only allows wider visibility to "public"
+ * objects (CKA_PRIVATE = CK_FALSE) but also allows write access to
+ * "public session" (CKA_PRIVATE = CK_FALSE, CKA_TOKEN = CK_FALSE)
+ * objects regardless of login state.
*
* PKCS #11 also has a concept of read-only sessions, which we don't
* bother to implement at all on the HSM, since the PIN is required to
@@ -173,29 +173,55 @@ static inline hal_error_t check_writable(const hal_client_handle_t client,
}
/*
+ * PKCS #1.5 encryption requires non-zero random bytes, which is a bit
+ * messy if done in place, so make it a separate function for readability.
+ */
+
+static inline hal_error_t get_nonzero_random(uint8_t *buffer, size_t n)
+{
+ assert(buffer != NULL);
+
+ uint32_t word = 0;
+ hal_error_t err;
+
+ while (n > 0) {
+
+ while ((word & 0xFF) == 0)
+ if ((word & ~0xFF) != 0)
+ word >>= 8;
+ else if ((err = hal_get_random(NULL, &word, sizeof(word))) != HAL_OK)
+ return err;
+
+ *buffer++ = word & 0xFF;
+ word >>= 8;
+ n--;
+ }
+
+ return HAL_OK;
+}
+
+/*
* Pad an octet string with PKCS #1.5 padding for use with RSA.
*
- * For the moment, this only handles type 01 encryption blocks, thus
- * is only suitable for use with signature and verification. If and
- * when we add support for encryption and decryption, this function
- * should be extended to take an argument specifying the block type
- * and include support for generating type 02 encryption blocks.
- * Other than the block type code, the only difference is the padding
- * value: for type 01 it's constant (0xFF), for type 02 it should be
- * non-zero random bytes from the CSPRNG.
+ * This handles type 01 and type 02 encryption blocks. The formats
+ * are identical, except that the padding string is constant 0xFF
+ * bytes for type 01 and non-zero random bytes for type 02.
*
* We use memmove() instead of memcpy() so that the caller can
* construct the data to be padded in the same buffer.
*/
static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len,
- uint8_t *block, const size_t block_len)
+ uint8_t *block, const size_t block_len,
+ const uint8_t type)
{
- assert(data != NULL && block != NULL);
+ assert(data != NULL && block != NULL && (type == 0x01 || type == 0x02));
+
+ hal_error_t err;
/*
* Congregation will now please turn to RFC 2313 8.1 as we
- * construct a PKCS #1.5 type 01 encryption block.
+ * construct a PKCS #1.5 type 01 or type 02 encryption block.
*/
if (data_len > block_len - 11)
@@ -204,10 +230,20 @@ static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len
memmove(block + block_len - data_len, data, data_len);
block[0] = 0x00;
- block[1] = 0x01;
+ block[1] = type;
+
+ switch (type) {
+
+ case 0x01: /* Signature */
+ memset(block + 2, 0xFF, block_len - 3 - data_len);
+ break;
+
+ case 0x02: /* Encryption */
+ if ((err = get_nonzero_random(block + 2, block_len - 3 - data_len)) != HAL_OK)
+ return err;
+ break;
- /* This is where we'd use non-zero random bytes if constructing a type 02 block. */
- memset(block + 2, 0xFF, block_len - 3 - data_len);
+ }
block[block_len - data_len - 1] = 0x00;
@@ -231,6 +267,8 @@ static inline hal_error_t ks_open_from_flags(hal_ks_t **ks, const hal_key_flags_
* return a key handle and the name.
*/
+#warning Convert hal_rpc_pkey_load() to use hal-asn1_guess_key_type()?
+
static hal_error_t pkey_local_load(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
@@ -699,7 +737,7 @@ static hal_error_t pkey_local_sign_rsa(uint8_t *keybuf, const size_t keybuf_len,
input = signature;
}
- if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len)) != HAL_OK ||
+ if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len, 0x01)) != HAL_OK ||
(err = hal_rsa_decrypt(NULL, key, signature, *signature_len, signature, *signature_len)) != HAL_OK)
return err;
@@ -831,7 +869,7 @@ static hal_error_t pkey_local_verify_rsa(uint8_t *keybuf, const size_t keybuf_le
input = expected;
}
- if ((err = pkcs1_5_pad(input, input_len, expected, sizeof(expected))) != HAL_OK ||
+ if ((err = pkcs1_5_pad(input, input_len, expected, sizeof(expected), 0x01)) != HAL_OK ||
(err = hal_rsa_encrypt(NULL, key, signature, signature_len, received, sizeof(received))) != HAL_OK)
return err;
@@ -1023,6 +1061,216 @@ static hal_error_t pkey_local_get_attributes(const hal_pkey_handle_t pkey,
return err;
}
+/*
+ * This is an RPC function, so the NULL pointer input convention for
+ * querying required buffer length isn't all that useful, but buffer
+ * lengths are predictable anyway:
+ *
+ * Size of the pkcs8 buffer is a constant, determined by
+ * oid_aes_aesKeyWrap_len, HAL_KS_WRAPPED_KEYSIZE, and some ASN.1
+ * overhead;
+ *
+ * Size of the kek buffer is the same as the length of the
+ * modulus of the RSA public key indicated by wrap_handle.
+ *
+ * Except that we might want ASN.1 around the KEK, something like:
+ *
+ * SEQUENCE {
+ * keyEncryptionAlgorithm AlgorithmIdentifier { rsaEncryption },
+ * encryptedKey OCTET STRING
+ * }
+ *
+ * which would still be constant-length, just a bit more verbose.
+ *
+ * Oddly enough, this is exactly the syntax of PKCS #8
+ * EncryptedPrivateKeyInfo, which we already use for other purposes.
+ * Using it to wrap an AES key encrypted with an RSA key seems a bit
+ * odd, but it's a good fit and lets us reuse ASN.1 code. Cool.
+ */
+
+static hal_error_t pkey_local_export(const hal_pkey_handle_t pkey_handle,
+ const hal_pkey_handle_t kekek_handle,
+ uint8_t *pkcs8, size_t *pkcs8_len, const size_t pkcs8_max,
+ uint8_t *kek, size_t *kek_len, const size_t kek_max)
+{
+ assert(pkcs8 != NULL && pkcs8_len != NULL && kek != NULL && kek_len != NULL && kek_max > KEK_LENGTH);
+
+ uint8_t rsabuf[hal_rsa_key_t_size];
+ hal_rsa_key_t *rsa = NULL;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+ size_t len;
+
+ hal_pkey_slot_t * const pkey = find_handle(pkey_handle);
+ hal_pkey_slot_t * const kekek = find_handle(kekek_handle);
+
+ if (pkey == NULL || kekek == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ if ((pkey->flags & HAL_KEY_FLAG_EXPORTABLE) == 0)
+ return HAL_ERROR_FORBIDDEN;
+
+ if (kekek->type != HAL_KEY_TYPE_RSA_PRIVATE && kekek->type != HAL_KEY_TYPE_RSA_PUBLIC)
+ return HAL_ERROR_UNSUPPORTED_KEY;
+
+ if (pkcs8_max < HAL_KS_WRAPPED_KEYSIZE)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ if ((err = ks_open_from_flags(&ks, kekek->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, kekek, pkcs8, &len, pkcs8_max)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+ if (err != HAL_OK)
+ goto fail;
+
+ switch (kekek->type) {
+ case HAL_KEY_TYPE_RSA_PRIVATE:
+ err = hal_rsa_private_key_from_der(&rsa, rsabuf, sizeof(rsabuf), pkcs8, len);
+ break;
+ case HAL_KEY_TYPE_RSA_PUBLIC:
+ err = hal_rsa_public_key_from_der(&rsa, rsabuf, sizeof(rsabuf), pkcs8, len);
+ break;
+ default:
+ err = HAL_ERROR_IMPOSSIBLE;
+ }
+ if (err != HAL_OK)
+ goto fail;
+
+ if ((err = hal_rsa_get_modulus(rsa, NULL, kek_len, 0)) != HAL_OK)
+ goto fail;
+
+ if (*kek_len > kek_max) {
+ err = HAL_ERROR_RESULT_TOO_LONG;
+ goto fail;
+ }
+
+ if ((err = ks_open_from_flags(&ks, pkey->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, pkey, pkcs8, &len, pkcs8_max)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+
+ if (err != HAL_OK)
+ goto fail;
+
+ if ((err = hal_get_random(NULL, kek, KEK_LENGTH)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_aes_keywrap(NULL, kek, KEK_LENGTH, pkcs8, len, pkcs8, &len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_asn1_encode_pkcs8_encryptedprivatekeyinfo(hal_asn1_oid_aesKeyWrap, hal_asn1_oid_aesKeyWrap_len,
+ pkcs8, len, pkcs8, pkcs8_len, pkcs8_max)) != HAL_OK)
+ goto fail;
+
+ if ((err = pkcs1_5_pad(kek, KEK_LENGTH, kek, *kek_len, 0x02)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_rsa_encrypt(NULL, rsa, kek, *kek_len, kek, *kek_len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_asn1_encode_pkcs8_encryptedprivatekeyinfo(hal_asn1_oid_rsaEncryption, hal_asn1_oid_rsaEncryption_len,
+ kek, *kek_len, kek, *kek_len, kek_max)) != HAL_OK)
+ goto fail;
+
+ memset(rsabuf, 0, sizeof(rsabuf));
+ return HAL_OK;
+
+ fail:
+ memset(pkcs8, 0, pkcs8_max);
+ memset(kek, 0, kek_max);
+ memset(rsabuf, 0, sizeof(rsabuf));
+ *pkcs8_len = *kek_len = 0;
+ return err;
+}
+
+static hal_error_t pkey_local_import(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const hal_pkey_handle_t kekek_handle,
+ const uint8_t * const pkcs8, const size_t pkcs8_len,
+ const uint8_t * const kek_, const size_t kek_len,
+ const hal_key_flags_t flags)
+{
+ assert(pkey != NULL && name != NULL && pkcs8 != NULL && kek_ != NULL && kek_len > 2);
+
+ uint8_t kek[KEK_LENGTH], rsabuf[hal_rsa_key_t_size], der[HAL_KS_WRAPPED_KEYSIZE], *d, *oid, *data;
+ size_t der_len, oid_len, data_len;
+ hal_rsa_key_t *rsa = NULL;
+ hal_curve_name_t curve;
+ hal_key_type_t type;
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+
+ hal_pkey_slot_t * const kekek = find_handle(kekek_handle);
+
+ if (kekek == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ if (kekek->type != HAL_KEY_TYPE_RSA_PRIVATE)
+ return HAL_ERROR_UNSUPPORTED_KEY;
+
+ if ((err = ks_open_from_flags(&ks, kekek->flags)) == HAL_OK &&
+ (err = hal_ks_fetch(ks, kekek, der, &der_len, sizeof(der))) == HAL_OK)
+ err = hal_ks_close(ks);
+ else if (ks != NULL)
+ (void) hal_ks_close(ks);
+ if (err != HAL_OK)
+ goto fail;
+
+ if ((err = hal_rsa_private_key_from_der(&rsa, rsabuf, sizeof(rsabuf), der, der_len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(&oid, &oid_len, &data, &data_len, kek_, kek_len)) != HAL_OK)
+ goto fail;
+
+ if (oid_len != hal_asn1_oid_rsaEncryption_len ||
+ memcmp(oid, hal_asn1_oid_rsaEncryption, oid_len) != 0 ||
+ data_len > sizeof(der) ||
+ data_len < 2) {
+ err = HAL_ERROR_ASN1_PARSE_FAILED;
+ goto fail;
+ }
+
+ if ((err = hal_rsa_decrypt(NULL, rsa, data, data_len, der, data_len)) != HAL_OK)
+ goto fail;
+
+ d = memchr(der + 2, 0x00, data_len - 2);
+
+ if (der[0] != 0x00 || der[1] != 0x02 || d == NULL || der + data_len != d + 1 + KEK_LENGTH) {
+ err = HAL_ERROR_ASN1_PARSE_FAILED;
+ goto fail;
+ }
+
+ memcpy(kek, d + 1, sizeof(kek));
+
+ if ((err = hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(&oid, &oid_len, &data, &data_len, pkcs8, pkcs8_len)) != HAL_OK)
+ goto fail;
+
+ if (oid_len != hal_asn1_oid_aesKeyWrap_len ||
+ memcmp(oid, hal_asn1_oid_aesKeyWrap, oid_len) != 0 ||
+ data_len > sizeof(der)) {
+ err = HAL_ERROR_ASN1_PARSE_FAILED;
+ goto fail;
+ }
+
+ if ((err = hal_aes_keyunwrap(NULL, kek, sizeof(kek), data, data_len, der, &der_len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_asn1_guess_key_type(&type, &curve, der, der_len)) != HAL_OK)
+ goto fail;
+
+ err = pkey_local_load(client, session, pkey, type, curve, name, der, der_len, flags);
+
+ fail:
+ memset(rsabuf, 0, sizeof(rsabuf));
+ memset(kek, 0, sizeof(kek));
+ memset(der, 0, sizeof(der));
+ return err;
+}
+
const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
.load = pkey_local_load,
.open = pkey_local_open,
@@ -1039,7 +1287,9 @@ const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
.verify = pkey_local_verify,
.match = pkey_local_match,
.set_attributes = pkey_local_set_attributes,
- .get_attributes = pkey_local_get_attributes
+ .get_attributes = pkey_local_get_attributes,
+ .export = pkey_local_export,
+ .import = pkey_local_import
};
/*