From 080e32d73617ff70b0021a87e8330eac16c0581f Mon Sep 17 00:00:00 2001
From: Aveen Ismail <42414844+aveenismail@users.noreply.github.com>
Date: Fri, 2 Aug 2024 17:56:43 +0200
Subject: [PATCH] Asymmetric wrap support (#25)
Add support for asymmetric wrap functionality
---
.github/workflows/build_and_test.yml | 48 +-
.github/workflows/integration_test.yml | 17 +-
.github/workflows/release.yml | 21 +-
lib/error.c | 2 +-
lib/scp.h | 2 +-
lib/yubihsm.c | 458 +++++++++++-
lib/yubihsm.h | 243 ++++++-
pkcs11/pkcs11y.h | 11 +
pkcs11/tests/CMakeLists.txt | 21 +-
pkcs11/tests/asym_wrap_test.c | 653 +++++++++++++++++
pkcs11/util_pkcs11.c | 434 ++++++++++--
pkcs11/util_pkcs11.h | 6 +
pkcs11/yubihsm_pkcs11.c | 930 +++++++++++++++++--------
resources/tests/bash/test_wrapkey.sh | 43 +-
src/cmdline.ggo | 9 +
src/commands.c | 395 ++++++++++-
src/commands.h | 10 +
src/main.c | 287 +++++++-
18 files changed, 3118 insertions(+), 472 deletions(-)
create mode 100644 pkcs11/tests/asym_wrap_test.c
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index ba35a84ab..92f0b8bce 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -8,16 +8,16 @@ jobs:
fail-fast: false
matrix:
include:
- - environment: "ubuntu:23.10"
+ - environment: "ubuntu:24.04"
cc: "gcc"
upload_for_test: "false"
- - environment: "ubuntu:23.10"
+ - environment: "ubuntu:24.04"
cc: "clang"
upload_for_test: "false"
- - environment: "ubuntu:23.04"
+ - environment: "ubuntu:23.10"
cc: "gcc"
upload_for_test: "false"
- - environment: "ubuntu:23.04"
+ - environment: "ubuntu:23.10"
cc: "clang"
upload_for_test: "false"
- environment: "ubuntu:22.04"
@@ -32,15 +32,15 @@ jobs:
- environment: "ubuntu:20.04"
cc: "clang"
upload_for_test: "false"
- - environment: "ubuntu:18.04"
- cc: "gcc"
- upload_for_test: "false"
- - environment: "ubuntu:16.04"
- cc: "gcc"
- upload_for_test: "false"
- - environment: "ubuntu:14.04"
- cc: "gcc"
- upload_for_test: "false"
+# - environment: "ubuntu:18.04"
+# cc: "gcc"
+# upload_for_test: "false"
+# - environment: "ubuntu:16.04"
+# cc: "gcc"
+# upload_for_test: "false"
+# - environment: "ubuntu:14.04"
+# cc: "gcc"
+# upload_for_test: "false"
- environment: "debian:12"
cc: "gcc"
upload_for_test: "false"
@@ -53,9 +53,6 @@ jobs:
- environment: "debian:11"
cc: "clang"
upload_for_test: "false"
- - environment: "debian:10"
- cc: "gcc"
- upload_for_test: "false"
name: build on ${{ matrix.environment }} (${{ matrix.cc }},${{ matrix.upload_for_test}})
runs-on: ubuntu-latest
@@ -87,7 +84,7 @@ jobs:
fi
- name: clone the Yubico/yubihsm-shell repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
path: yubihsm-shell
@@ -169,21 +166,18 @@ jobs:
matrix:
include:
# we do not perform clang builds for all environments, only fedora
- - environment: "fedora:38"
+ - environment: "fedora:40"
cc: "gcc"
- upload_for_test: "false"
- - environment: "fedora:38"
+ upload_for_test: "true"
+ - environment: "fedora:40"
cc: "clang"
upload_for_test: "false"
- - environment: "fedora:37"
+ - environment: "fedora:39"
cc: "gcc"
upload_for_test: "false"
- - environment: "fedora:37"
+ - environment: "fedora:39"
cc: "clang"
upload_for_test: "false"
- - environment: "centos:7"
- cc: "gcc"
- upload_for_test: "true"
name: build on ${{ matrix.environment }} (${{ matrix.cc }}, ${{ matrix.upload_for_test }})
runs-on: ubuntu-latest
@@ -352,7 +346,7 @@ jobs:
include:
- environment: "ubuntu:22.04"
cc: "clang"
- - environment: "centos:7"
+ - environment: "fedora:40"
cc: "gcc"
name: run unit tests
@@ -371,7 +365,7 @@ jobs:
apt install -q -y build-essential cmake python3 python3-pip python3-setuptools curl libedit2 libpcsclite1 libengine-pkcs11-openssl opensc swig openjdk-11-jdk-headless libssl3
- name: install dependencies from package management (rpm based)
- if: ${{ matrix.environment == 'centos:7' }}
+ if: ${{ matrix.environment == 'fedora:40' }}
run: |
yum install -y gcc gcc-c++ cmake python3-devel python3-pip python3-setuptools curl libedit gengetopt openssl libcurl pcsc-lite swig java-11-openjdk-headless which
diff --git a/.github/workflows/integration_test.yml b/.github/workflows/integration_test.yml
index ec7945876..903c2e49f 100644
--- a/.github/workflows/integration_test.yml
+++ b/.github/workflows/integration_test.yml
@@ -1,9 +1,6 @@
name: Run Integration Tests
-on:
- schedule:
- # Run this every wednesday at 3:40. https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule
- - cron: '40 3 * * 3'
+on: [push, pull_request]
jobs:
main:
@@ -77,12 +74,12 @@ jobs:
working-directory: yubihsm-shell/resources/tests/bash
run: ./cmdline_test.sh $GITHUB_WORKSPACE/yubihsm-shell/build/src/yubihsm-shell $DEFAULT_CONNECTOR_URL
- - name: run pkcs11-tool tests
- working-directory: yubihsm-shell/resources/tests/bash
- run: |
- echo "connector=$DEFAULT_CONNECTOR_URL" > yubihsm_pkcs11.conf
- export YUBIHSM_PKCS11_CONF=`pwd`/yubihsm_pkcs11.conf
- ./opensc_test.sh $GITHUB_WORKSPACE/yubihsm-shell/build/pkcs11/yubihsm_pkcs11.so
+# - name: run pkcs11-tool tests
+# working-directory: yubihsm-shell/resources/tests/bash
+# run: |
+# echo "connector=$DEFAULT_CONNECTOR_URL" > yubihsm_pkcs11.conf
+# export YUBIHSM_PKCS11_CONF=`pwd`/yubihsm_pkcs11.conf
+# ./opensc_test.sh $GITHUB_WORKSPACE/yubihsm-shell/build/pkcs11/yubihsm_pkcs11.so
- name: clone the YubicoLabs/yubihsm_sunpkcs11_tests repository
uses: actions/checkout@v4
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e132ef6c4..61701464e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -141,16 +141,15 @@ jobs:
fail-fast: false
matrix:
environment: [
+ "ubuntu:24.04",
"ubuntu:23.10",
- "ubuntu:23.04",
"ubuntu:22.04",
"ubuntu:20.04",
- "ubuntu:18.04",
- "ubuntu:16.04",
- "ubuntu:14.04",
+# "ubuntu:18.04",
+# "ubuntu:16.04",
+# "ubuntu:14.04",
"debian:12",
"debian:11",
- "debian:10"
]
# perform gcc builds for all environments
cc: [ "gcc" ]
@@ -208,6 +207,13 @@ jobs:
# append the following flags: -Wno-missing-braces -Wno-missing-field-initializers -Wno-implicit-function-declaration
sed -i 's/-Wall -Wextra -Werror/-Wall -Wextra -Werror -Wno-missing-braces -Wno-missing-field-initializers -Wno-implicit-function-declaration/' cmake/SecurityFlags.cmake
+ - name: apply environment specific changes to CMakeLists.txt
+ working-directory: yubihsm-shell
+ if: ${{ matrix.environment == 'ubuntu:24.04' }}
+ run: |
+ # ubuntu 24.04 comes with _FORTIFY_SOURCE already set
+ sed -i 's/add_definitions (-D_FORTIFY_SOURCE=2)/add_definitions (-D_FORTIFY_SOURCE=3)/' cmake/SecurityFlags.cmake
+
- name: extract platform name
env:
DOCKER_IMAGE: ${{ matrix.environment }}
@@ -278,9 +284,8 @@ jobs:
fail-fast: false
matrix:
environment: [
- "fedora:37",
- "fedora:38",
- "centos:7"
+ "fedora:39",
+ "fedora:40",
]
name: build on ${{ matrix.environment }}
diff --git a/lib/error.c b/lib/error.c
index 71a3c33a0..7e8a98889 100644
--- a/lib/error.c
+++ b/lib/error.c
@@ -39,7 +39,7 @@ static const err_t errors[] = {
ERR(YHR_SESSION_AUTHENTICATION_FAILED, "Unable to authenticate session"),
ERR(YHR_MAC_MISMATCH, "Unable to verify MAC"),
ERR(YHR_DEVICE_OK, "No error"),
- ERR(YHR_DEVICE_INVALID_COMMAND, "Invalid command"),
+ ERR(YHR_DEVICE_INVALID_COMMAND, "Unrecognized command"),
ERR(YHR_DEVICE_INVALID_DATA, "Malformed command / invalid data"),
ERR(YHR_DEVICE_INVALID_SESSION, "Invalid session"),
ERR(YHR_DEVICE_AUTHENTICATION_FAILED,
diff --git a/lib/scp.h b/lib/scp.h
index b9f673c93..242397765 100644
--- a/lib/scp.h
+++ b/lib/scp.h
@@ -49,7 +49,7 @@
#define SCP_AUTHKEY_ID_LEN 2
-#define SCP_MSG_BUF_SIZE 2048
+#define SCP_MSG_BUF_SIZE 4096
// Message
#pragma pack(push, 1)
diff --git a/lib/yubihsm.c b/lib/yubihsm.c
index b0e8a1aba..096ee574e 100644
--- a/lib/yubihsm.c
+++ b/lib/yubihsm.c
@@ -1351,6 +1351,45 @@ yh_rc yh_get_connector_address(yh_connector *connector, char **const address) {
return YHR_SUCCESS;
}
+yh_rc yh_util_get_partnumber(yh_connector *connector, char *part_number,
+ size_t *part_number_len) {
+ if (part_number == NULL || part_number_len == NULL) {
+ // Nothing to read
+ return YHR_SUCCESS;
+ }
+
+ if (connector == NULL) {
+ DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
+ return YHR_INVALID_PARAMETERS;
+ }
+
+ uint8_t response[256] = {0};
+ size_t response_len = sizeof(response);
+ yh_cmd response_cmd = 0;
+
+ uint8_t data[1] = {1};
+ yh_rc yrc =
+ yh_send_plain_msg(connector, YHC_GET_DEVICE_INFO, data, sizeof(data),
+ &response_cmd, response, &response_len);
+ if (yrc != YHR_SUCCESS) {
+ DBG_ERR("Failed to send GET DEVICE INFO command for page 1: %s",
+ yh_strerror(yrc));
+ *part_number_len = 0;
+ return yrc;
+ }
+
+ if (*part_number_len < (response_len + 1)) {
+ DBG_ERR("Response buffer too small");
+ *part_number_len = 0;
+ return YHR_BUFFER_TOO_SMALL;
+ }
+ memcpy(part_number, response, response_len);
+ part_number[response_len] = 0;
+ *part_number_len = response_len;
+
+ return YHR_SUCCESS;
+}
+
yh_rc yh_util_get_device_info(yh_connector *connector, uint8_t *major,
uint8_t *minor, uint8_t *patch, uint32_t *serial,
uint8_t *log_total, uint8_t *log_used,
@@ -1609,22 +1648,28 @@ yh_rc yh_util_get_object_info(yh_session *session, uint16_t id,
return YHR_SUCCESS;
}
-yh_rc yh_util_get_public_key(yh_session *session, uint16_t id, uint8_t *data,
- size_t *data_len, yh_algorithm *algorithm) {
+yh_rc yh_util_get_public_key_ex(yh_session *session, yh_object_type type,
+ uint16_t id, uint8_t *data, size_t *data_len,
+ yh_algorithm *algorithm) {
if (session == NULL || data == NULL || data_len == NULL) {
DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
return YHR_INVALID_PARAMETERS;
}
- uint8_t cmd[2] = {id >> 8, id & 0xff};
+ if (type == YH_PUBLIC_KEY) {
+ type = YH_ASYMMETRIC_KEY;
+ }
+
+ uint8_t cmd[] = {id >> 8, id & 0xff, type};
yh_cmd response_cmd = 0;
uint8_t response[YH_MSG_BUF_SIZE] = {0};
size_t response_len = sizeof(response);
- yh_rc yrc = yh_send_secure_msg(session, YHC_GET_PUBLIC_KEY, cmd, sizeof(cmd),
+ yh_rc yrc = yh_send_secure_msg(session, YHC_GET_PUBLIC_KEY, cmd,
+ type == YH_ASYMMETRIC_KEY ? sizeof(cmd) - 1
+ : sizeof(cmd),
&response_cmd, response, &response_len);
-
if (yrc != YHR_SUCCESS) {
DBG_ERR("Failed to send GET PUBLIC KEY command: %s", yh_strerror(yrc));
return yrc;
@@ -1648,6 +1693,12 @@ yh_rc yh_util_get_public_key(yh_session *session, uint16_t id, uint8_t *data,
return YHR_SUCCESS;
}
+
+yh_rc yh_util_get_public_key(yh_session *session, uint16_t id, uint8_t *data,
+ size_t *data_len, yh_algorithm *algorithm) {
+ return yh_util_get_public_key_ex(session, YH_ASYMMETRIC_KEY, id, data, data_len, algorithm);
+}
+
yh_rc yh_util_close_session(yh_session *session) {
if (session == NULL) {
@@ -1705,7 +1756,7 @@ yh_rc yh_util_sign_pkcs1v1_5(yh_session *session, uint16_t key_id, bool hashed,
uint8_t buf[1];
} data = {0};
#pragma pack(pop)
- uint16_t data_len;
+ size_t data_len;
yh_cmd response_cmd = 0;
@@ -1756,7 +1807,7 @@ yh_rc yh_util_sign_pss(yh_session *session, uint16_t key_id, const uint8_t *in,
uint8_t buf[1];
} data = {0};
#pragma pack(pop)
- uint16_t data_len = in_len;
+ size_t data_len = in_len;
yh_cmd response_cmd = 0;
@@ -1812,7 +1863,7 @@ yh_rc yh_util_sign_ecdsa(yh_session *session, uint16_t key_id,
uint8_t buf[1];
} data = {0};
#pragma pack(pop)
- uint16_t data_len = in_len;
+ size_t data_len = in_len;
yh_cmd response_cmd = 0;
@@ -1853,7 +1904,7 @@ yh_rc yh_util_sign_eddsa(yh_session *session, uint16_t key_id,
uint8_t buf[1];
} data = {0};
#pragma pack(pop)
- uint16_t data_len = in_len;
+ size_t data_len = in_len;
yh_cmd response_cmd = 0;
@@ -1885,7 +1936,7 @@ yh_rc yh_util_sign_hmac(yh_session *session, uint16_t key_id, const uint8_t *in,
}
uint8_t data[YH_MSG_BUF_SIZE] = {0};
- uint16_t data_len = 2;
+ size_t data_len = 2;
yh_cmd response_cmd = 0;
@@ -1934,7 +1985,7 @@ static yh_rc import_key(yh_cmd cmd, yh_session *session, uint16_t *key_id,
const char *label, uint16_t domains,
const yh_capabilities *capabilities,
yh_algorithm algorithm, const uint8_t *key,
- uint16_t key_len) {
+ size_t key_len) {
if (cmd != YHC_PUT_ASYMMETRIC_KEY && cmd != YHC_PUT_SYMMETRIC_KEY) {
DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
return YHR_INVALID_PARAMETERS;
@@ -1977,7 +2028,7 @@ static yh_rc import_key(yh_cmd cmd, yh_session *session, uint16_t *key_id,
}
memcpy(k.bytes, key, key_len);
- uint16_t len = sizeof(k.key_id) + sizeof(k.domains) + sizeof(k.capabilities) +
+ size_t len = sizeof(k.key_id) + sizeof(k.domains) + sizeof(k.capabilities) +
sizeof(k.algo) + sizeof(k.label) + key_len;
yh_rc yrc = yh_send_secure_msg(session, cmd, k.buf, len, &response_cmd,
response.buf, &response_len);
@@ -2006,7 +2057,7 @@ yh_rc yh_util_import_aes_key(yh_session *session, uint16_t *key_id,
return YHR_INVALID_PARAMETERS;
}
- uint16_t len;
+ size_t len;
if (algorithm == YH_ALGO_AES128) {
len = 16;
@@ -2036,7 +2087,7 @@ yh_rc yh_util_import_rsa_key(yh_session *session, uint16_t *key_id,
}
uint8_t keybuf[256 * 2] = {0};
- uint16_t component_len;
+ size_t component_len;
if (algorithm == YH_ALGO_RSA_2048) {
component_len = 128;
@@ -2069,7 +2120,7 @@ yh_rc yh_util_import_ec_key(yh_session *session, uint16_t *key_id,
return YHR_INVALID_PARAMETERS;
}
- uint16_t component_len;
+ size_t component_len;
switch (algorithm) {
case YH_ALGO_EC_P224:
component_len = 28;
@@ -2107,7 +2158,7 @@ yh_rc yh_util_import_ed_key(yh_session *session, uint16_t *key_id,
return YHR_INVALID_PARAMETERS;
}
- uint16_t component_len;
+ size_t component_len;
switch (algorithm) {
case YH_ALGO_EC_ED25519:
component_len = 32;
@@ -2153,7 +2204,7 @@ yh_rc yh_util_import_hmac_key(yh_session *session, uint16_t *key_id,
size_t response_len = sizeof(response);
yh_cmd response_cmd = 0;
size_t max_len = 64;
- int len = sizeof(k) - sizeof(k.key);
+ size_t len = sizeof(k) - sizeof(k.key);
k.key_id = htons(*key_id);
@@ -2220,7 +2271,7 @@ static yh_rc generate_key(yh_cmd cmd, yh_session *session, uint16_t *key_id,
};
uint8_t buf[1];
} data = {0};
- int data_len = sizeof(data);
+ size_t data_len = sizeof(data);
union {
struct {
uint16_t key_id;
@@ -2336,7 +2387,7 @@ yh_rc yh_util_verify_hmac(yh_session *session, uint16_t key_id,
}
uint8_t cmd_data[YH_MSG_BUF_SIZE] = {0};
- int cmd_data_len;
+ size_t cmd_data_len;
uint8_t response[3] = {0};
size_t response_len = sizeof(response);
@@ -2485,7 +2536,7 @@ yh_rc yh_util_decrypt_oaep(yh_session *session, uint16_t key_id,
#pragma pack(pop)
yh_cmd response_cmd = 0;
- uint16_t len = 0;
+ size_t len = 0;
data.key_id = htons(key_id);
len += sizeof(data.key_id);
@@ -2600,6 +2651,12 @@ yh_rc yh_util_delete_object(yh_session *session, uint16_t id,
yh_rc yh_util_export_wrapped(yh_session *session, uint16_t wrapping_key_id,
yh_object_type target_type, uint16_t target_id,
uint8_t *out, size_t *out_len) {
+ return yh_util_export_wrapped_ex(session, wrapping_key_id, target_type, target_id, 0, out, out_len);
+}
+
+yh_rc yh_util_export_wrapped_ex(yh_session *session, uint16_t wrapping_key_id,
+ yh_object_type target_type, uint16_t target_id,
+ uint8_t format, uint8_t *out, size_t *out_len) {
if (session == NULL || out == NULL || out_len == NULL) {
DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
@@ -2612,6 +2669,7 @@ yh_rc yh_util_export_wrapped(yh_session *session, uint16_t wrapping_key_id,
uint16_t key_id;
uint8_t type;
uint16_t tgt_id;
+ uint8_t format;
};
uint8_t buf[1];
} data = {0};
@@ -2622,9 +2680,11 @@ yh_rc yh_util_export_wrapped(yh_session *session, uint16_t wrapping_key_id,
data.key_id = htons(wrapping_key_id);
data.type = (uint8_t) target_type;
data.tgt_id = htons(target_id);
+ data.format = format;
yh_rc yrc = yh_send_secure_msg(session, YHC_EXPORT_WRAPPED, data.buf,
- sizeof(data), &response_cmd, out, out_len);
+ format == 0 ? sizeof(data) - 1 : sizeof(data),
+ &response_cmd, out, out_len);
if (yrc != YHR_SUCCESS) {
DBG_ERR("Failed to send EXPORT WRAPPED command: %s", yh_strerror(yrc));
return yrc;
@@ -2657,7 +2717,7 @@ yh_rc yh_util_import_wrapped(yh_session *session, uint16_t wrapping_key_id,
uint8_t buf[1];
} data = {0};
#pragma pack(pop)
- uint16_t data_len = 2 + in_len;
+ size_t data_len = 2 + in_len;
uint8_t response[YH_MSG_BUF_SIZE] = {0};
size_t response_len = sizeof(response);
@@ -2680,6 +2740,237 @@ yh_rc yh_util_import_wrapped(yh_session *session, uint16_t wrapping_key_id,
return YHR_SUCCESS;
}
+yh_rc yh_util_import_rsa_wrapped(yh_session *session, uint16_t wrapping_key_id,
+ yh_algorithm hash, yh_algorithm mgf1,
+ const uint8_t *label, size_t label_len,
+ const uint8_t *in, size_t in_len,
+ yh_object_type *target_type, uint16_t *target_id) {
+
+ if (session == NULL || in == NULL || target_type == NULL ||
+ target_id == NULL) {
+ DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
+ return YHR_INVALID_PARAMETERS;
+ }
+
+ if (in_len + label_len > YH_MSG_BUF_SIZE) {
+ DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2);
+ return YHR_INVALID_PARAMETERS;
+ }
+
+#pragma pack(push, 1)
+ union {
+ struct {
+ uint16_t wrap_key_id;
+ uint8_t hash;
+ uint8_t mgf1;
+ uint8_t bytes[YH_MSG_BUF_SIZE];
+ };
+ uint8_t buf[1];
+ } data = {
+ {
+ htons(wrapping_key_id),
+ hash,
+ mgf1,
+ { 0 }
+ }
+ };
+#pragma pack(pop)
+ size_t data_len = 4;
+ uint8_t response[YH_MSG_BUF_SIZE] = {0};
+ size_t response_len = sizeof(response);
+ yh_cmd response_cmd = 0;
+
+ memcpy(data.bytes, in, in_len);
+ data_len += in_len;
+ memcpy(data.bytes + in_len, label, label_len);
+ data_len += label_len;
+
+ yh_rc yrc =
+ yh_send_secure_msg(session, YHC_IMPORT_RSA_WRAPPED, data.buf, data_len,
+ &response_cmd, response, &response_len);
+ if (yrc != YHR_SUCCESS) {
+ DBG_ERR("Failed to send IMPORT RSA WRAPPED command: %s", yh_strerror(yrc));
+ return yrc;
+ }
+
+ *target_type = response[0];
+ *target_id = ntohs(*((uint16_t *) (response + 1)));
+
+ return YHR_SUCCESS;
+}
+
+yh_rc yh_util_put_rsa_wrapped_key(yh_session *session, uint16_t wrapping_key_id,
+ yh_object_type type, uint16_t *target_id, yh_algorithm algo, const char *label,
+ uint16_t domains, const yh_capabilities *capabilities,
+ yh_algorithm hash, yh_algorithm mgf1, const uint8_t *oaep_label, size_t oaep_label_len,
+ const uint8_t *in, size_t in_len) {
+
+ if (session == NULL || in == NULL || target_id == NULL || label == NULL || strlen(label) > YH_OBJ_LABEL_LEN) {
+ DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
+ return YHR_INVALID_PARAMETERS;
+ }
+
+ if (in_len + oaep_label_len > YH_MSG_BUF_SIZE) {
+ DBG_ERR("Too much data, must be < %d", YH_MSG_BUF_SIZE - 2);
+ return YHR_INVALID_PARAMETERS;
+ }
+
+#pragma pack(push, 1)
+ union {
+ struct {
+ uint16_t wrap_key_id;
+ uint8_t target_type;
+ uint16_t target_id;
+ uint8_t label[YH_OBJ_LABEL_LEN];
+ uint16_t domains;
+ uint8_t capabilities[YH_CAPABILITIES_LEN];
+ uint8_t algorithm;
+ uint8_t hash;
+ uint8_t mgf1;
+ uint8_t bytes[YH_MSG_BUF_SIZE];
+ };
+ uint8_t buf[1];
+ } data = {
+ {
+ htons(wrapping_key_id),
+ type,
+ htons(*target_id),
+ { 0 }, // label
+ htons(domains),
+ { 0 }, // capabilities
+ algo,
+ hash,
+ mgf1,
+ { 0 }
+ }
+ };
+#pragma pack(pop)
+
+ // 2 bytes wrap key ID +
+ // 1 byte target type +
+ // 2 bytes target ID +
+ // 2 bytes domains +
+ // 1 byte algorithm +
+ // 1 byte hash algorithm +
+ // 1 byte MGF1 algorithm
+ // = 10 bytes
+ size_t data_len = 10 + YH_OBJ_LABEL_LEN + YH_CAPABILITIES_LEN;
+ uint8_t response[YH_MSG_BUF_SIZE] = {0};
+ size_t response_len = sizeof(response);
+ yh_cmd response_cmd = 0;
+
+ memcpy(data.label, label, strlen(label));
+ memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN);
+ memcpy(data.bytes, in, in_len);
+ data_len += in_len;
+ memcpy(data.bytes + in_len, oaep_label, oaep_label_len);
+ data_len += oaep_label_len;
+
+ yh_rc yrc =
+ yh_send_secure_msg(session, YHC_PUT_RSA_WRAPPED_KEY, data.buf, data_len,
+ &response_cmd, response, &response_len);
+ if (yrc != YHR_SUCCESS) {
+ DBG_ERR("Failed to send IMPORT WRAPPED command: %s", yh_strerror(yrc));
+ return yrc;
+ }
+
+ *target_id = ntohs(*((uint16_t *) (response + 1)));
+
+ if (response[0] != type) {
+ DBG_ERR("Imported key type does not match stated key. Removing key.");
+ yh_util_delete_object(session, *target_id, response[0]);
+ *target_id = 0;
+ return YHR_INVALID_PARAMETERS;
+ }
+
+ return YHR_SUCCESS;
+}
+
+static yh_rc
+do_rsa_wrap(yh_cmd cmd,
+ yh_session *session, uint16_t wrap_key_id,
+ yh_object_type target_type, uint16_t target_id,
+ yh_algorithm aes, yh_algorithm hash, yh_algorithm mgf1,
+ const uint8_t *oaep_label, size_t oaep_label_len,
+ uint8_t *out, size_t *out_len) {
+
+ if (session == NULL || out == NULL || out_len == NULL ||
+ oaep_label == NULL) {
+ DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
+ return YHR_INVALID_PARAMETERS;
+ }
+
+#pragma pack(push, 1)
+ union {
+ struct {
+ uint16_t wrap_key_id;
+ uint8_t target_type;
+ uint16_t target_id;
+ uint8_t aes;
+ uint8_t hash;
+ uint8_t mgf1;
+ uint8_t label[64];
+ };
+ uint8_t buf[1];
+ } data = {
+ {
+ htons(wrap_key_id),
+ target_type,
+ htons(target_id),
+ aes,
+ hash,
+ mgf1,
+ { 0 }
+ }
+ };
+#pragma pack(pop)
+
+ yh_cmd response_cmd = 0;
+ size_t len = sizeof(data);
+
+ memcpy(data.label, oaep_label, oaep_label_len);
+ len -= sizeof(data.label);
+ len += oaep_label_len;
+
+ yh_rc yrc = yh_send_secure_msg(session, cmd, data.buf, len,
+ &response_cmd, out, out_len);
+ if (yrc != YHR_SUCCESS) {
+ DBG_ERR("Failed to send 0x%02x command: %s", cmd, yh_strerror(yrc));
+ return yrc;
+ }
+
+ return YHR_SUCCESS;
+}
+
+yh_rc yh_util_get_rsa_wrapped_key(yh_session *session, uint16_t wrap_key_id,
+ yh_object_type target_type,
+ uint16_t target_id, yh_algorithm aes,
+ yh_algorithm hash, yh_algorithm mgf1,
+ const uint8_t *oaep_label,
+ size_t oaep_label_len, uint8_t *out,
+ size_t *out_len) {
+
+ if (target_type != YH_ASYMMETRIC_KEY && target_type != YH_SYMMETRIC_KEY) {
+ DBG_ERR("Only symmetric or asymmetric keys are supported");
+ return YHR_INVALID_PARAMETERS;
+ }
+ return do_rsa_wrap(YHC_GET_RSA_WRAPPED_KEY, session, wrap_key_id, target_type,
+ target_id, aes, hash, mgf1, oaep_label, oaep_label_len,
+ out, out_len);
+}
+
+yh_rc yh_util_export_rsa_wrapped(yh_session *session, uint16_t wrap_key_id,
+ yh_object_type target_type, uint16_t target_id,
+ yh_algorithm aes, yh_algorithm hash,
+ yh_algorithm mgf1, const uint8_t *oaep_label,
+ size_t oaep_label_len, uint8_t *out,
+ size_t *out_len) {
+
+ return do_rsa_wrap(YHC_EXPORT_RSA_WRAPPED, session, wrap_key_id, target_type,
+ target_id, aes, hash, mgf1, oaep_label, oaep_label_len,
+ out, out_len);
+}
+
yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id,
const char *label, uint16_t domains,
const yh_capabilities *capabilities,
@@ -2703,11 +2994,10 @@ yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id,
uint8_t capabilities[YH_CAPABILITIES_LEN];
uint8_t algorithm;
uint8_t delegated_capabilities[YH_CAPABILITIES_LEN];
- uint8_t key[32];
+ uint8_t key[512];
};
uint8_t buf[1];
} data = {0};
- uint16_t data_len = sizeof(data);
union {
struct {
uint16_t key_id;
@@ -2718,27 +3008,36 @@ yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id,
size_t response_len = sizeof(response);
yh_cmd response_cmd = 0;
- uint16_t key_len;
+ size_t key_len = 0;
switch (algorithm) {
case YH_ALGO_AES128_CCM_WRAP:
key_len = 16;
- data_len -= 16;
break;
case YH_ALGO_AES192_CCM_WRAP:
key_len = 24;
- data_len -= 8;
break;
case YH_ALGO_AES256_CCM_WRAP:
key_len = 32;
break;
+ case YH_ALGO_RSA_2048:
+ key_len = 256;
+ break;
+ case YH_ALGO_RSA_3072:
+ key_len = 384;
+ break;
+ case YH_ALGO_RSA_4096:
+ key_len = 512;
+ break;
default:
DBG_ERR("Bad algorithm specified: %x", algorithm);
return YHR_INVALID_PARAMETERS;
}
+ size_t data_len = sizeof(data) - sizeof(data.key) + key_len;
+
if (in_len != key_len) {
- DBG_ERR("Key length not matching, should be %d", key_len);
+ DBG_ERR("Key length not matching, should be %zu", key_len);
return YHR_INVALID_PARAMETERS;
}
@@ -2766,6 +3065,91 @@ yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id,
return YHR_SUCCESS;
}
+yh_rc yh_util_import_public_wrap_key(yh_session *session, uint16_t *key_id,
+ const char *label, uint16_t domains,
+ const yh_capabilities *capabilities,
+ yh_algorithm algorithm,
+ const yh_capabilities *delegated_capabilities,
+ const uint8_t *in, size_t in_len) {
+
+ if (session == NULL || key_id == NULL || label == NULL ||
+ strlen(label) > YH_OBJ_LABEL_LEN || capabilities == NULL ||
+ delegated_capabilities == NULL || in == NULL) {
+ DBG_ERR("%s", yh_strerror(YHR_INVALID_PARAMETERS));
+ return YHR_INVALID_PARAMETERS;
+ }
+
+#pragma pack(push, 1)
+ union {
+ struct {
+ uint16_t key_id;
+ uint8_t label[YH_OBJ_LABEL_LEN];
+ uint16_t domains;
+ uint8_t capabilities[YH_CAPABILITIES_LEN];
+ uint8_t algorithm;
+ uint8_t delegated_capabilities[YH_CAPABILITIES_LEN];
+ uint8_t key[512];
+ };
+ uint8_t buf[1];
+ } data = {0};
+ union {
+ struct {
+ uint16_t key_id;
+ };
+ uint8_t buf[1];
+ } response = {0};
+#pragma pack(pop)
+
+ size_t response_len = sizeof(response);
+ yh_cmd response_cmd = 0;
+ size_t key_len;
+
+ switch (algorithm) {
+ case YH_ALGO_RSA_2048:
+ key_len = 256;
+ break;
+ case YH_ALGO_RSA_3072:
+ key_len = 384;
+ break;
+ case YH_ALGO_RSA_4096:
+ key_len = 512;
+ break;
+ default:
+ DBG_ERR("Bad algorithm specified: %x", algorithm);
+ return YHR_INVALID_PARAMETERS;
+ }
+
+ size_t data_len = sizeof(data) - sizeof(data.key) + key_len;
+
+ if (in_len != key_len) {
+ DBG_ERR("Key length not matching, should be %zu", key_len);
+ return YHR_INVALID_PARAMETERS;
+ }
+
+ data.key_id = htons(*key_id);
+ memcpy(data.label, label, strlen(label));
+ memset(data.label + strlen(label), 0, YH_OBJ_LABEL_LEN - strlen(label));
+ data.domains = htons(domains);
+ memcpy(data.capabilities, capabilities, YH_CAPABILITIES_LEN);
+ data.algorithm = algorithm;
+ memcpy(data.delegated_capabilities, delegated_capabilities,
+ YH_CAPABILITIES_LEN);
+ memcpy(data.key, in, key_len);
+
+ yh_rc yrc = yh_send_secure_msg(session, YHC_PUT_PUBLIC_WRAPKEY, data.buf, data_len,
+ &response_cmd, response.buf, &response_len);
+ insecure_memzero(data.buf, data_len);
+ if (yrc != YHR_SUCCESS) {
+ DBG_ERR("Failed to send PUT PUBLIC WRAP KEY command: %s", yh_strerror(yrc));
+ return yrc;
+ }
+
+ *key_id = ntohs(response.key_id);
+ DBG_INFO("Imported public wrap key 0x%04x", *key_id);
+
+ return YHR_SUCCESS;
+}
+
yh_rc yh_util_generate_wrap_key(yh_session *session, uint16_t *key_id,
const char *label, uint16_t domains,
const yh_capabilities *capabilities,
@@ -2791,7 +3175,7 @@ yh_rc yh_util_generate_wrap_key(yh_session *session, uint16_t *key_id,
};
uint8_t buf[1];
} data = {0};
- uint16_t data_len = sizeof(data);
+ size_t data_len = sizeof(data);
union {
struct {
uint16_t key_id;
@@ -2821,7 +3205,7 @@ yh_rc yh_util_generate_wrap_key(yh_session *session, uint16_t *key_id,
yh_send_secure_msg(session, YHC_GENERATE_WRAP_KEY, data.buf, data_len,
&response_cmd, response.buf, &response_len);
if (yrc != YHR_SUCCESS) {
- DBG_ERR("Failed to send GENERATE WRAP KEY command: %s", yh_strerror(yrc));
+ DBG_ERR("Failed to generate wrap key: %s", yh_strerror(yrc));
return yrc;
}
@@ -2982,7 +3366,7 @@ yh_rc yh_util_import_opaque(yh_session *session, uint16_t *object_id,
};
uint8_t buf[1];
} data = {0};
- uint16_t data_len;
+ size_t data_len;
union {
struct {
uint16_t object_id;
@@ -3047,7 +3431,7 @@ yh_rc yh_util_sign_ssh_certificate(yh_session *session, uint16_t key_id,
};
uint8_t buf[1];
} data = {0};
- uint16_t data_len;
+ size_t data_len;
#pragma pack(pop)
yh_cmd response_cmd = 0;
@@ -3126,7 +3510,7 @@ yh_rc yh_util_import_template(yh_session *session, uint16_t *object_id,
};
uint8_t buf[1];
} data = {0};
- uint16_t data_len;
+ size_t data_len;
union {
struct {
uint16_t object_id;
@@ -3587,7 +3971,7 @@ yh_rc yh_util_import_otp_aead_key(yh_session *session, uint16_t *key_id,
} response = {0};
#pragma pack(pop)
- uint16_t data_len = sizeof(data);
+ size_t data_len = sizeof(data);
size_t response_len = sizeof(response);
yh_cmd response_cmd = 0;
@@ -3655,7 +4039,7 @@ yh_rc yh_util_generate_otp_aead_key(yh_session *session, uint16_t *key_id,
};
uint8_t buf[1];
} data = {0};
- uint16_t data_len = sizeof(data);
+ size_t data_len = sizeof(data);
union {
struct {
uint16_t key_id;
@@ -3864,7 +4248,7 @@ yh_rc yh_util_wrap_data(yh_session *session, uint16_t key_id, const uint8_t *in,
uint8_t buf[1];
} data = {0};
#pragma pack(pop)
- uint16_t data_len = in_len + 2;
+ size_t data_len = in_len + 2;
yh_cmd response_cmd = 0;
@@ -3905,7 +4289,7 @@ yh_rc yh_util_unwrap_data(yh_session *session, uint16_t key_id,
uint8_t buf[1];
} data = {0};
#pragma pack(pop)
- uint16_t data_len = in_len + 2;
+ size_t data_len = in_len + 2;
yh_cmd response_cmd = 0;
diff --git a/lib/yubihsm.h b/lib/yubihsm.h
index 0d7001602..792e767a3 100644
--- a/lib/yubihsm.h
+++ b/lib/yubihsm.h
@@ -88,7 +88,7 @@
/// Length of host challenge for authentication
#define YH_HOST_CHAL_LEN 8
/// Maximum length of message buffer
-#define YH_MSG_BUF_SIZE 2048
+#define YH_MSG_BUF_SIZE 4096
/// Length of authentication keys
#define YH_KEY_LEN 16
/// Device vendor ID
@@ -359,6 +359,16 @@ typedef enum {
ADD_COMMAND(YHC_DECRYPT_CBC, 0x71),
/// Encrypt data using a Symmetric Key with CBC
ADD_COMMAND(YHC_ENCRYPT_CBC, 0x72),
+ /// Import public RSA key as a Public Wrap Key
+ ADD_COMMAND(YHC_PUT_PUBLIC_WRAPKEY, 0x73),
+ /// Export (a)symmetric key using a Public Wrap Key
+ ADD_COMMAND(YHC_GET_RSA_WRAPPED_KEY, 0x74),
+ /// Import (a)symmetric key after unwrapping in using and RSA wrap key
+ ADD_COMMAND(YHC_PUT_RSA_WRAPPED_KEY, 0x75),
+ /// Wrap an object using an RSA Wrap Key
+ ADD_COMMAND(YHC_EXPORT_RSA_WRAPPED, 0x76),
+ /// Import an object after unwrapping in using and RSA Wrap Key
+ ADD_COMMAND(YHC_IMPORT_RSA_WRAPPED, 0x77),
/// The response byte returned from the device if the command resulted in an
/// error
YHC_ERROR = 0x7f,
@@ -392,6 +402,9 @@ typedef enum {
YH_OTP_AEAD_KEY = 0x07,
/// Symmetric Key is a secret key used for encryption and decryption.
YH_SYMMETRIC_KEY = 0x08,
+ /// Public Wrap Key is a public key used to wrap Objects during the
+ /// export process
+ YH_PUBLIC_WRAP_KEY = 0x09,
/// Public Key is the public key of an asymmetric key-pair. The public key
/// never exists in device and is mostly here for PKCS#11.
YH_PUBLIC_KEY = 0x83,
@@ -514,6 +527,8 @@ typedef enum {
YH_ALGO_AES_ECB = 53,
/// aes-cbc
YH_ALGO_AES_CBC = 54,
+ /// aes-kwp
+ YH_ALGO_AES_KWP = 55,
} yh_algorithm;
/**
@@ -623,6 +638,7 @@ static const struct {
{"delete-hmac-key", 0x2b},
{"delete-opaque", 0x27},
{"delete-otp-aead-key", 0x2d},
+ {"delete-public-wrap-key", 0x55},
{"delete-symmetric-key", 0x31},
{"delete-template", 0x2c},
{"delete-wrap-key", 0x2a},
@@ -647,6 +663,7 @@ static const struct {
{"put-mac-key", 0x14},
{"put-opaque", 0x01},
{"put-otp-aead-key", 0x23},
+ {"put-public-wrap-key", 0x54},
{"put-symmetric-key", 0x2f},
{"put-template", 0x1b},
{"put-wrap-key", 0x0e},
@@ -683,6 +700,7 @@ static const struct {
{"aes256-yubico-otp", YH_ALGO_AES256_YUBICO_OTP},
{"aes-cbc", YH_ALGO_AES_CBC},
{"aes-ecb", YH_ALGO_AES_ECB},
+ {"aes-kwp", YH_ALGO_AES_KWP},
{"ecbp256", YH_ALGO_EC_BP256},
{"ecbp384", YH_ALGO_EC_BP384},
{"ecbp512", YH_ALGO_EC_BP512},
@@ -736,6 +754,7 @@ static const struct {
{"hmac-key", YH_HMAC_KEY},
{"opaque", YH_OPAQUE},
{"otp-aead-key", YH_OTP_AEAD_KEY},
+ {"public-wrap-key", YH_PUBLIC_WRAP_KEY},
{"symmetric-key", YH_SYMMETRIC_KEY},
{"template", YH_TEMPLATE},
{"wrap-key", YH_WRAP_KEY},
@@ -1229,6 +1248,24 @@ yh_rc yh_util_get_device_info(yh_connector *connector, uint8_t *major,
uint8_t *log_total, uint8_t *log_used,
yh_algorithm *algorithms, size_t *n_algorithms);
+/**
+ * Get device version, part number (chip designator) as required ny FIPS
+ *
+ * @param connector Connector to the device
+ * @param part_number Part number (chip designator)
+ * @param part_number_len Size of part_number
+ *
+ * @return #YHR_SUCCESS if successful or of part_number is NULL
+ * #YHR_DEVICE_INVALID_COMMAND if firmware version does not support the
+ *command
+ * #YHR_INVALID_PARAMETER if the connector is NULL.
+ * #YH_INVALID_DEVICE_INVALID_DATA If returned part_number is less than
+ *12 bytes
+ * #YHR_BUFFER_TOO_SMALL if part_number is smaller than 13 bytes
+ **/
+yh_rc yh_util_get_partnumber(yh_connector *connector, char *part_number,
+ size_t *part_number_len);
+
/**
* List objects accessible from the session
*
@@ -1303,6 +1340,23 @@ yh_rc yh_util_get_object_info(yh_session *session, uint16_t id,
yh_rc yh_util_get_public_key(yh_session *session, uint16_t id, uint8_t *data,
size_t *data_len, yh_algorithm *algorithm);
+/**
+ * Get the value of the public key with the specified Object ID and type
+ *
+ * @param session Authenticated session to use
+ * @param id Object ID of the public key
+ * @param type Object type of the public key
+ * @param data Value of the public key
+ * @param data_len Length of the public key in bytes
+ * @param algorithm Algorithm of the key
+ *
+ * @return #YHR_SUCCESS if successful.
+ * #YHR_INVALID_PARAMETERS if input parameters are NULL.
+ * #YHR_BUFFER_TOO_SMALL if the actual key length was bigger than
+ *data_len. See #yh_rc for other possible errors
+ **/
+yh_rc yh_util_get_public_key_ex(yh_session *session, yh_object_type type, uint16_t id, uint8_t *data, size_t *data_len, yh_algorithm *algorithm);
+
/**
* Close a session
*
@@ -1800,10 +1854,31 @@ yh_rc yh_util_delete_object(yh_session *session, uint16_t id,
* #YHR_INVALID_PARAMETERS if input parameters are NULL.
* See #yh_rc for other possible errors
**/
+
yh_rc yh_util_export_wrapped(yh_session *session, uint16_t wrapping_key_id,
yh_object_type target_type, uint16_t target_id,
uint8_t *out, size_t *out_len);
+/**
+ * Export an object under wrap from the device with the option to include the
+ *ED25519 seed
+ *
+ * @param session Authenticated session to use
+ * @param wrapping_key_id Object ID of the Wrap Key to use to wrap the object
+ * @param target_type Type of the object to be exported. See #yh_object_type
+ * @param target_id Object ID of the object to be exported
+ * @param format Curently supported formats: 0=legacy 1=include ED25519 seed
+ * @param out Wrapped data
+ * @param out_len Length of wrapped data
+ *
+ * @return #YHR_SUCCESS if successful.
+ * #YHR_INVALID_PARAMETERS if input parameters are NULL.
+ * See #yh_rc for other possible errors
+ **/
+yh_rc yh_util_export_wrapped_ex(yh_session *session, uint16_t wrapping_key_id,
+ yh_object_type target_type, uint16_t target_id,
+ uint8_t format, uint8_t *out, size_t *out_len);
+
/**
* Import a wrapped object into the device. The object should have been
*previously exported by #yh_util_export_wrapped()
@@ -1823,6 +1898,131 @@ yh_rc yh_util_import_wrapped(yh_session *session, uint16_t wrapping_key_id,
const uint8_t *in, size_t in_len,
yh_object_type *target_type, uint16_t *target_id);
+/**
+ * Export a (a)symmetric key material using an RSA wrap key, meta data or
+ *properties, like domains and capabilities, are not included. Only asymmetric
+ *and symmetric key objects are valid targets.
+ *
+ * @param session Authenticated session to use
+ * @param wrapping_key_id Object ID of the Wrap Key to use to wrap the object
+ * @param target_type Type of the target key object
+ * @param target_id Object ID of the target key object
+ * @param aes Algorithm of the ephemeral AES key. Can be #YH_ALGO_AES128,
+ *#YH_ALGO_AES192 or #YH_ALGO_AES256
+ * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1,
+ *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512
+ * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256,
+ *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512
+ * @param label Label for the MGF1 algorithm
+ * @param label_len Label length
+ * @param out Wrapped key object bytes
+ * @param out_len Length of the wrapped key
+ *
+ * @return #YHR_SUCCESS if successful.
+ * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the
+ * command is not supported.
+ * See #yh_rc for other possible errors
+ **/
+yh_rc yh_util_get_rsa_wrapped_key(yh_session *session, uint16_t wrap_key_id,
+ yh_object_type target_type,
+ uint16_t target_id, yh_algorithm aes,
+ yh_algorithm hash, yh_algorithm mgf1,
+ const uint8_t *oaep_label,
+ size_t oaep_label_len, uint8_t *out,
+ size_t *out_len);
+
+/**
+ * Export an object using an RSA wrap key. The wrapped object contain all meta
+ *data and properties, like domains and capabilities
+ *
+ * @param session Authenticated session to use
+ * @param wrapping_key_id Object ID of the Wrap Key to use to wrap the object
+ * @param target_type Type of the target object
+ * @param target_id Object ID of the target object
+ * @param aes Algorithm of the ephemeral AES key. Can be #YH_ALGO_AES128,
+ *#YH_ALGO_AES192 or #YH_ALGO_AES256
+ * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1,
+ *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512
+ * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256,
+ *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512
+ * @param label Label for the MGF1 algorithm
+ * @param label_len Label length
+ * @param out Wrapped object bytes
+ * @param out_len Length of the wrapped object
+ *
+ * @return #YHR_SUCCESS if successful.
+ * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the
+ * command is not supported.
+ * See #yh_rc for other possible errors
+ **/
+yh_rc yh_util_export_rsa_wrapped(yh_session *session, uint16_t wrap_key_id,
+ yh_object_type target_type, uint16_t target_id,
+ yh_algorithm aes, yh_algorithm hash,
+ yh_algorithm mgf1, const uint8_t *oaep_label,
+ size_t oaep_label_len, uint8_t *out,
+ size_t *out_len);
+
+/**
+ * Import an object using an RSA wrap key.
+ *
+ * @param session Authenticated session to use
+ * @param wrapping_key_id Object ID of the Wrap Key to use to unwrap the object
+ * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1,
+ *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512
+ * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256,
+ *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512
+ * @param label Label for the MGF1 algorithm
+ * @param label_len Label length
+ * @param in Wrapped object bytes
+ * @param in_len Length of the wrapped object
+ * @param target_type Type of the target object
+ * @param target_id Object ID of the target object
+ *
+ * @return #YHR_SUCCESS if successful.
+ * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the
+ * command is not supported.
+ * See #yh_rc for other possible errors
+ **/
+yh_rc yh_util_import_rsa_wrapped(yh_session *session, uint16_t wrapping_key_id,
+ yh_algorithm hash, yh_algorithm mgf1,
+ const uint8_t *label, size_t label_len,
+ const uint8_t *in, size_t in_len,
+ yh_object_type *target_type,
+ uint16_t *target_id);
+
+/**
+ * Import an (a)symmetric key using an RSA wrap key.
+ *
+ * @param session Authenticated session to use
+ * @param wrapping_key_id Object ID of the Wrap Key to use to unwrap the object
+ * @param type Type of object to import. One of #YH_SYMMETRIC_KEY or
+ *#YH_ASYMMETRIC_KEY
+ * @param target_id Object ID of object to import
+ * @param algo Key algorithm of object to import
+ * @param label Label of object to import
+ * @param domains Domains of object to import
+ * @param capabilities of object to import
+ * @param hash Hash algorithm. One of #YH_ALGO_RSA_OAEP_SHA1,
+ *#YH_ALGO_RSA_OAEP_SHA256, #YH_ALGO_RSA_OAEP_SHA384 or #YH_ALGO_RSA_OAEP_SHA512
+ * @param mgf1 MGF1 algorithm. One of #YH_ALGO_MGF1_SHA1, #YH_ALGO_MGF1_SHA256,
+ *#YH_ALGO_MGF1_SHA384 or #YH_ALGO_MGF1_SHA512
+ * @param oaep_label Label for the MGF1 algorithm
+ * @param oaep_label_len Label length
+ * @param in Wrapped object bytes
+ * @param in_len Length of the wrapped object
+ *
+ * @return #YHR_SUCCESS if successful.
+ * #YHR_INVALID_PARAMETERS if input parameters are NULL or if the
+ * command is not supported.
+ * See #yh_rc for other possible errors
+ **/
+yh_rc yh_util_put_rsa_wrapped_key(
+ yh_session *session, uint16_t wrapping_key_id, yh_object_type type,
+ uint16_t *target_id, yh_algorithm algo, const char *label, uint16_t domains,
+ const yh_capabilities *capabilities, yh_algorithm hash, yh_algorithm mgf1,
+ const uint8_t *oaep_label, size_t oaep_label_len, const uint8_t *in,
+ size_t in_len);
+
/**
* Import a Wrap Key into the device
*
@@ -1835,8 +2035,9 @@ yh_rc yh_util_import_wrapped(yh_session *session, uint16_t wrapping_key_id,
* @param capabilities Capabilities of the Wrap Key. See
*#yh_string_to_capabilities()
* @param algorithm Algorithm of the Wrap Key. Supported algorithms:
- *#YH_ALGO_AES128_CCM_WRAP, #YH_ALGO_AES192_CCM_WRAP and
- *#YH_ALGO_AES256_CCM_WRAP
+ *#YH_ALGO_AES128_CCM_WRAP, #YH_ALGO_AES192_CCM_WRAP,
+ *#YH_ALGO_AES256_CCM_WRAP, #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 and
+ * #YH_ALGO_RSA_4096
* @param delegated_capabilities Delegated capabilities of the Wrap Key. See
*#yh_string_to_capabilities()
* @param in the Wrap Key to import
@@ -1845,8 +2046,9 @@ yh_rc yh_util_import_wrapped(yh_session *session, uint16_t wrapping_key_id,
* @return #YHR_SUCCESS if successful.
* #YHR_INVALID_PARAMETERS if input parameters are NULL, in_len
*is not what expected based on the algorithm and if the algorithms is not one
- *of #YH_ALGO_AES128_CCM_WRAP, #YH_ALGO_AES192_CCM_WRAP or
- *#YH_ALGO_AES256_CCM_WRAP.
+ *of #YH_ALGO_AES128_CCM_WRAP, #YH_ALGO_AES192_CCM_WRAP,
+ *#YH_ALGO_AES256_CCM_WRAP or an RSA key algorithm. #YHR_INVALID_PARAMETERS will
+ * also be returned if the firmware version does not support RSA wrap keys.
* See #yh_rc for other possible errors
**/
yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id,
@@ -1856,6 +2058,37 @@ yh_rc yh_util_import_wrap_key(yh_session *session, uint16_t *key_id,
const yh_capabilities *delegated_capabilities,
const uint8_t *in, size_t in_len);
+/**
+ * Import a public RSA key as a public wrap Key into the device
+ *
+ * @param session Authenticated session to use
+ * @param key_id Object ID the Wrap Key. 0 if the Object ID should be generated
+ *by the device
+ * @param label Label of the Wrap Key. Maximum length is #YH_OBJ_LABEL_LEN
+ * @param domains Domains where the Wrap Key will be operating within. See
+ *#yh_string_to_domains()
+ * @param capabilities Capabilities of the Wrap Key. See
+ *#yh_string_to_capabilities()
+ * @param algorithm Algorithm of the Public Wrap Key. Supported algorithms:
+ *#YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 and #YH_ALGO_RSA_4096
+ * @param delegated_capabilities Delegated capabilities of the Wrap Key. See
+ *#yh_string_to_capabilities()
+ * @param in the Public Wrap Key to import in PEM format
+ * @param in_len Length of the Wrap Key to import
+ *
+ * @return #YHR_SUCCESS if successful.
+ * #YHR_INVALID_PARAMETERS if input parameters are NULL, in_len
+ *is not what expected based on the algorithm and if the algorithms is not one
+ *of #YH_ALGO_RSA_2048, #YH_ALGO_RSA_3072 or #YH_ALGO_RSA_4096.
+ * See #yh_rc for other possible errors
+ **/
+yh_rc yh_util_import_public_wrap_key(yh_session *session, uint16_t *key_id,
+ const char *label, uint16_t domains,
+ const yh_capabilities *capabilities,
+ yh_algorithm algorithm,
+ const yh_capabilities *delegated_capabilities,
+ const uint8_t *in, size_t in_len);
+
/**
* Generate a Wrap Key that can be used for export, import, wrap data and unwrap
*data in the device.
diff --git a/pkcs11/pkcs11y.h b/pkcs11/pkcs11y.h
index 555b2f2fd..e0dc9bf6f 100644
--- a/pkcs11/pkcs11y.h
+++ b/pkcs11/pkcs11y.h
@@ -76,4 +76,15 @@ extern "C" {
#define CKM_YUBICO_AES_CCM_WRAP \
(CKM_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_WRAP_KEY)
+/* CKM_YUBICO_AES_CCM_WRAP_PARAMS provides the parameters to the
+ * CKM_YUBICO_AES_CCM_WRAP mechanism.
+ */
+typedef struct CKM_YUBICO_AES_CCM_WRAP_PARAMS {
+ CK_ULONG format; // 0 = legacy, 1 = ED keys with seed
+} CKM_YUBICO_AES_CCM_WRAP_PARAMS;
+
+typedef CKM_YUBICO_AES_CCM_WRAP_PARAMS CK_PTR CKM_YUBICO_AES_CCM_WRAP_PARAMS_PTR;
+
+#define CKM_YUBICO_RSA_WRAP \
+ (CKM_VENDOR_DEFINED | YUBICO_BASE_VENDOR | YH_PUBLIC_WRAP_KEY)
#endif
diff --git a/pkcs11/tests/CMakeLists.txt b/pkcs11/tests/CMakeLists.txt
index 6486543e9..3b0d74ae9 100644
--- a/pkcs11/tests/CMakeLists.txt
+++ b/pkcs11/tests/CMakeLists.txt
@@ -227,6 +227,12 @@ set (
common.c
)
+set (
+ SOURCE_ASYM_WRAP_TEST
+ asym_wrap_test.c
+ common.c
+)
+
set (
SOURCE_PKCS11_INTERFACES_TEST
pkcs11_interfaces_test.c
@@ -270,12 +276,10 @@ add_test (
if (NOT ${LIBCRYPTO_VERSION} VERSION_LESS 1.1)
add_executable (rsa_enc_test ${SOURCE_RSA_ENC_TEST})
-
target_link_libraries (
rsa_enc_test
${LIBCRYPTO_LDFLAGS}
"-ldl")
-
add_test (
NAME rsa_enc_test
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/rsa_enc_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT}
@@ -283,24 +287,29 @@ if (NOT ${LIBCRYPTO_VERSION} VERSION_LESS 1.1)
add_executable (pss_sign_test ${SOURCE_RSA_PSS_SIGN_TEST})
-
target_link_libraries (
pss_sign_test
${LIBCRYPTO_LDFLAGS}
"-ldl")
-
add_test (
NAME pss_sign_test
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pss_sign_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT}
)
+ add_executable (asym_wrap_test ${SOURCE_ASYM_WRAP_TEST})
+ target_link_libraries (
+ asym_wrap_test
+ ${LIBCRYPTO_LDFLAGS}
+ "-ldl")
+ add_test (
+ NAME asym_wrap_test
+ COMMAND ${CMAKE_CURRENT_BINARY_DIR}/asym_wrap_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT}
+ )
add_executable (pkcs11_interfaces_test ${SOURCE_PKCS11_INTERFACES_TEST})
-
target_link_libraries (
pkcs11_interfaces_test
"-ldl")
-
add_test (
NAME pkcs11_interfaces_test
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/pkcs11_interfaces_test ${CMAKE_CURRENT_BINARY_DIR}/../yubihsm_pkcs11.${LIBEXT}
diff --git a/pkcs11/tests/asym_wrap_test.c b/pkcs11/tests/asym_wrap_test.c
new file mode 100644
index 000000000..5f37ae4b1
--- /dev/null
+++ b/pkcs11/tests/asym_wrap_test.c
@@ -0,0 +1,653 @@
+/*
+ * Copyright 2015-2018 Yubico AB
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "../pkcs11y.h"
+#include "../lib/yubihsm.h"
+#include "common.h"
+#include "../common/util.h"
+
+const char rsa2048[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIEpAIBAAKCAQEA1mA5mATDvo4dN7gTNyXMr+Sen2vkTaYY2vDY6B59ZuQp7si9\n"
+ "H4sjjZjXm0/+CCuwmi287mu8zrqDYsi+cVtw+KsVdMp7EmaHUelael0JzUy+pbJs\n"
+ "4+PT8kZ/ytx2640j5P1H7mt/LJKcJCq7U0N4WUGx5YEyPUPGJxCgYgnXx8CSxCst\n"
+ "A3leSfVEnPu9kA7hztMREfyrSIyLoDcNY3y0n7yHL/uHlNAIMvOT1+RAqYHm1mxQ\n"
+ "sKZtDNtRBACRh4j1wKZSjK+0Wt0h15RJ4fp0i+smNR5rU0UpvpjfbeEe14DBxxE5\n"
+ "v0W64hsIoedJh5GD9vWARa1wF8+pi+KDHny5KwIDAQABAoIBAG4o4k+g2yl3g8IX\n"
+ "ICCtluIn++72FUpleM5BB2U4Db6qrnWax7yG1k0z5k9UKrjuIoEH0dc+m7Yrl8pS\n"
+ "V7KOh53w5ESwq8+Hyi+oVysb1iaeMjWZW2U7tLUBzzdiVOW0EGbiVG1K5f30lLHt\n"
+ "F3ew6w4KuSyzWCqtQgze+VuHrU9iT/jllv/KFxxaIFQeUOL0sR0CeE7gji7QE4C1\n"
+ "2WjYjGYb7+N+3R+nmWq3NOXBarj4vSQ42UngzO2eH6d04KsCWJzOQ/2ymCzoai+v\n"
+ "AaiACdrOrZFscJw8E8jyrNHDEBXvqY6j3S4444FshKiXij5gLoZZ22rY2lWcc3s+\n"
+ "qOPK9MkCgYEA7wVV3ON+nmS+GZKRa+RlQ0Ooh/VlYw2NJBxmPrYVTN/YQAzE2hoA\n"
+ "OVrXOjfuF4g/YgxvvbKcImSxUvAoemUPO0v/9NA0L1u8ehP/S+RrmvTk4IG2OlGs\n"
+ "LqAzpUp1t4OONKzulISmJ0LNRblwbA2ORgugVo5/X495XIwJZ5V2cX0CgYEA5Zq2\n"
+ "scXFMmcl99OgH5DwPtlYLlKjub4lhiyEEWghcCMDriLlbT/oqi3cJlJejsqHhI+u\n"
+ "pWH8WBfoVc2xNvaqzqzCJtKHxjjrEhwpjFO7e+idxwbKCB6blpBwayClVjd3UURz\n"
+ "TNBWPPvx0a1cMyufF1g1Nw8DwpjfTeA7WZdsVccCgYAhW0NCUlVHUZPeCcBVqEgh\n"
+ "fP22C58clbWOxo/WTJ7oXYzWU3HdZieF2ZGTxF5r1k3SJx4pARYdDqRYiL99ZUEc\n"
+ "61xLFAtUWJ8TAltsgfIqa+bNFg0SUnePAjhy5tNKywc7fq7E90Yg0IfJJTn1OmcS\n"
+ "i2jS64wHEATFz504YXloGQKBgQCntZCI3YqivFExanTlWbsCTUNp4pcQz2EdVlrJ\n"
+ "VCRIgmrnwTmPyUSrOYA6xaOn7St7mm/ZAW+O8TeVpP8yxI4TFIFkVhcypNSfj86R\n"
+ "X3/sjAbjH4Rm1eST38EdnuTlyvHufG8zxmGXffguTdCw18YHCTkllGQMuhkyCv2O\n"
+ "/Vn2dQKBgQDI1dM1/jCLg6mh51np0ZB8BgTv8mEIOvgdlD21lTpWaCeAWFJZOqWY\n"
+ "Oo/dNh3YcbW0I6kTpriukDSxXJ095BhcBAG8jGNxw2293A/lKeyQyGKCYOX2Foh/\n"
+ "dBVLu4zKddTSxwy7p5iu5fTf4m0T/BJIea16hiyWfL01UxfiS+ybRg==\n"
+ "-----END RSA PRIVATE KEY-----";
+
+const char rsa3072[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIG5AIBAAKCAYEAy9VfKYjKmcggcZaopxgy0TxrnLTQWT+EkInakIz1J7FCRpCw\n"
+ "FaD/d0eIFcfUka5hRHMSPnP/XtZFoV0CpfOy8lJ/8YSPDv9v/E8Z+A5bATiRlkoD\n"
+ "iJENb5XhBNe3HGuF6bZUVQWPBpmNTna4t4JiMwJ9xXsnF9m0gWlqz7BSuLM5ivWg\n"
+ "BSOzcSCwJ3hV6nVygDqWebrULWJ87qGA26zFGBNbYZbwAxHEMAoN9Ys0mxa4WidV\n"
+ "estUt3fFD3Coc9BdeA7kDD844rDQ74t3joagrwqnsXyTx61g7RyrT+gAOfNvEFpx\n"
+ "N/1Y4FPgpwHBZLxiF2yFw/Zapq1DPTXQJY2tkHyTb5PUKxXEpOjZlOcxKvJq/x50\n"
+ "AZMdIxo/UZQ6OwGUTtYq1TpWzH8fa/NNKXu3ciGKvGO5HU+dYRZ2Hl8ZpVbA+PR/\n"
+ "wGdBd8fENFk6HEP6ztHAC0EHD34BRMXtheSvWJDoa7VuZ+RuwibdQmHOea2rRcHT\n"
+ "/ljEp6tJNHcp2yDtAgMBAAECggGATWgiU2uXRP8zEu/b7FjMM5l2ZHRmCv6MITe4\n"
+ "wNxG3WP7f0DDHfOeEHYhv+O7XfeTCKOKch0rBaDpoHXp44vAkTWzUMy+ZzuqE28W\n"
+ "tZT+CmCpKSHCZcJwD8gjQ+uHpktO94o+TGtn/WGiwAFl9IqXMDfp+2zhU7VhTyPx\n"
+ "ZB3ZzDqDx7mvo0QDiRqYyuRv/DHN4dReAKxqlzGnsBe1D7d0wcfYFB911jSRBI1M\n"
+ "78qFl7/xEouNcqx055ecRljKH/EoX5CRm6dGBcThem5EeRY+S0xQGg8escKB4Iiu\n"
+ "UIQ3drKpHxh6fwIg+rXh7DNp6MasVKjBgEAYEpRkPuJn7KIW1mxU7WTadFyYCzJp\n"
+ "ABtxUxnplxML4O9+7CYA0SUjOzhGzqN/Clymr7LNAiYSY9fYFc5+M0FhslE+JF7J\n"
+ "5DJC8fqc08yQ9gx5VAtXVor5ezw64Bahldh9y+tjkLv8DQephQhSuzWugzVIwJgp\n"
+ "xITOgINUdJ3DPhhekQemAo2z03MBAoHBAPojsnGhahNeu8AwhlUu+JhBiLx4kmxo\n"
+ "SrU5w183NhEf0jePZQ4GKxxcUkjRM49YIGMA1q646rhA+8Qsk1iKvenPXKiV+9hS\n"
+ "iYv5Mp4Ou1Xx7RDkdvsdE6i3NV7ZAWQiBXTEQlgufqAO465fR+5lICnhoIV5bU8y\n"
+ "oEzJXq3zu4VXuX7OCU1nCsNMg+5cIla0EUn932ruwIRuyHUsoWTSkxJCl033SeC9\n"
+ "srZIhh9oE1MLhsHhCBVd9/Z7SJ4EUgHTZQKBwQDQm/APC7puxCR/bLpYFyYOnLt8\n"
+ "oqZrI6PjWX7tdI35+4ZIHP2ap0bQUm/7Y22Ihy1DTb/xGU8nJ/3ff9Pkhnrg0nTO\n"
+ "IeOVlz5PDoywMjj0EuBWcES9b7PHMZ1V/hPjWFY/lyhIwUe2VsH8Ff1kyR3uPZHR\n"
+ "ijbdorPzAXx1eoSCmmcH1kO7hgV9tiKMPUcbKng+yNVjki0nJhp8fe2mwGmo83j9\n"
+ "ZiiNCXs5h4Blue0gsJMHhGNIEXaak5TZZLTIMukCgcEA0eY2jSeX7Z0nC4UslDqQ\n"
+ "HKORbCX5KMLzPdO04CdiVUhQjJLlh7khX/EQk04JaBXZR3qiq4c8X1UYb2vAUSJL\n"
+ "bvG0nTsOVF4eUbjRAtT12o7iEbTFKr8higgC3w5WHoJ19Z/i1EBfvUwBPodxwthU\n"
+ "/w/4NUjJsxWWchjgPDQ0fRY57/BQ2gTHgU6pvtDNd9guUdqZKhAiuH6F8915qTMS\n"
+ "etYqRSBnfBFy74c4FQ6ueJdJg1OkBtoNg2W8b+zMLAAJAoHBALY4sL6D0St2fCcu\n"
+ "s6vFNMIo2IErltEZxcwPXhdP68EEnCyb3k9cdTf9+sGN/Zz372rOHK8fG4wpm9LC\n"
+ "VzZU3jtKuytgYOtHvO7T18MFa8iQQJRg5zrOuyxxw2zdT0QU4uoTQOYkp164dCSe\n"
+ "lMSYBWQZNiniYMDDogrQLoZ0KhHni75FxM6maF+CXLVBxb4OIBE/315lzrlWyGYc\n"
+ "nh4+D028t+Apf5yLPq9nFJpHicI3W4eCdjL6xi6KYchv9pa2GQKBwBEfxlxetAKu\n"
+ "QnK4xSWJ0VdlI6QInZN3AjuLRonaS4OeiymZJ2nmmk8Gow3UZfQJcUJ/ucEHWbxY\n"
+ "eYzv2F8s9x5dHY46hhfNFi+fOb5nc2yLPGlFiD8C5Np6SjxkGPaXASRzO4HUWVB2\n"
+ "U43rrVtnDR+qIPFQd7V6MWEFF6TDgpEJptpqu741kkm/gT0qFdUXHiQ8tSCZMzDX\n"
+ "hc3roHoelzSkhPdUeKn0PVTz4LHmsw9FnpdaxzV21F98i0jNCWB28w==\n"
+ "-----END RSA PRIVATE KEY-----";
+
+const char rsa4096[] =
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIIJKAIBAAKCAgEA5pyOip8CLSY6a15Cnrvrr9d5Xs6JSaryH3YGsfkpqe9P+NtZ\n"
+ "qQXYwsUPNboEJh8RF3y9l6qkJNwW/WQXPfQ46zkCrBuTDpAkSaTsGvXnb7bEUyvu\n"
+ "ORVgLKIqv69KrwGbP+dRm02xUJiEJiWGxzREOUgTjf+dgtIvbDBSV7SjI1C3Z7Ww\n"
+ "z2Lx+P5qq34c2HM1F2DL9tSHAYtOoNgcefjMSbwCDABcNwcXofn7ZHXU0NKXDVkI\n"
+ "3UV4SWNnoABkqmLYKqlM7T5OyFO88C35M55wWj64/WiHJQRy1RSDHhP8Il1VsAMm\n"
+ "j2mBg+sDL98OhyHP9PwuOZPZ5fABjsKfm5otZmPummffCA3bD5LldVLV/fAIKix+\n"
+ "QPeArchSD55iafP4Bz1xG5+GXwCWQ1D9DKYVRhiDGHfaJsEJOuZETteHWfs1iC9t\n"
+ "Oc53eTcqne1TEKS0+KZcdKUpG9LigLXRIHOq61Gg2nKvIK0l9uvNyd1+7GE7CyR+\n"
+ "q3UXQqQYW0HPduaFIe8l+WIDugCxdWN9yK1l9/xWnIVhhd4BZlaqqO1SvfApyCj9\n"
+ "RIyPuCkyw2BncRjJ3g58tmdiVUF9GPl9ycUtjCG52aNJIzFa6/jYVWik9QXkp1hA\n"
+ "ipjWHL0ow1bPYcRQaKJBSby95mcVdHjS3wsJylsQZydQe4v+N6T8p54NXHUCAwEA\n"
+ "AQKCAgBqojnHH3+CIQsiWpOzknGI/bnBfP8+cS1EHu85nF0HlwEDsWnkHi/83+II\n"
+ "ldsVRYhBtAx29RCxepOm14FnxGYNXm895gI52azt4LTMQqihn4FodAfTnW67NMFP\n"
+ "oV6HTdbb1bqGdYZoHh39BZ0sv55MXmesYWYT99y1yiJJK93Dlq835Wu8eaQp3nq0\n"
+ "kbwE2kDSbo/hsqQ6so/JECUawVC1R5oqsn/xcfYbj9wOt+2QIdB2+5R9vIHCbZSd\n"
+ "B5GEt+/8ygwoJ4eGWjIjXR6+H6UUFay0gID9PPFcVf/LCLKtsTrOCKbr6X1Z4nG2\n"
+ "0Q2GrrvaLEGzngpDqJcPzC7BZKlYrj+mC6+yC5exT8fbd64HCbaG6XLnKW8HZnw6\n"
+ "iin8ZFXkejyJEtk2oqvxFfMPxkagYMqUSqfLTnLgf/4a0fNrNDSb4el4L/5AxKby\n"
+ "NSqE5eATa2cSAK/cBTI1iLfTk6vAneP16S9oGAO7IxzT8d7t2mwSb1xWg2+KdAzg\n"
+ "NnRLIp9XTz09d21LGzW1Kj6wlPe1j+a37sdLLQ1OH6g7NA7k1m3R+RF8tQU8wIMA\n"
+ "/DBp3tk38N71rbuTdlxYQ+ur+zxiqoQjN1rNPTc6FMQdekDsXg1uNmyQuAUAYnvo\n"
+ "BIM2E0w8YQ/07ghDf3KJbIVkPV8FZgjY9zkMIP000ODMYY4oAQKCAQEA/FDQ1nxM\n"
+ "4EZwLw1Vt33W3SV0iLXJsUUS34Rwy+xcAfPy3WBViaqDZE4ju2kZLQhoFA4L+RIw\n"
+ "cyIZF+ShOkDf1lVJgBq5yDFRjkC39IAFHQf3E7HyG+3iVo29k+jb0HTR19f2arI6\n"
+ "LCygQPviNbvJJ+Yr8EyZslCqW0NjhQWw/z2ydWrMwmVgg2wMO/64y2LYq2RujQKi\n"
+ "SzMnZsIGNBVm/eB7geKDv0JB4XOfnWBml7PYUx05Pd8QHxbEhLrXvSCv75nRRSVh\n"
+ "lCDa+ebwXCHWIzIJPeye+5YOYrbtQ35dNbhAerP2DwyqAjG/LarZT+uGXpy90WtP\n"
+ "zuX1nDojCwc9cQKCAQEA6fqbyW4apLZwj2y1X0Bf6YvLRCOyPJV7XqKhM3humgFN\n"
+ "Ry/VXTS3JqrlcquxB1LTaXeS8FoGENMAZX+e4Yw+4MFKqMoI3YkN9EUTa3iJF/0U\n"
+ "ZhvMikwDPgkddvKSZQqs/jTauqEdDBe5R2hITu95PoThrOg4a2ish1nML8Y+0QYR\n"
+ "R0bTgt96IIq/Hmhl84NwWaC+rx5U8GcFhKuVx3tN+wys1MK2eXwUGlVt1p1KtpWx\n"
+ "2F/5Z9AIbfU1ovRH7+ugql0Cupu+KtczOeO5Z6BCk9CFMz32qLDYw+dXBJ+6kUcy\n"
+ "UImgd+u/tULJ2K7GLkAIeK6Z7SBYH2pA1XxBg2QdRQKCAQAqvg4Cp5/mRkhu0BV7\n"
+ "NggWAmhRWGpIa2kdEDSDdxDHC+pSciVLYuVLMql+7/jh1hC7hP2mPdyTRG13zLU7\n"
+ "Rw4kIuKGnwBl12T3ciM3ehBjsJu8bGKVNKEpBG3fBo1mLMP3ipAl1vdf0Fd9aq4R\n"
+ "aDRVW/qJhJBs0plpSGstd59aPbtjhKoXLFFDMiSIbUgkvCP0NNk9bfrMPmgoUin2\n"
+ "3MFLtKF3iUXEOpcqeAnMAS6f+ElnGwY9YvI6MgMscPJnCYiEUExRKFn1W/N8bhC9\n"
+ "qsW5xJooMVNlTzA0rMRYsKldlk7l+mJufji2knLOa6jQjxd+I5NMTJ+CbxZCVt7k\n"
+ "2V8hAoIBAGc3refjUY+eB/PNggl+DZGqoMXzdVpymxT5a2GYXDpGHsArotVWPwGo\n"
+ "3EWE5jiT2j2piUHMhOaBHqin7wAS7V4bBwOE9Po9ztEWc+WyK9BQTeJpmwbbV4bT\n"
+ "YJMrmVdHqV8PE/rGvliqUorkvxlLXVIuLpwnaVRAvfOLsp7UtrthENg/r2kJiwe2\n"
+ "DW+toGQXdMWlOtln6RKQcAfB5fY1OAZq5geJyhO3n+qqCyVlCCOZz/XjCNQ6Gq3f\n"
+ "QYUcfGujp6HgHCcUM4UUoD2GbzD+qsAoecpMKHbsZQOvF10r1ZLnNJQA0rB0aILe\n"
+ "7spO95BJoTMT20WXQijBp85F3WTIEn0CggEBAPhtkW3ezzzwCwAwN8wsJ/qNmY0Z\n"
+ "QWmflKPmz1SPzIkArtysDEO4/K9zBrP1/DTpOCknzpoxDZjt7iPFyOw6hIyYL4oI\n"
+ "+kbEBrw7mrOBLZyp0WUia+KXGzM6TA1HQxtZZMd1MbyI7ZA1l8gaidENfl5OeFgC\n"
+ "m43X4wJEWD2EyGX7Uvc/DsEYSey1ESQtdp6bxmBiqg53BcfL2V7VmXUv1skDJY0i\n"
+ "qSeb46nVbqBha4bRBPTxeh7a4DAuwn/2J2p+8bzGiHmBLNB31RNJiVtkqzQYLqzi\n"
+ "Gh0FCwVmpa+sRcA2c0N7gwt6YEWo4QJgUjQ16GxxszS9Y+xjw2jdYUaOdBQ=\n"
+ "-----END RSA PRIVATE KEY-----";
+
+#define BUFSIZE 1024
+
+static CK_FUNCTION_LIST_3_0_PTR p11;
+static CK_SESSION_HANDLE session;
+
+static void generate_ec_keys(CK_OBJECT_HANDLE_PTR pubkey,
+ CK_OBJECT_HANDLE_PTR pvtkey) {
+ CK_BYTE ec_params[] = {0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x03, 0x01, 0x07};
+ CK_ULONG class_k = CKO_PRIVATE_KEY;
+ CK_ULONG class_c = CKO_PUBLIC_KEY;
+ CK_ULONG kt = CKK_EC;
+ CK_BBOOL exportable_capability = CK_TRUE;
+ CK_BBOOL sign_capability = CK_TRUE;
+ char *label = "eckey";
+
+ CK_ATTRIBUTE privateKeyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)},
+ {CKA_KEY_TYPE, &kt, sizeof(kt)},
+ {CKA_LABEL, label, strlen(label)},
+ {CKA_EXTRACTABLE, &exportable_capability,
+ sizeof(exportable_capability)},
+ {CKA_SIGN, &sign_capability,
+ sizeof(sign_capability)}};
+
+ CK_ATTRIBUTE publicKeyTemplate[] = {{CKA_CLASS, &class_c, sizeof(class_c)},
+ {CKA_EC_PARAMS, ec_params,
+ sizeof(ec_params)}};
+
+ CK_MECHANISM mech = {CKM_EC_KEY_PAIR_GEN, NULL, 0};
+
+ assert(p11->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 2,
+ privateKeyTemplate, 5, pubkey,
+ pvtkey) == CKR_OK);
+ fprintf(stdout, "Generated EC key. Handle 0x%06lx\n", *pvtkey);
+}
+
+static void generate_aes_key(CK_OBJECT_HANDLE_PTR key) {
+ CK_OBJECT_CLASS class = CKO_SECRET_KEY;
+ CK_KEY_TYPE type = CKK_AES;
+ CK_ULONG key_len = 32;
+ CK_BBOOL exportable_capability = CK_TRUE;
+ CK_BBOOL encrypt_capability = CK_TRUE;
+ CK_BBOOL decrypt_capability = CK_TRUE;
+ CK_ATTRIBUTE templ[] =
+ {{CKA_CLASS, &class, sizeof(class)},
+ {CKA_KEY_TYPE, &type, sizeof(type)},
+ {CKA_VALUE_LEN, &key_len, sizeof(CK_ULONG)},
+ {CKA_EXTRACTABLE, &exportable_capability, sizeof(exportable_capability)},
+ {CKA_ENCRYPT, &encrypt_capability, sizeof(encrypt_capability)},
+ {CKA_DECRYPT, &decrypt_capability, sizeof(decrypt_capability)}};
+ CK_MECHANISM mech = {CKM_AES_KEY_GEN, NULL, 0};
+
+ assert(p11->C_GenerateKey(session, &mech, templ, 6, key) == CKR_OK);
+ fprintf(stdout, "Generated AES key. Handle 0x%06lx\n", *key);
+}
+
+static void import_rsa_wrapkey(const char *key, int keylen,
+ CK_OBJECT_HANDLE_PTR keyid) {
+ CK_BYTE e[] = {0x01, 0x00, 0x01};
+ CK_BYTE *p, *q, *dp, *dq, *qinv;
+ int len = keylen / 16;
+ p = malloc(len);
+ q = malloc(len);
+ dp = malloc(len);
+ dq = malloc(len);
+ qinv = malloc(len);
+
+ BIO *bio = BIO_new_mem_buf((void *) key, strlen(key));
+ RSA *rsak = PEM_read_bio_RSAPrivateKey(bio, 0, 0, 0);
+
+ const BIGNUM *bp, *bq, *biqmp, *bdmp1, *bdmq1;
+ RSA_get0_factors(rsak, &bp, &bq);
+ RSA_get0_crt_params(rsak, &bdmp1, &bdmq1, &biqmp);
+ BN_bn2binpad(bp, p, len);
+ BN_bn2binpad(bq, q, len);
+ BN_bn2binpad(bdmp1, dp, len);
+ BN_bn2binpad(bdmq1, dq, len);
+ BN_bn2binpad(biqmp, qinv, len);
+
+ CK_ULONG class_k = CKO_PRIVATE_KEY;
+ CK_ULONG kt = CKK_RSA;
+ CK_BYTE id[] = {0, 0};
+ CK_BBOOL wrap_capability = CK_TRUE;
+ CK_BBOOL sign_capability = CK_TRUE;
+ char *label = "rsa_wrap";
+ CK_ATTRIBUTE keyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)},
+ {CKA_KEY_TYPE, &kt, sizeof(kt)},
+ {CKA_ID, &id, sizeof(id)},
+ {CKA_LABEL, label, strlen(label)},
+ {CKA_UNWRAP, &wrap_capability,
+ sizeof(wrap_capability)},
+ {CKA_SIGN, &sign_capability,
+ sizeof(sign_capability)},
+ {CKA_PUBLIC_EXPONENT, e, sizeof(e)},
+ {CKA_PRIME_1, p, len},
+ {CKA_PRIME_2, q, len},
+ {CKA_EXPONENT_1, dp, len},
+ {CKA_EXPONENT_2, dq, len},
+ {CKA_COEFFICIENT, qinv, len}};
+ assert(p11->C_CreateObject(session, keyTemplate, 12, keyid) == CKR_OK);
+ fprintf(stdout, "Imorted RSA wrap key. Size %d. Handle 0x%06lx\n", keylen,
+ *keyid);
+
+ free(p);
+ free(q);
+ free(dp);
+ free(dq);
+ free(qinv);
+}
+
+static CK_OBJECT_HANDLE import_rsa_pub_wrapkey(uint8_t *pubkey,
+ size_t pubkey_len) {
+
+ CK_OBJECT_HANDLE pubkey_handle;
+
+ CK_ULONG class_k = CKO_PUBLIC_KEY;
+ CK_BBOOL wrap_capability = CK_TRUE;
+ char *label = "pub_rsa_wrap";
+ CK_ULONG kt = CKK_RSA;
+
+ CK_ATTRIBUTE template[] = {{CKA_CLASS, &class_k, sizeof(class_k)},
+ {CKA_KEY_TYPE, &kt, sizeof(kt)},
+ {CKA_LABEL, label, strlen(label)},
+ {CKA_WRAP, &wrap_capability,
+ sizeof(wrap_capability)},
+ {CKA_VALUE, pubkey, pubkey_len}};
+ assert(p11->C_CreateObject(session, template, 5, &pubkey_handle) == CKR_OK);
+ return pubkey_handle;
+}
+
+static void generate_rsa_wrapkey(int keylen, CK_OBJECT_HANDLE_PTR keyid) {
+ CK_ULONG class_k = CKO_PRIVATE_KEY;
+ CK_ULONG class_c = CKO_PUBLIC_KEY;
+ CK_ULONG kt = CKK_RSA;
+ CK_BYTE id[] = {0, 0};
+ char *label = "rsa_wrap";
+ CK_BBOOL wrap_capability = CK_TRUE;
+ CK_BBOOL sign_capability = CK_TRUE;
+ CK_ULONG key_len = keylen;
+ CK_OBJECT_HANDLE pub_keyid;
+
+ CK_MECHANISM mech = {CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0};
+
+ CK_ATTRIBUTE privateKeyTemplate[] = {{CKA_CLASS, &class_k, sizeof(class_k)},
+ {CKA_KEY_TYPE, &kt, sizeof(kt)},
+ {CKA_ID, &id, sizeof(id)},
+ {CKA_LABEL, label, strlen(label)},
+ {CKA_UNWRAP, &wrap_capability,
+ sizeof(wrap_capability)},
+ {CKA_SIGN, &sign_capability,
+ sizeof(sign_capability)}};
+
+ CK_ATTRIBUTE publicKeyTemplate[] = {{CKA_CLASS, &class_c, sizeof(class_c)},
+ {CKA_MODULUS_BITS, &key_len,
+ sizeof(key_len)}};
+
+ assert(p11->C_GenerateKeyPair(session, &mech, publicKeyTemplate, 2,
+ privateKeyTemplate, 6, &pub_keyid,
+ keyid) == CKR_OK);
+ fprintf(stdout, "Generated RSA wrap key. Size %lu. Handle 0x%06lx\n", key_len,
+ *keyid);
+}
+
+static void get_pub_wrapkey(CK_OBJECT_HANDLE rsa_wrapkeyid, uint8_t *pubkey,
+ size_t *pubkey_len) {
+ CK_ATTRIBUTE template[] = {
+ {CKA_MODULUS, pubkey, *pubkey_len},
+ };
+ assert(p11->C_GetAttributeValue(session, rsa_wrapkeyid, template, 1) ==
+ CKR_OK);
+ *pubkey_len = template[0].ulValueLen;
+}
+
+static void get_wrapped_data(CK_OBJECT_HANDLE wrapping_keyid,
+ CK_OBJECT_HANDLE keyid, uint8_t *wrapped_obj,
+ size_t *wrapped_obj_len, bool only_key) {
+ CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, 0, NULL, 0};
+ CK_RSA_AES_KEY_WRAP_PARAMS params = {256, &oaep_params};
+ CK_MECHANISM mech = {0, ¶ms, sizeof(params)};
+
+ if (only_key) {
+ mech.mechanism = CKM_RSA_AES_KEY_WRAP;
+ } else {
+ mech.mechanism = CKM_YUBICO_RSA_WRAP;
+ }
+ assert(p11->C_WrapKey(session, &mech, wrapping_keyid, keyid, wrapped_obj,
+ wrapped_obj_len) == CKR_OK);
+}
+
+static CK_OBJECT_HANDLE import_wrapped_data(CK_OBJECT_HANDLE wrapping_keyid,
+ uint8_t *wrapped_obj,
+ size_t wrapped_obj_len,
+ bool only_key, CK_ULONG key_type) {
+
+ CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA256, CKG_MGF1_SHA256, 0, NULL, 0};
+ CK_RSA_AES_KEY_WRAP_PARAMS params = {256, &oaep_params};
+ CK_MECHANISM mech = {0, ¶ms, sizeof(params)};
+ if (only_key) {
+ mech.mechanism = CKM_RSA_AES_KEY_WRAP;
+ } else {
+ mech.mechanism = CKM_YUBICO_RSA_WRAP;
+ }
+
+ CK_OBJECT_HANDLE imported_keyhandle;
+ CK_ULONG kt = key_type;
+ CK_ULONG class_k = kt == CKK_EC ? CKO_PRIVATE_KEY : CKO_SECRET_KEY;
+
+ if (kt == CKK_EC) {
+ CK_BYTE ec_params[] = {0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x03, 0x01, 0x07};
+ CK_BBOOL sign_capability = CK_TRUE;
+ CK_ATTRIBUTE template[] = {{CKA_CLASS, &class_k, sizeof(class_k)},
+ {CKA_KEY_TYPE, &kt, sizeof(kt)},
+ {CKA_SIGN, &sign_capability,
+ sizeof(sign_capability)},
+ {CKA_EC_PARAMS, ec_params, sizeof(ec_params)}};
+
+ assert(p11->C_UnwrapKey(session, &mech, wrapping_keyid, wrapped_obj,
+ wrapped_obj_len, template, 4,
+ &imported_keyhandle) == CKR_OK);
+ } else {
+ CK_ULONG keylen = 32;
+ CK_BBOOL encrypt_capability = CK_TRUE;
+ CK_BBOOL decrypt_capability = CK_TRUE;
+ CK_ATTRIBUTE template[] = {{CKA_CLASS, &class_k, sizeof(class_k)},
+ {CKA_KEY_TYPE, &kt, sizeof(kt)},
+ {CKA_DECRYPT, &decrypt_capability,
+ sizeof(decrypt_capability)},
+ {CKA_ENCRYPT, &encrypt_capability,
+ sizeof(encrypt_capability)},
+ {CKA_VALUE_LEN, &keylen, sizeof(keylen)}};
+
+ assert(p11->C_UnwrapKey(session, &mech, wrapping_keyid, wrapped_obj,
+ wrapped_obj_len, template, 5,
+ &imported_keyhandle) == CKR_OK);
+ }
+ return imported_keyhandle;
+}
+
+static void find_rsa_wrapkey(CK_OBJECT_HANDLE keyid, size_t key_size) {
+ CK_BBOOL wrap_capability = CK_TRUE;
+ char *label = "rsa_wrap";
+ CK_ATTRIBUTE template[] = {{CKA_LABEL, label, strlen(label)},
+ {CKA_UNWRAP, &wrap_capability,
+ sizeof(wrap_capability)}};
+
+ CK_OBJECT_HANDLE objects[10] = {0};
+ CK_ULONG n_objects = 0;
+ assert(p11->C_FindObjectsInit(session, template, 2) == CKR_OK);
+ assert(p11->C_FindObjects(session, objects, 10, &n_objects) == CKR_OK);
+ assert(p11->C_FindObjectsFinal(session) == CKR_OK);
+ assert(n_objects == 1);
+ assert(objects[0] == keyid);
+
+ CK_ULONG mod_bits = 0;
+ CK_ATTRIBUTE value_template[] = {
+ {CKA_MODULUS_BITS, &mod_bits, sizeof(CK_ULONG)}};
+ assert(p11->C_GetAttributeValue(session, objects[0], value_template, 1) ==
+ CKR_OK);
+ assert(mod_bits == key_size);
+}
+
+static void find_pub_rsa_wrapkey(CK_OBJECT_HANDLE keyid, size_t key_size) {
+ CK_BBOOL wrap_capability = CK_TRUE;
+ char *label = "pub_rsa_wrap";
+ CK_ATTRIBUTE template[] = {{CKA_LABEL, label, strlen(label)},
+ {CKA_WRAP, &wrap_capability,
+ sizeof(wrap_capability)}};
+
+ CK_OBJECT_HANDLE objects[10] = {0};
+ CK_ULONG n_objects = 0;
+ assert(p11->C_FindObjectsInit(session, template, 2) == CKR_OK);
+ assert(p11->C_FindObjects(session, objects, 10, &n_objects) == CKR_OK);
+ assert(p11->C_FindObjectsFinal(session) == CKR_OK);
+ assert(n_objects == 1);
+ assert(objects[0] == keyid);
+
+ CK_ULONG mod_bits = 0;
+ CK_ULONG key_type = 0;
+ CK_ATTRIBUTE value_template[] = {{CKA_MODULUS_BITS, &mod_bits,
+ sizeof(CK_ULONG)},
+ {CKA_KEY_TYPE, &key_type, sizeof(CK_ULONG)}};
+ assert(p11->C_GetAttributeValue(session, objects[0], value_template, 2) ==
+ CKR_OK);
+ assert(mod_bits == key_size);
+ assert(key_type == CKK_RSA);
+}
+
+static CK_OBJECT_HANDLE get_public_key_handle(CK_OBJECT_HANDLE privkey) {
+ CK_OBJECT_HANDLE found_obj[10] = {0};
+ CK_ULONG n_found_obj = 0;
+ CK_ULONG class_pub = CKO_PUBLIC_KEY;
+ uint16_t ckaid = 0;
+
+ CK_ATTRIBUTE idTemplate[] = {
+ {CKA_ID, &ckaid, sizeof(ckaid)}
+ };
+ CK_ATTRIBUTE idClassTemplate[] = {
+ {CKA_ID, &ckaid, sizeof(ckaid)},
+ {CKA_CLASS, &class_pub, sizeof(class_pub)}
+ };
+
+ assert(p11->C_GetAttributeValue(session, privkey, idTemplate, 1) == CKR_OK);
+ assert(p11->C_FindObjectsInit(session, idClassTemplate, 2) == CKR_OK);
+ assert(p11->C_FindObjects(session, found_obj, 10, &n_found_obj) == CKR_OK);
+ assert(n_found_obj == 1);
+ assert(p11->C_FindObjectsFinal(session) == CKR_OK);
+ return found_obj[0];
+}
+
+static void do_ecdsa_sign(CK_OBJECT_HANDLE eckey) {
+ CK_MECHANISM mech = {CKM_ECDSA_SHA1, NULL, 0};
+ CK_BYTE sig[64] = {0};
+ CK_ULONG sig_len = sizeof(sig);
+
+ CK_BYTE data[16] = {0};
+ CK_ULONG data_len = sizeof(data);
+ assert((RAND_bytes(data, data_len) > 0));
+ assert(p11->C_SignInit(session, &mech, eckey) == CKR_OK);
+ assert(p11->C_Sign(session, data, sizeof(data), sig, &sig_len) == CKR_OK);
+ CK_OBJECT_HANDLE eckey_pub = get_public_key_handle(eckey);
+ assert(p11->C_VerifyInit(session, &mech, eckey_pub) == CKR_OK);
+ assert(p11->C_Verify(session, data, sizeof(data), sig, sig_len) == CKR_OK);
+}
+
+static void do_aesecb_encryption(CK_OBJECT_HANDLE aeskey) {
+ CK_MECHANISM mech = {CKM_AES_ECB, NULL, 0};
+ CK_BYTE enc[16] = {0};
+ CK_ULONG enc_len = sizeof(enc);
+ CK_BYTE dec[16] = {0};
+ CK_ULONG dec_len = sizeof(dec);
+
+ CK_BYTE data[16] = {0};
+ CK_ULONG data_len = sizeof(data);
+ assert((RAND_bytes(data, data_len) > 0));
+
+ assert(p11->C_EncryptInit(session, &mech, aeskey) == CKR_OK);
+ assert(p11->C_Encrypt(session, data, sizeof(data), enc, &enc_len) == CKR_OK);
+ assert(p11->C_DecryptInit(session, &mech, aeskey) == CKR_OK);
+ assert(p11->C_Decrypt(session, enc, enc_len, dec, &dec_len) == CKR_OK);
+ assert(dec_len == 16);
+ assert(memcmp(data, dec, dec_len) == 0);
+}
+
+static void test_asym_wrapkey(CK_OBJECT_HANDLE_PTR eckey,
+ CK_OBJECT_HANDLE_PTR aeskey,
+ CK_OBJECT_HANDLE wrapkey, size_t keysize) {
+ CK_OBJECT_HANDLE pub_wrapkey, imported_eckey, imported_aeskey;
+
+ find_rsa_wrapkey(wrapkey, keysize);
+
+ // Get public key of RSA wrap key: C_GetAttributeValue(CKA_MODULUS)
+ uint8_t pubkey[2048] = {0};
+ size_t pubkey_len = sizeof(pubkey);
+ get_pub_wrapkey(wrapkey, pubkey, &pubkey_len);
+ fprintf(stdout, "Got public key for RSA wrap key 0x%06lx. OK!\n", wrapkey);
+
+ // Import the public key of the RSA wrap key as a public wrap key
+ // C_CreateObject(RSA Public Key)
+ pub_wrapkey = import_rsa_pub_wrapkey(pubkey, pubkey_len);
+ fprintf(stdout,
+ "Imported RSA public wrap key of size %zu. ID 0x%06lx OK!\n",
+ keysize, pub_wrapkey);
+ find_pub_rsa_wrapkey(pub_wrapkey, keysize);
+
+ // Wrap EC key material then import it again as an RSA wrapped key
+ // C_WrapKey, C_UnwrapKey
+ uint8_t wrapped_key[2048] = {0};
+ size_t wrapped_key_len = sizeof(wrapped_key);
+ get_wrapped_data(pub_wrapkey, *eckey, wrapped_key, &wrapped_key_len, true);
+ fprintf(stdout, "Got wrapped EC key material. %zu bytes. OK!\n", wrapped_key_len);
+ imported_eckey =
+ import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, true, CKK_EC);
+ fprintf(stdout, "Imported unwrapped EC key material. 0x%06lx. OK!\n",
+ imported_eckey);
+ do_ecdsa_sign(imported_eckey);
+ fprintf(stdout, "Signed using imported EC key. OK!\n");
+
+ // Wrap EC key object then import it again as an RSA wrapped object
+ // C_WrapKey, C_UnwrapKey
+ memset(wrapped_key, 0, sizeof(wrapped_key));
+ wrapped_key_len = sizeof(wrapped_key);
+ get_wrapped_data(pub_wrapkey, *eckey, wrapped_key, &wrapped_key_len, false);
+ fprintf(stdout, "Got wrapped EC key object. %zu bytes. OK!\n", wrapped_key_len);
+ destroy_object(p11, session, *eckey);
+ fprintf(stdout, "Removed EC key object. OK!\n");
+ *eckey =
+ import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, false, CKK_EC);
+ fprintf(stdout, "Imported unwrapped EC key object. OK!\n");
+ do_ecdsa_sign(*eckey);
+ fprintf(stdout, "Signed using imported EC object. OK!\n");
+
+ // Wrap AES key material then import it again as an RSA wrapped key
+ // C_WrapKey, C_UnwrapKey
+ memset(wrapped_key, 0, sizeof(wrapped_key));
+ wrapped_key_len = sizeof(wrapped_key);
+ get_wrapped_data(pub_wrapkey, *aeskey, wrapped_key, &wrapped_key_len, true);
+ fprintf(stdout, "Got wrapped AES key material. %zu bytes. OK!\n", wrapped_key_len);
+ imported_aeskey =
+ import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, true, CKK_AES);
+ fprintf(stdout, "Imported unwrapped AES key material. 0x%06lx. OK!\n",
+ imported_aeskey);
+ do_aesecb_encryption(imported_aeskey);
+ fprintf(stdout, "Encrypted using imported AES key. OK!\n");
+
+ // Wrap AES key object then import it again as an RSA wrapped object
+ // C_WrapKey, C_UnwrapKey
+ memset(wrapped_key, 0, sizeof(wrapped_key));
+ wrapped_key_len = sizeof(wrapped_key);
+ get_wrapped_data(pub_wrapkey, *aeskey, wrapped_key, &wrapped_key_len, false);
+ fprintf(stdout, "Got wrapped AES key object. %zu bytes. OK!\n", wrapped_key_len);
+ destroy_object(p11, session, *aeskey);
+ fprintf(stdout, "Removed AES key object. OK!\n");
+ *aeskey =
+ import_wrapped_data(wrapkey, wrapped_key, wrapped_key_len, false, CKK_AES);
+ fprintf(stdout, "Imported unwrapped AES key object. OK!\n");
+ do_aesecb_encryption(*aeskey);
+ fprintf(stdout, "Signed using imported AES object. OK!\n");
+
+ // Delete test keys
+ destroy_object(p11, session, imported_eckey);
+ destroy_object(p11, session, imported_aeskey);
+ destroy_object(p11, session, pub_wrapkey);
+
+}
+
+static bool is_asymwrap_supported(void) {
+ CK_SESSION_INFO info;
+ CK_RV r;
+
+ if ((r = p11->C_GetSessionInfo(session, &info)) != CKR_OK) {
+ fprintf(stderr, "C_GetSessionInfo (r = %lu)\n", r);
+ return CKR_FUNCTION_FAILED;
+ }
+
+ CK_MECHANISM_TYPE m[128];
+ CK_ULONG n = sizeof(m) / sizeof(m[0]);
+ if ((r = p11->C_GetMechanismList(info.slotID, m, &n)) != CKR_OK) {
+ fprintf(stderr, "C_GetMechanismList (r = %lu)\n", r);
+ return CKR_FUNCTION_FAILED;
+ }
+
+ for (CK_ULONG i = 0; i < n; i++) {
+ if (m[i] == CKM_YUBICO_RSA_WRAP) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int main(int argc, char **argv) {
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: /path/to/yubihsm_pkcs11/module\n");
+ exit(EXIT_FAILURE);
+ }
+
+ void *handle = open_module(argv[1]);
+ p11 = get_function_list(handle);
+ session = open_session(p11);
+ print_session_state(p11, session);
+
+ if (!is_asymwrap_supported()) {
+ goto clean;
+ }
+
+ const char *keys[] = {rsa2048, rsa3072, rsa4096};
+ size_t keysizes[] = {2048, 3072, 4096};
+
+// Generate EC key to wrap
+ CK_OBJECT_HANDLE ec_pubkey, ec_privkey, aes_key;
+ generate_ec_keys(&ec_pubkey, &ec_privkey);
+ generate_aes_key(&aes_key);
+
+ for (int i = 0; i < 3; i++) {
+ CK_OBJECT_HANDLE wrapkey;
+
+ generate_rsa_wrapkey(keysizes[i], &wrapkey);
+ assert(wrapkey != 0);
+ test_asym_wrapkey(&ec_privkey, &aes_key, wrapkey, keysizes[i]);
+ destroy_object(p11, session, wrapkey);
+
+ wrapkey = 0;
+ import_rsa_wrapkey(keys[i], keysizes[i], &wrapkey);
+ assert(wrapkey != 0);
+ test_asym_wrapkey(&ec_privkey, &aes_key, wrapkey, keysizes[i]);
+ destroy_object(p11, session, wrapkey);
+ }
+ destroy_object(p11, session, ec_privkey);
+ printf("OK!\n");
+
+clean:
+ close_session(p11, session);
+ close_module(handle);
+ return (EXIT_SUCCESS);
+}
diff --git a/pkcs11/util_pkcs11.c b/pkcs11/util_pkcs11.c
index 613224d88..da6c609db 100644
--- a/pkcs11/util_pkcs11.c
+++ b/pkcs11/util_pkcs11.c
@@ -168,13 +168,21 @@ static CK_ULONG encode_length(CK_BYTE_PTR buffer, CK_ULONG length) {
}
}
-static void add_mech(CK_MECHANISM_TYPE *buf, CK_ULONG_PTR count,
- CK_MECHANISM_TYPE item) {
- for (CK_ULONG i = 0; i < *count; i++) {
+static bool find_mech(CK_MECHANISM_TYPE_PTR buf, CK_ULONG count,
+ CK_MECHANISM_TYPE item) {
+ for (CK_ULONG i = 0; i < count; i++) {
if (buf[i] == item) {
- return;
+ return true;
}
}
+ return false;
+}
+
+static void add_mech(CK_MECHANISM_TYPE_PTR buf, CK_ULONG_PTR count,
+ CK_MECHANISM_TYPE item) {
+ if (find_mech(buf, *count, item)) {
+ return;
+ }
buf[*count] = item;
*count = *count + 1;
}
@@ -204,9 +212,8 @@ CK_RV get_mechanism_list(yubihsm_pkcs11_slot *slot,
}
}
- CK_MECHANISM_TYPE buffer[128] = {
- 0}; // NOTE: this is a bit hardcoded, but much more
- // than what we might add below.
+ // NOTE: this is a bit hardcoded, but much more than what we might add below.
+ CK_MECHANISM_TYPE buffer[128] = {0};
CK_ULONG items = 0;
for (size_t i = 0; i < slot->n_algorithms; i++) {
@@ -322,6 +329,18 @@ CK_RV get_mechanism_list(yubihsm_pkcs11_slot *slot,
case YH_ALGO_RSA_OAEP_SHA384:
case YH_ALGO_RSA_OAEP_SHA512:
add_mech(buffer, &items, CKM_RSA_PKCS_OAEP);
+ if(find_mech(buffer, items, CKM_AES_KEY_WRAP_KWP)) {
+ add_mech(buffer, &items, CKM_YUBICO_RSA_WRAP);
+ add_mech(buffer, &items, CKM_RSA_AES_KEY_WRAP);
+ }
+ break;
+
+ case YH_ALGO_AES_KWP:
+ add_mech(buffer, &items, CKM_AES_KEY_WRAP_KWP);
+ if(find_mech(buffer, items, CKM_RSA_PKCS_OAEP)) {
+ add_mech(buffer, &items, CKM_YUBICO_RSA_WRAP);
+ add_mech(buffer, &items, CKM_RSA_AES_KEY_WRAP);
+ }
break;
case YH_ALGO_AES128_CCM_WRAP:
@@ -529,6 +548,14 @@ CK_RV get_mechanism_info(yubihsm_pkcs11_slot *slot, CK_MECHANISM_TYPE type,
pInfo->flags = CKF_HW | CKF_DECRYPT | CKF_ENCRYPT;
break;
+ case CKM_YUBICO_RSA_WRAP:
+ case CKM_RSA_AES_KEY_WRAP:
+ find_minmax_rsa_key_length_in_bits(slot->algorithms, slot->n_algorithms,
+ &pInfo->ulMinKeySize,
+ &pInfo->ulMaxKeySize);
+ pInfo->flags = CKF_HW | CKF_WRAP | CKF_UNWRAP;
+ break;
+
case CKM_RSA_PKCS_KEY_PAIR_GEN:
find_minmax_rsa_key_length_in_bits(slot->algorithms, slot->n_algorithms,
&pInfo->ulMinKeySize,
@@ -628,6 +655,12 @@ CK_RV get_mechanism_info(yubihsm_pkcs11_slot *slot, CK_MECHANISM_TYPE type,
pInfo->flags = CKF_DIGEST;
break;
+ case CKM_AES_KEY_WRAP_KWP:
+ pInfo->ulMaxKeySize = 256;
+ pInfo->ulMinKeySize = 128;
+ pInfo->flags = CKF_HW;
+ break;
+
case CKM_YUBICO_AES_CCM_WRAP:
pInfo->ulMaxKeySize = 256;
pInfo->ulMinKeySize = 128;
@@ -839,9 +872,22 @@ yubihsm_pkcs11_object_desc *get_object_desc(yubihsm_pkcs11_slot *slot,
return _get_object_desc(slot, id, type, sequence);
}
-static bool check_domains(uint16_t subset_domains, uint16_t domains) {
+static bool check_domains(uint16_t subset_domains, yubihsm_pkcs11_slot *slot) {
+ uint16_t authkey_domains = slot->authkey_domains;
+ if (authkey_domains == 0) {
+ yh_object_descriptor authkey = {0};
+ if (yh_util_get_object_info(slot->device_session,
+ slot->device_session->authkey_id,
+ YH_AUTHENTICATION_KEY,
+ &authkey) != YHR_SUCCESS) {
+ DBG_ERR("Unable to check authentication key domains");
+ return false;
+ }
+ authkey_domains = authkey.domains;
+ }
+
for (uint16_t i = 0; i < YH_MAX_DOMAINS; i++) {
- if ((subset_domains & (1 << i)) && !(domains & (1 << i))) {
+ if ((subset_domains & (1 << i)) && !(authkey_domains & (1 << i))) {
return false;
}
}
@@ -853,7 +899,7 @@ CK_RV write_meta_object(yubihsm_pkcs11_slot *slot,
yh_capabilities *target_capabilities,
uint16_t target_domains, bool replace) {
- if (!check_domains(target_domains, slot->authkey_domains)) {
+ if (!check_domains(target_domains, slot)) {
DBG_ERR(
"Current user's domain access does not match target_object domains.");
return CKR_FUNCTION_REJECTED;
@@ -1082,9 +1128,8 @@ static void get_capability_attribute(yh_object_descriptor *object,
static CK_RV add_mech_type(CK_BYTE_PTR value, CK_ULONG max, CK_ULONG_PTR length,
CK_MECHANISM_TYPE mech) {
- for (CK_ULONG i = 0; i < *length; i += sizeof(CK_MECHANISM_TYPE)) {
- if (*(CK_MECHANISM_TYPE_PTR)(value + i) == mech)
- return CKR_OK;
+ if(find_mech((CK_MECHANISM_TYPE_PTR)value, *length / sizeof(CK_MECHANISM_TYPE), mech)) {
+ return CKR_OK;
}
if (*length + sizeof(CK_MECHANISM_TYPE) > max)
return CKR_BUFFER_TOO_SMALL;
@@ -1371,7 +1416,8 @@ static CK_RV get_attribute_secret_key(CK_ATTRIBUTE_TYPE type,
break;
case CKA_VALUE_LEN:
- if (object->type == YH_WRAP_KEY || object->type == YH_SYMMETRIC_KEY) {
+ if (object->type == YH_WRAP_KEY || object->type == YH_SYMMETRIC_KEY ||
+ object->type == YH_HMAC_KEY) {
size_t key_length = 0;
yh_rc yrc = yh_get_key_bitlength(object->algorithm, &key_length);
if (yrc != YHR_SUCCESS) {
@@ -1542,6 +1588,8 @@ static CK_RV get_attribute_private_key(CK_ATTRIBUTE_TYPE type,
}
*length = sizeof(CK_KEY_TYPE);
+ } else if (object->type == YH_WRAP_KEY && yh_is_rsa(object->algorithm)) {
+ *((CK_KEY_TYPE *) value) = CKK_RSA;
} else {
return CKR_FUNCTION_FAILED;
}
@@ -1622,11 +1670,18 @@ static CK_RV get_attribute_private_key(CK_ATTRIBUTE_TYPE type,
}
break;
+ case CKA_WRAP: // applicable for RSA wrap keys
+ get_capability_attribute(object, "export-wrapped", true, value,
+ length, NULL);
+ break;
+ case CKA_UNWRAP: // applicable for RSA wrap keys
+ get_capability_attribute(object, "import-wrapped", true, value,
+ length, NULL);
+ break;
+
case CKA_SIGN_RECOVER:
case CKA_VERIFY:
case CKA_VERIFY_RECOVER:
- case CKA_WRAP:
- case CKA_UNWRAP:
case CKA_WRAP_WITH_TRUSTED:
case CKA_ALWAYS_AUTHENTICATE:
*((CK_BBOOL *) value) = CK_FALSE;
@@ -1711,7 +1766,7 @@ static CK_RV get_attribute_private_key(CK_ATTRIBUTE_TYPE type,
p += resplen;
*length = p - (uint8_t *) value;
} else if (yh_is_ed(object->algorithm)) {
- uint8_t resp[2048];
+ uint8_t resp[2048] = {0};
size_t resplen = sizeof(resp);
yh_rc yrc =
@@ -1750,8 +1805,9 @@ static CK_RV get_attribute_private_key(CK_ATTRIBUTE_TYPE type,
uint8_t resp[2048] = {0};
size_t resp_len = sizeof(resp);
- yh_rc yrc = yh_util_get_public_key(session->slot->device_session,
- object->id, resp, &resp_len, NULL);
+ yh_rc yrc =
+ yh_util_get_public_key_ex(session->slot->device_session, object->type,
+ object->id, resp, &resp_len, NULL);
if (yrc != YHR_SUCCESS) {
return yrc_to_rv(yrc);
}
@@ -1787,7 +1843,7 @@ static CK_RV get_attribute_private_key(CK_ATTRIBUTE_TYPE type,
return CKR_OK;
}
-static CK_RV load_public_key(yh_session *session, uint16_t id, EVP_PKEY **key) {
+static CK_RV load_public_key(yh_session *session, uint16_t id, uint8_t type, EVP_PKEY **key) {
uint8_t data[1024] = {0};
size_t data_len = sizeof(data) - 1;
@@ -1800,7 +1856,8 @@ static CK_RV load_public_key(yh_session *session, uint16_t id, EVP_PKEY **key) {
EC_POINT *ec_point = NULL;
yh_algorithm algo;
- yh_rc yrc = yh_util_get_public_key(session, id, data + 1, &data_len, &algo);
+ yh_rc yrc =
+ yh_util_get_public_key_ex(session, type, id, data + 1, &data_len, &algo);
if (yrc != YHR_SUCCESS) {
return yrc_to_rv(yrc);
}
@@ -2030,6 +2087,9 @@ static CK_RV get_attribute_public_key(CK_ATTRIBUTE_TYPE type,
*((CK_KEY_TYPE *) value) = CKK_VENDOR_DEFINED; // TODO: argh
}
*length = sizeof(CK_KEY_TYPE);
+ } else if (object->type == YH_PUBLIC_WRAP_KEY && yh_is_rsa(object->algorithm)) {
+ *((CK_KEY_TYPE *) value) = CKK_RSA;
+ *length = sizeof(CK_KEY_TYPE);
} else {
return CKR_FUNCTION_FAILED;
}
@@ -2129,7 +2189,7 @@ static CK_RV get_attribute_public_key(CK_ATTRIBUTE_TYPE type,
p += resplen;
*length = p - (uint8_t *) value;
} else if (yh_is_ed(object->algorithm)) {
- uint8_t resp[2048];
+ uint8_t resp[2048] = {0};
size_t resplen = sizeof(resp);
yh_rc yrc =
@@ -2168,8 +2228,9 @@ static CK_RV get_attribute_public_key(CK_ATTRIBUTE_TYPE type,
uint8_t resp[2048] = {0};
size_t resp_len = sizeof(resp);
- yh_rc yrc = yh_util_get_public_key(session->slot->device_session,
- object->id, resp, &resp_len, NULL);
+ yh_rc yrc =
+ yh_util_get_public_key_ex(session->slot->device_session, object->type,
+ object->id, resp, &resp_len, NULL);
if (yrc != YHR_SUCCESS) {
return yrc_to_rv(yrc);
}
@@ -2197,7 +2258,7 @@ static CK_RV get_attribute_public_key(CK_ATTRIBUTE_TYPE type,
EVP_PKEY *pkey = NULL;
CK_RV rv =
- load_public_key(session->slot->device_session, object->id, &pkey);
+ load_public_key(session->slot->device_session, object->id, object->type, &pkey);
if (rv != CKR_OK) {
EVP_PKEY_free(pkey);
return rv;
@@ -2229,6 +2290,14 @@ static CK_RV get_attribute(CK_ATTRIBUTE_TYPE type, yh_object_descriptor *object,
session);
case YH_WRAP_KEY:
+ if(yh_is_rsa(object->algorithm)) {
+ return get_attribute_private_key(type, object, meta_object, value, length,
+ session);
+ } else {
+ return get_attribute_secret_key(type, object, meta_object, value, length);
+ }
+ break;
+
case YH_HMAC_KEY:
case YH_SYMMETRIC_KEY:
return get_attribute_secret_key(type, object, meta_object, value, length);
@@ -2237,6 +2306,7 @@ static CK_RV get_attribute(CK_ATTRIBUTE_TYPE type, yh_object_descriptor *object,
return get_attribute_private_key(type, object, meta_object, value, length,
session);
case YH_PUBLIC_KEY:
+ case YH_PUBLIC_WRAP_KEY:
return get_attribute_public_key(type, object, meta_object, value, length,
session);
@@ -2339,12 +2409,9 @@ CK_RV check_sign_mechanism(yubihsm_pkcs11_slot *slot,
return rv;
}
- for (CK_ULONG i = 0; i < count; i++) {
- if (pMechanism->mechanism == mechanisms[i]) {
- return CKR_OK;
- }
+ if (find_mech(mechanisms, count, pMechanism->mechanism)) {
+ return CKR_OK;
}
-
return CKR_MECHANISM_INVALID;
}
@@ -2367,12 +2434,9 @@ CK_RV check_decrypt_mechanism(yubihsm_pkcs11_slot *slot,
return rv;
}
- for (CK_ULONG i = 0; i < count; i++) {
- if (pMechanism->mechanism == mechanisms[i]) {
- return CKR_OK;
- }
+ if (find_mech(mechanisms, count, pMechanism->mechanism)) {
+ return CKR_OK;
}
-
return CKR_MECHANISM_INVALID;
}
@@ -2397,7 +2461,9 @@ CK_RV check_wrap_mechanism(yubihsm_pkcs11_slot *slot,
CK_MECHANISM_TYPE mechanisms[128] = {0};
CK_ULONG count = 128;
- if (pMechanism->mechanism != CKM_YUBICO_AES_CCM_WRAP) {
+ if (pMechanism->mechanism != CKM_YUBICO_AES_CCM_WRAP &&
+ pMechanism->mechanism != CKM_YUBICO_RSA_WRAP &&
+ pMechanism->mechanism != CKM_RSA_AES_KEY_WRAP) {
return CKR_MECHANISM_INVALID;
}
@@ -2406,12 +2472,9 @@ CK_RV check_wrap_mechanism(yubihsm_pkcs11_slot *slot,
return rv;
}
- for (CK_ULONG i = 0; i < count; i++) {
- if (pMechanism->mechanism == mechanisms[i]) {
- return CKR_OK;
- }
+ if (find_mech(mechanisms, count, pMechanism->mechanism)) {
+ return CKR_OK;
}
-
return CKR_MECHANISM_INVALID;
}
@@ -3368,7 +3431,7 @@ CK_RV perform_verify(yh_session *session, yubihsm_pkcs11_op_info *op_info,
unsigned int md_len = sizeof(md_data);
EVP_PKEY_CTX *ctx = NULL;
- rv = load_public_key(session, op_info->op.verify.key_id, &key);
+ rv = load_public_key(session, op_info->op.verify.key_id, YH_ASYMMETRIC_KEY, &key);
if (rv != CKR_OK) {
goto pv_failure;
}
@@ -3626,7 +3689,7 @@ CK_RV perform_rsa_encrypt(yh_session *session, yubihsm_pkcs11_op_info *op_info,
EVP_PKEY *public_key = NULL;
EVP_PKEY_CTX *ctx = NULL;
- CK_RV rv = load_public_key(session, op_info->op.encrypt.key_id, &public_key);
+ CK_RV rv = load_public_key(session, op_info->op.encrypt.key_id, YH_ASYMMETRIC_KEY, &public_key);
if (rv != CKR_OK) {
DBG_ERR("Failed to load public key");
goto rsa_enc_cleanup;
@@ -4213,6 +4276,14 @@ CK_RV parse_rsa_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
}
break;
+ case CKA_ENCRYPT:
+ if ((rv = set_template_attribute(&template->encrypt,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_ENCRYPT inconsistent in template");
+ return rv;
+ }
+ break;
+
case CKA_TOKEN:
case CKA_PRIVATE:
case CKA_SENSITIVE:
@@ -4225,28 +4296,40 @@ CK_RV parse_rsa_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
break;
case CKA_WRAP:
+ if ((rv = set_template_attribute(&template->wrap,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_WRAP inconsistent in template");
+ return rv;
+ }
+ break;
+
+ case CKA_UNWRAP:
+ if ((rv = set_template_attribute(&template->unwrap,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_UNWRAP inconsistent in template");
+ return rv;
+ }
+ break;
+
case CKA_DERIVE:
- case CKA_ENCRYPT:
+ if ((rv = set_template_attribute(&template->derive,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_DERIVE inconsistent in template");
+ return rv;
+ }
+ break;
+
case CKA_VERIFY:
case CKA_VERIFY_RECOVER:
case CKA_MODIFIABLE:
case CKA_COPYABLE:
case CKA_ALWAYS_AUTHENTICATE:
+ case CKA_SIGN_RECOVER:
if ((rv = check_bool_attribute(pTemplate[i].pValue, false)) != CKR_OK) {
return rv;
}
break;
- case CKA_SIGN_RECOVER:
- case CKA_UNWRAP: {
- CK_BBOOL b_val = *(CK_BBOOL *) pTemplate[i].pValue;
- if (b_val != CK_FALSE) {
- DBG_ERR("Boolean false check failed for attribute 0x%lx. This will "
- "be ignored",
- pTemplate[i].type);
- }
- } break;
-
case CKA_MODULUS:
case CKA_PRIVATE_EXPONENT:
case CKA_EXPONENT_1:
@@ -4905,7 +4988,31 @@ CK_RV parse_rsa_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate,
break;
case CKA_WRAP:
+ if ((rv = check_bool_attribute(pPrivateKeyTemplate[i].pValue, false)) !=
+ CKR_OK) {
+ DBG_ERR("Boolean false check failed for attribute CKA_WRAP");
+ return rv;
+ }
+ break;
+
+ case CKA_UNWRAP: // pkcs11-tool sets this on private keys
+ if ((rv = set_template_attribute(&template->unwrap,
+ pPrivateKeyTemplate[i].pValue)) !=
+ CKR_OK) {
+ DBG_ERR("CKA_UNWRAP inconsistent in template");
+ return rv;
+ }
+ break;
+
case CKA_DERIVE:
+ if ((rv = set_template_attribute(&template->derive,
+ pPrivateKeyTemplate[i].pValue)) !=
+ CKR_OK) {
+ DBG_ERR("CKA_DERIVE inconsistent in template");
+ return rv;
+ }
+ break;
+
case CKA_ENCRYPT:
case CKA_SIGN_RECOVER:
case CKA_VERIFY:
@@ -4920,7 +5027,6 @@ CK_RV parse_rsa_generate_template(CK_ATTRIBUTE_PTR pPublicKeyTemplate,
}
break;
- case CKA_UNWRAP: // pkcs11-tool sets this on private keys
case CKA_SUBJECT:
break;
@@ -5485,6 +5591,223 @@ CK_RV parse_wrap_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
}
}
+CK_RV set_object_type(uint8_t *type, uint8_t expected_type) {
+ if (*type == 0) {
+ *type = expected_type;
+ return CKR_OK;
+ }
+ if (*type != expected_type) {
+ DBG_ERR("Mismatch in attribute values");
+ return CKR_TEMPLATE_INCONSISTENT;
+ }
+ return CKR_OK;
+}
+
+CK_RV
+parse_rsa_wrappedkey_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
+ yubihsm_pkcs11_object_template *template,
+ pkcs11_meta_object *pkcs11meta, CK_BYTE* type) {
+ CK_RV rv;
+ CK_ULONG ckk_type = 0;
+ uint8_t *ecparams = NULL;
+ uint16_t ecparams_len = 0;
+ for (CK_ULONG i = 0; i < ulCount; i++) {
+ switch (pTemplate[i].type) {
+ case CKA_CLASS: {
+ uint32_t value = *((CK_ULONG_PTR) (pTemplate[i].pValue));
+ switch (value) {
+ case CKO_SECRET_KEY:
+ rv = set_object_type(type, YH_SYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ break;
+ case CKO_PRIVATE_KEY:
+ rv = set_object_type(type, YH_ASYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ break;
+ default:
+ DBG_ERR("Unsupported wrapped key class");
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+ } break;
+ case CKA_KEY_TYPE: {
+ ckk_type = *((CK_ULONG_PTR) (pTemplate[i].pValue));
+ switch (ckk_type) {
+ case CKK_RSA:
+ case CKK_EC:
+ case CKK_EC_EDWARDS:
+ rv = set_object_type(type, YH_ASYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ break;
+ case CKK_AES:
+ rv = set_object_type(type, YH_SYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ break;
+ default:
+ DBG_ERR("Unsupported wrapped key type 0x%lx", ckk_type);
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+ } break;
+ case CKA_ID:
+ rv =
+ parse_meta_id_template(template, pkcs11meta, true,
+ pTemplate[i].pValue, pTemplate[i].ulValueLen);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ break;
+
+ case CKA_LABEL:
+ rv = parse_meta_label_template(template, pkcs11meta, true,
+ pTemplate[i].pValue,
+ pTemplate[i].ulValueLen);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ break;
+
+ case CKA_MODULUS_BITS:
+ rv = set_object_type(type, YH_ASYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ switch (*((CK_ULONG_PTR) pTemplate[i].pValue)) {
+ case 2048:
+ template->algorithm = YH_ALGO_RSA_2048;
+ break;
+
+ case 3072:
+ template->algorithm = YH_ALGO_RSA_3072;
+ break;
+
+ case 4096:
+ template->algorithm = YH_ALGO_RSA_4096;
+ break;
+
+ default:
+ DBG_ERR("CKA_MODULUS_BITS wrong length in PublicKeyTemplate (%lu)",
+ *((CK_ULONG_PTR) pTemplate[i].pValue));
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+ break;
+
+ case CKA_EC_PARAMS:
+ rv = set_object_type(type, YH_ASYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ if (ecparams == NULL) {
+ ecparams = (CK_BYTE_PTR) pTemplate[i].pValue;
+ ecparams_len = pTemplate[i].ulValueLen;
+ } else {
+ DBG_ERR("CKA_PUBLIC_EXPONENT inconsistent in PublicKeyTemplate");
+ return CKR_TEMPLATE_INCONSISTENT;
+ }
+ break;
+
+ case CKA_VALUE_LEN:
+ rv = set_object_type(type, YH_SYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ CK_ULONG keylen = *((CK_ULONG_PTR) pTemplate[i].pValue);
+ switch (keylen) {
+ case 16:
+ template->algorithm = YH_ALGO_AES128;
+ break;
+ case 24:
+ template->algorithm = YH_ALGO_AES192;
+ break;
+ case 32:
+ template->algorithm = YH_ALGO_AES256;
+ break;
+ default:
+ DBG_ERR("Invalid key length %lu", keylen);
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+ break;
+
+ case CKA_DECRYPT:
+ if ((rv = set_template_attribute(&template->encrypt,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_DECRYPT inconsistent in pTemplate");
+ return rv;
+ }
+ break;
+ case CKA_ENCRYPT:
+ if ((rv = set_template_attribute(&template->decrypt,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_DECRYPT inconsistent in pTemplate");
+ return rv;
+ }
+ break;
+
+ case CKA_SIGN:
+ rv = set_object_type(type, YH_ASYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ if ((rv = set_template_attribute(&template->sign,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_SIGN inconsistent in pTemplate");
+ return rv;
+ }
+ break;
+
+ case CKA_DERIVE:
+ rv = set_object_type(type, YH_ASYMMETRIC_KEY);
+ if (rv != CKR_OK) {
+ return rv;
+ }
+ if ((rv = set_template_attribute(&template->derive,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_DERIVE inconsistent in PrivateKeyTemplate");
+ return rv;
+ }
+ break;
+
+ case CKA_EXTRACTABLE:
+ if ((rv = set_template_attribute(&template->exportable,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_EXTRACTABLE inconsistent in PrivateKeyTemplate");
+ return rv;
+ }
+ break;
+
+ default:
+ DBG_ERR("unknown attribute 0x%lx", pTemplate[i].type);
+ break;
+ }
+ }
+
+ if (ecparams != NULL) {
+ uint16_t key_len;
+ if (ckk_type == CKK_EC) {
+ rv =
+ parse_ecparams(ecparams, ecparams_len, &template->algorithm, &key_len);
+ } else if (ckk_type == CKK_EC_EDWARDS) {
+ rv =
+ parse_edparams(ecparams, ecparams_len, &template->algorithm, &key_len);
+ } else {
+ DBG_ERR("Found EC parameters for non EC keys");
+ return CKR_TEMPLATE_INCONSISTENT;
+ }
+ if (rv != CKR_OK) {
+ DBG_ERR("Failed to parse CKA_ECPARAMS");
+ return rv;
+ }
+ }
+
+ return CKR_OK;
+}
+
CK_RV parse_aes_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
yubihsm_pkcs11_object_template *template,
bool generate) {
@@ -5595,7 +5918,6 @@ CK_RV populate_template(int type, void *object, CK_ATTRIBUTE_PTR pTemplate,
DBG_INFO("Getting attribute 0x%lx", pTemplate[i].type);
CK_ULONG len = sizeof(tmp);
CK_RV attribute_rc;
-
if (type == ECDH_KEY_TYPE) {
ecdh_session_key *key = object;
attribute_rc =
diff --git a/pkcs11/util_pkcs11.h b/pkcs11/util_pkcs11.h
index 8deb3fb2c..be4090383 100644
--- a/pkcs11/util_pkcs11.h
+++ b/pkcs11/util_pkcs11.h
@@ -123,6 +123,7 @@ bool create_session(yubihsm_pkcs11_slot *slot, CK_FLAGS flags,
void release_session(yubihsm_pkcs11_context *ctx,
yubihsm_pkcs11_session *session);
+CK_RV set_object_type(uint8_t *type, uint8_t expected_type);
CK_RV set_template_attribute(yubihsm_pkcs11_attribute *attribute,
CK_BBOOL *value);
CK_RV parse_rsa_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
@@ -137,6 +138,11 @@ CK_RV parse_hmac_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_RV parse_wrap_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
yubihsm_pkcs11_object_template *template,
yh_algorithm algorithm, bool generate);
+CK_RV parse_rsa_wrappedkey_template(CK_ATTRIBUTE_PTR pTemplate,
+ CK_ULONG ulCount,
+ yubihsm_pkcs11_object_template *template,
+ pkcs11_meta_object *pkcs11meta,
+ CK_BYTE *type);
CK_RV parse_aes_template(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
yubihsm_pkcs11_object_template *template,
bool generate);
diff --git a/pkcs11/yubihsm_pkcs11.c b/pkcs11/yubihsm_pkcs11.c
index ec1ca87a5..29dfa59bf 100644
--- a/pkcs11/yubihsm_pkcs11.c
+++ b/pkcs11/yubihsm_pkcs11.c
@@ -462,14 +462,14 @@ static CK_RV C_GetInfo_Ex(CK_INFO_PTR pInfo, CK_VERSION cryptokiVersion) {
memcpy((char *) pInfo->libraryDescription, YUBIHSM_PKCS11_LIBDESC,
strlen(YUBIHSM_PKCS11_LIBDESC));
- CK_VERSION libraryVersion = {VERSION_MAJOR, (VERSION_MINOR * 10) + VERSION_PATCH};
+ CK_VERSION libraryVersion = {VERSION_MAJOR,
+ (VERSION_MINOR * 10) + VERSION_PATCH};
pInfo->libraryVersion = libraryVersion;
return CKR_OK;
}
-
CK_DEFINE_FUNCTION(CK_RV, C_GetInfo)(CK_INFO_PTR pInfo) {
DIN;
@@ -707,16 +707,17 @@ CK_DEFINE_FUNCTION(CK_RV, C_GetTokenInfo)
memcpy((char *) pInfo->model, s, l);
memset(pInfo->serialNumber, ' ', sizeof(pInfo->serialNumber));
- l = snprintf((char *) pInfo->serialNumber, sizeof(pInfo->serialNumber), "%08u", serial);
+ l = snprintf((char *) pInfo->serialNumber, sizeof(pInfo->serialNumber),
+ "%08u", serial);
pInfo->serialNumber[l] = ' ';
pInfo->flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED |
CKF_TOKEN_INITIALIZED;
pInfo->ulMaxSessionCount =
- CK_EFFECTIVELY_INFINITE; // maximum number of sessions that can be opened
- // with the token at one time by a single
- // application
+ CK_EFFECTIVELY_INFINITE; // maximum number of sessions that can be opened
+ // with the token at one time by a single
+ // application
pInfo->ulSessionCount =
CK_UNAVAILABLE_INFORMATION; // number of sessions that this application
// currently has open with the token
@@ -1221,6 +1222,40 @@ CK_DEFINE_FUNCTION(CK_RV, C_Logout)(CK_SESSION_HANDLE hSession) {
return rv;
}
+static yh_rc set_wrapkey_capabilities(yubihsm_pkcs11_object_template *template,
+ yh_capabilities *capabilities) {
+ yh_rc rc;
+ if (template->wrap == ATTRIBUTE_TRUE) {
+ rc = yh_string_to_capabilities("export-wrapped", capabilities);
+ if (rc != YHR_SUCCESS) {
+ return rc;
+ }
+ }
+
+ if (template->unwrap == ATTRIBUTE_TRUE) {
+ rc = yh_string_to_capabilities("import-wrapped", capabilities);
+ if (rc != YHR_SUCCESS) {
+ return rc;
+ }
+ }
+
+ if (template->encrypt == ATTRIBUTE_TRUE) {
+ rc = yh_string_to_capabilities("wrap-data", capabilities);
+ if (rc != YHR_SUCCESS) {
+ return rc;
+ }
+ }
+
+ if (template->decrypt == ATTRIBUTE_TRUE) {
+ rc = yh_string_to_capabilities("unwrap-data", capabilities);
+ if (rc != YHR_SUCCESS) {
+ return rc;
+ }
+ }
+
+ return YHR_SUCCESS;
+}
+
CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR phObject) {
@@ -1340,34 +1375,61 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
DBG_INFO("parsed RSA key, algorithm: %d, objlen: %d", template.algorithm,
template.objlen);
- if (template.sign == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities);
+ uint8_t p[512], q[512];
+
+ set_component(p, template.obj.rsa.p, template.objlen);
+ set_component(q, template.obj.rsa.q, template.objlen);
+
+ BN_free(template.obj.rsa.p);
+ BN_free(template.obj.rsa.q);
+
+ if (template.unwrap) {
+ type = YH_WRAP_KEY;
+
+ rc = set_wrapkey_capabilities(&template, &capabilities);
if (rc != YHR_SUCCESS) {
rv = yrc_to_rv(rc);
goto c_co_out;
}
- }
- if (template.decrypt == ATTRIBUTE_TRUE) {
- rc =
- yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep", &capabilities);
+ rc = yh_string_to_capabilities("all", &delegated_capabilities);
if (rc != YHR_SUCCESS) {
rv = yrc_to_rv(rc);
goto c_co_out;
}
- }
- uint8_t p[512], q[512];
+ uint8_t key[1024] = {0};
+ memcpy(key, p, template.objlen);
+ memcpy(key + template.objlen, q, template.objlen);
- set_component(p, template.obj.rsa.p, template.objlen);
- set_component(q, template.obj.rsa.q, template.objlen);
+ rc = yh_util_import_wrap_key(session->slot->device_session, &template.id,
+ template.label, 0xffff, &capabilities,
+ template.algorithm, &delegated_capabilities,
+ key, template.objlen * 2);
- BN_free(template.obj.rsa.p);
- BN_free(template.obj.rsa.q);
+ } else {
- rc = yh_util_import_rsa_key(session->slot->device_session, &template.id,
- template.label, 0xffff, &capabilities,
- template.algorithm, p, q);
+ if (template.sign == ATTRIBUTE_TRUE) {
+ rc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities);
+ if (rc != YHR_SUCCESS) {
+ rv = yrc_to_rv(rc);
+ goto c_co_out;
+ }
+ }
+
+ if (template.decrypt == ATTRIBUTE_TRUE) {
+ rc = yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep",
+ &capabilities);
+ if (rc != YHR_SUCCESS) {
+ rv = yrc_to_rv(rc);
+ goto c_co_out;
+ }
+ }
+
+ rc = yh_util_import_rsa_key(session->slot->device_session, &template.id,
+ template.label, 0xffff, &capabilities,
+ template.algorithm, p, q);
+ }
if (rc != YHR_SUCCESS) {
DBG_ERR("Failed importing RSA key to device: %s", yh_strerror(rc));
rv = yrc_to_rv(rc);
@@ -1429,10 +1491,9 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
}
rc = yh_util_import_ed_key(session->slot->device_session, &template.id,
- template.label, 0xffff, &capabilities,
- template.algorithm,
- template.obj.buf);
- if(rc != YHR_SUCCESS) {
+ template.label, 0xffff, &capabilities,
+ template.algorithm, template.obj.buf);
+ if (rc != YHR_SUCCESS) {
DBG_ERR("Failed importing ED key to device");
rv = yrc_to_rv(rc);
goto c_co_out;
@@ -1490,7 +1551,6 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
key_type.d == CKK_YUBICO_AES192_CCM_WRAP ||
key_type.d == CKK_YUBICO_AES256_CCM_WRAP) {
yh_algorithm algo = key_type.d & 0xff;
- type = YH_WRAP_KEY;
rv = parse_wrap_template(pTemplate, ulCount, &template, algo, false);
if (rv != CKR_OK) {
goto c_co_out;
@@ -1498,36 +1558,10 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
DBG_INFO("parsed WRAP key, objlen: %d", template.objlen);
- if (template.wrap == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("export-wrapped", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_co_out;
- }
- }
-
- if (template.unwrap == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("import-wrapped", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_co_out;
- }
- }
-
- if (template.encrypt == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("wrap-data", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_co_out;
- }
- }
-
- if (template.decrypt == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("unwrap-data", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_co_out;
- }
+ rc = set_wrapkey_capabilities(&template, &capabilities);
+ if (rc != YHR_SUCCESS) {
+ rv = yrc_to_rv(rc);
+ goto c_co_out;
}
rc = yh_string_to_capabilities("all", &delegated_capabilities);
@@ -1536,10 +1570,11 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
goto c_co_out;
}
+ type = YH_WRAP_KEY;
rc = yh_util_import_wrap_key(session->slot->device_session, &template.id,
- template.label, 0xffff, &capabilities, algo,
- &delegated_capabilities, template.obj.buf,
- template.objlen);
+ template.label, 0xffff, &capabilities, algo,
+ &delegated_capabilities, template.obj.buf,
+ template.objlen);
if (rc != YHR_SUCCESS) {
DBG_ERR("Failed writing WRAP key to device: %s", yh_strerror(rc));
rv = yrc_to_rv(rc);
@@ -1665,7 +1700,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
meta_object.target_id = template.id;
}
} else if (class.d == CKO_PUBLIC_KEY) {
- bool pubkey_found = false;
+
// Read the value of the public key
for (CK_ULONG i = 0; i < ulCount; i++) {
switch (pTemplate[i].type) {
@@ -1680,84 +1715,155 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
goto c_co_out;
}
break;
+ case CKA_WRAP:
+ if ((rv = set_template_attribute(&template.wrap,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_WRAP inconsistent in template");
+ return rv;
+ }
+ break;
+ case CKA_ENCRYPT:
+ if ((rv = set_template_attribute(&template.encrypt,
+ pTemplate[i].pValue)) != CKR_OK) {
+ DBG_ERR("CKA_ENCRYPT inconsistent in template");
+ return rv;
+ }
+ break;
}
}
- // Get a list of all asym objects in the YubiHSM
- yh_object_descriptor asym_keys[YH_MAX_ITEMS_COUNT] = {0};
- size_t asym_keys_len = sizeof(asym_keys);
- rc = yh_util_list_objects(session->slot->device_session, 0,
- YH_ASYMMETRIC_KEY, 0, &capabilities, 0, NULL,
- asym_keys, &asym_keys_len);
- if (rc != YHR_SUCCESS) {
- DBG_ERR("Failed to get object list");
- rv = yrc_to_rv(rc);
- goto c_co_out;
- }
+ if (template.wrap && key_type.d == CKK_RSA) {
+ switch (template.objlen) {
+ case 256:
+ template.algorithm = YH_ALGO_RSA_2048;
+ break;
+ case 384:
+ template.algorithm = YH_ALGO_RSA_3072;
+ break;
+ case 512:
+ template.algorithm = YH_ALGO_RSA_4096;
+ break;
+ default:
+ DBG_ERR("Unsupported key length");
+ rv = CKR_DATA_INVALID;
+ goto c_co_out;
+ }
+
+ if (template.algorithm == 0) {
+ DBG_ERR("Missing CKA_KEY_TYPE in attribute template");
+ rv = CKR_TEMPLATE_INCOMPLETE;
+ goto c_co_out;
+ }
+
+ rc = set_wrapkey_capabilities(&template, &capabilities);
+ if (rc != YHR_SUCCESS) {
+ rv = yrc_to_rv(rc);
+ goto c_co_out;
+ }
- // Check which asym public key matches the one in the request
- for (size_t i = 0; i < asym_keys_len; i++) {
- uint8_t pubkey[2048] = {0};
- size_t pubkey_len = sizeof(pubkey);
- rc = yh_util_get_public_key(session->slot->device_session,
- asym_keys[i].id, pubkey, &pubkey_len, NULL);
+ rc = yh_string_to_capabilities("all", &delegated_capabilities);
if (rc != YHR_SUCCESS) {
- DBG_ERR("Failed to get public key of object 0x%x", asym_keys[i].id);
rv = yrc_to_rv(rc);
goto c_co_out;
}
- if (match_byte_array(pubkey, pubkey_len, template.obj.buf,
- template.objlen)) {
- template.id = asym_keys[i].id;
- pubkey_found = true;
+ rc =
+ yh_util_import_public_wrap_key(session->slot->device_session, &template.id,
+ template.label, 0xffff, &capabilities,
+ template.algorithm, &delegated_capabilities,
+ template.obj.buf, template.objlen);
+ if (rc != YHR_SUCCESS) {
+ DBG_ERR("Failed writing Public Wrap key to device: %s",
+ yh_strerror(rc));
+ rv = yrc_to_rv(rc);
+ goto c_co_out;
+ }
+ type = YH_PUBLIC_WRAP_KEY;
+
+ } else { // Treat it as asymmetric public key. List all asymmetric keys and
+ // check whether this public key matches any of them. If not,
+ // import operation fails
+
+ bool pubkey_found = false;
+ // Get a list of all asym objects in the YubiHSM
+ yh_object_descriptor asym_keys[YH_MAX_ITEMS_COUNT] = {0};
+ size_t asym_keys_len = sizeof(asym_keys);
+ rc = yh_util_list_objects(session->slot->device_session, 0,
+ YH_ASYMMETRIC_KEY, 0, &capabilities, 0, NULL,
+ asym_keys, &asym_keys_len);
+ if (rc != YHR_SUCCESS) {
+ DBG_ERR("Failed to get object list");
+ rv = yrc_to_rv(rc);
+ goto c_co_out;
+ }
- // If there's need, update or create meta_object
- yubihsm_pkcs11_object_desc *asym_key_desc =
- _get_object_desc(session->slot, asym_keys[i].id, YH_ASYMMETRIC_KEY,
- asym_keys[i].sequence);
- if (asym_key_desc == NULL) {
- continue;
+ // Check which asym public key matches the one in the request
+ for (size_t i = 0; i < asym_keys_len; i++) {
+ uint8_t pubkey[2048] = {0};
+ size_t pubkey_len = sizeof(pubkey);
+ rc = yh_util_get_public_key(session->slot->device_session,
+ asym_keys[i].id, pubkey, &pubkey_len, NULL);
+ if (rc != YHR_SUCCESS) {
+ DBG_ERR("Failed to get public key of object 0x%x", asym_keys[i].id);
+ rv = yrc_to_rv(rc);
+ goto c_co_out;
}
- if (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0) {
- yubihsm_pkcs11_object_desc *pMeta_object =
- find_meta_object_by_target(session->slot, asym_keys[i].id,
- YH_ASYMMETRIC_KEY, asym_keys[i].sequence,
- asym_key_desc->object.domains);
-
- if (pMeta_object != NULL) { // meta object already exists. Update it.
- if (meta_object.cka_id.len > 0) {
- pMeta_object->meta_object.cka_id_pubkey.len =
- meta_object.cka_id.len;
- memcpy(pMeta_object->meta_object.cka_id_pubkey.value,
- meta_object.cka_id.value, meta_object.cka_id.len);
- }
- if (meta_object.cka_label.len > 0) {
- pMeta_object->meta_object.cka_label_pubkey.len =
- meta_object.cka_label.len;
- memcpy(pMeta_object->meta_object.cka_label_pubkey.value,
- meta_object.cka_label.value, meta_object.cka_label.len);
- }
- rv = write_meta_object(session->slot, &pMeta_object->meta_object,
- &capabilities, asym_key_desc->object.domains,
- true);
- if (rv != CKR_OK) {
- goto c_co_out;
+
+ if (match_byte_array(pubkey, pubkey_len, template.obj.buf,
+ template.objlen)) {
+ template.id = asym_keys[i].id;
+ pubkey_found = true;
+
+ // If there's need, update or create meta_object
+ yubihsm_pkcs11_object_desc *asym_key_desc =
+ _get_object_desc(session->slot, asym_keys[i].id, YH_ASYMMETRIC_KEY,
+ asym_keys[i].sequence);
+ if (asym_key_desc == NULL) {
+ continue;
+ }
+ if (meta_object.cka_id.len > 0 || meta_object.cka_label.len > 0) {
+ yubihsm_pkcs11_object_desc *pMeta_object =
+ find_meta_object_by_target(session->slot, asym_keys[i].id,
+ YH_ASYMMETRIC_KEY,
+ asym_keys[i].sequence,
+ asym_key_desc->object.domains);
+
+ if (pMeta_object !=
+ NULL) { // meta object already exists. Update it.
+ if (meta_object.cka_id.len > 0) {
+ pMeta_object->meta_object.cka_id_pubkey.len =
+ meta_object.cka_id.len;
+ memcpy(pMeta_object->meta_object.cka_id_pubkey.value,
+ meta_object.cka_id.value, meta_object.cka_id.len);
+ }
+ if (meta_object.cka_label.len > 0) {
+ pMeta_object->meta_object.cka_label_pubkey.len =
+ meta_object.cka_label.len;
+ memcpy(pMeta_object->meta_object.cka_label_pubkey.value,
+ meta_object.cka_label.value, meta_object.cka_label.len);
+ }
+ rv = write_meta_object(session->slot, &pMeta_object->meta_object,
+ &capabilities,
+ asym_key_desc->object.domains, true);
+ if (rv != CKR_OK) {
+ goto c_co_out;
+ }
+ } else { // meta object does not exist. Create it
+ meta_object.target_id = asym_keys[i].id;
+ // No need to write this meta object now becase we will do it
+ // later
}
- } else { // meta object does not exist. Create it
- meta_object.target_id = asym_keys[i].id;
- // No need to write this meta object now becase we will do it later
}
+ break;
}
- break;
}
- }
- if (pubkey_found == false) {
- rv = CKR_ATTRIBUTE_VALUE_INVALID;
- goto c_co_out;
+ if (pubkey_found == false) {
+ rv = CKR_ATTRIBUTE_VALUE_INVALID;
+ goto c_co_out;
+ }
+ type = YH_ASYMMETRIC_KEY;
}
- type = YH_ASYMMETRIC_KEY;
} else {
rv = CKR_TEMPLATE_INCONSISTENT;
goto c_co_out;
@@ -1786,7 +1892,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
}
}
- if (class.d == CKO_PUBLIC_KEY) {
+ if (class.d == CKO_PUBLIC_KEY && type != YH_PUBLIC_WRAP_KEY) {
*phObject =
object->sequence << 24 | (object->type | 0x80) << 16 | object->id;
} else {
@@ -1856,7 +1962,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_DestroyObject)
DBG_INFO("No ECDH session key with ID %08lx was found", hObject);
}
} else {
- if (((uint8_t)(hObject >> 16)) == YH_PUBLIC_KEY) {
+ if (((uint8_t) (hObject >> 16)) == YH_PUBLIC_KEY) {
DBG_INFO("Trying to delete public key, returning success with noop");
goto c_do_out;
}
@@ -2220,18 +2326,6 @@ static bool should_include_sessionkeys(bool is_secret_key, bool extractable_set,
return true;
}
-static CK_RV set_object_type(uint8_t *type, uint8_t expected_type) {
- if (*type == 0) {
- *type = expected_type;
- return CKR_OK;
- }
- if (*type != expected_type) {
- DBG_ERR("Mismatch in attribute values");
- return CKR_TEMPLATE_INCONSISTENT;
- }
- return CKR_OK;
-}
-
CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) {
@@ -2286,6 +2380,8 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
yh_algorithm algorithm = 0;
bool unknown = false;
bool secret_key = false;
+ bool rsa_key = false;
+ bool wrap_key = false;
bool extractable_set = false;
size_t template_value_len = 0;
uint8_t template_id[CKA_ATTRIBUTE_VALUE_SIZE] = {0};
@@ -2303,14 +2399,14 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
break;
case CKA_CLASS: {
- uint32_t value = *((CK_ULONG_PTR)(pTemplate[i].pValue));
+ uint32_t value = *((CK_ULONG_PTR) (pTemplate[i].pValue));
uint8_t class_type = 0;
switch (value) {
case CKO_CERTIFICATE:
DBG_INFO("filtering for certificates");
algorithm =
YH_ALGO_OPAQUE_X509_CERTIFICATE; // TODO: handle other certs?
- type = YH_OPAQUE;
+ class_type = YH_OPAQUE;
break;
case CKO_DATA:
@@ -2388,10 +2484,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
case CKA_WRAP:
if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) {
- rv = set_object_type(&type, YH_WRAP_KEY);
- if (rv != CKR_OK) {
- goto c_foi_out;
- }
+ wrap_key = true;
rc = yh_string_to_capabilities("export-wrapped", &capabilities);
if (rc != YHR_SUCCESS) {
rv = yrc_to_rv(rc);
@@ -2402,10 +2495,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
case CKA_UNWRAP:
if (*((CK_BBOOL *) pTemplate[i].pValue) == CK_TRUE) {
- rv = set_object_type(&type, YH_WRAP_KEY);
- if (rv != CKR_OK) {
- goto c_foi_out;
- }
+ wrap_key = true;
rc = yh_string_to_capabilities("import-wrapped", &capabilities);
if (rc != YHR_SUCCESS) {
rv = yrc_to_rv(rc);
@@ -2434,7 +2524,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
break;
case CKA_KEY_TYPE: {
- uint32_t value = *((CK_ULONG_PTR)(pTemplate[i].pValue));
+ uint32_t value = *((CK_ULONG_PTR) (pTemplate[i].pValue));
uint8_t key_type = 0;
switch (value) {
case CKK_YUBICO_AES128_CCM_WRAP:
@@ -2452,6 +2542,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
key_type = YH_SYMMETRIC_KEY;
break;
case CKK_RSA:
+ rsa_key = true;
case CKK_EC:
key_type = YH_ASYMMETRIC_KEY;
break;
@@ -2487,6 +2578,14 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
}
}
+ if(wrap_key && rsa_key) {
+ if (pub) {
+ type = YH_PUBLIC_WRAP_KEY;
+ } else {
+ type = YH_WRAP_KEY;
+ }
+ }
+
if (unknown == false) {
uint16_t found_objects = 0;
if (secret_key == true) {
@@ -2529,39 +2628,38 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjectsInit)
"Value in template not an X509Certificate. Cannot perform search.");
rv = CKR_ATTRIBUTE_VALUE_INVALID;
goto c_foi_out;
- } else {
- yh_object_descriptor tmp_objects[YH_MAX_ITEMS_COUNT] = {0};
- size_t tmp_n_objects = sizeof(tmp_objects);
- rc = yh_util_list_objects(session->slot->device_session, 0, YH_OPAQUE,
- domains, &capabilities,
- YH_ALGO_OPAQUE_X509_CERTIFICATE, label,
- tmp_objects, &tmp_n_objects);
+ }
+ yh_object_descriptor tmp_objects[YH_MAX_ITEMS_COUNT] = {0};
+ size_t tmp_n_objects = sizeof(tmp_objects);
+ rc = yh_util_list_objects(session->slot->device_session, 0, YH_OPAQUE,
+ domains, &capabilities,
+ YH_ALGO_OPAQUE_X509_CERTIFICATE, label,
+ tmp_objects, &tmp_n_objects);
+ if (rc != YHR_SUCCESS) {
+ DBG_ERR("Failed to get object list");
+ rv = yrc_to_rv(rc);
+ goto c_foi_out;
+ }
+
+ for (size_t i = 0; i < tmp_n_objects; i++) {
+ uint8_t cert[2048] = {0};
+ size_t cert_len = sizeof(cert);
+ rc = yh_util_get_opaque(session->slot->device_session,
+ tmp_objects[i].id, cert, &cert_len);
if (rc != YHR_SUCCESS) {
- DBG_ERR("Failed to get object list");
+ DBG_ERR("Failed to get opaque object 0x%x", tmp_objects[i].id);
rv = yrc_to_rv(rc);
goto c_foi_out;
}
- for (size_t i = 0; i < tmp_n_objects; i++) {
- uint8_t cert[2048] = {0};
- size_t cert_len = sizeof(cert);
- rc = yh_util_get_opaque(session->slot->device_session,
- tmp_objects[i].id, cert, &cert_len);
- if (rc != YHR_SUCCESS) {
- DBG_ERR("Failed to get opaque object 0x%x", tmp_objects[i].id);
- rv = yrc_to_rv(rc);
- goto c_foi_out;
- }
-
- if (match_byte_array(template_value, template_value_len, cert,
- cert_len)) {
- session->operation.op.find.objects[0].id = tmp_objects[i].id;
- session->operation.op.find.objects[0].type = tmp_objects[i].type;
- session->operation.op.find.objects[0].sequence =
- tmp_objects[i].sequence;
- found_objects = 1;
- break;
- }
+ if (match_byte_array(template_value, template_value_len, cert,
+ cert_len)) {
+ session->operation.op.find.objects[0].id = tmp_objects[i].id;
+ session->operation.op.find.objects[0].type = tmp_objects[i].type;
+ session->operation.op.find.objects[0].sequence =
+ tmp_objects[i].sequence;
+ found_objects = 1;
+ break;
}
}
} else {
@@ -2705,6 +2803,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_FindObjects)
case YH_ASYMMETRIC_KEY:
case YH_OPAQUE:
case YH_WRAP_KEY:
+ case YH_PUBLIC_WRAP_KEY:
case YH_HMAC_KEY:
case YH_PUBLIC_KEY:
case YH_SYMMETRIC_KEY:
@@ -2814,7 +2913,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_EncryptInit)
rv = check_decrypt_mechanism(session->slot, pMechanism);
if (rv != CKR_OK) {
- DBG_ERR("Encryption mechanism %lu not supported", pMechanism->mechanism);
+ DBG_ERR("Encryption mechanism 0x%lx not supported", pMechanism->mechanism);
goto c_ei_out;
}
@@ -3135,6 +3234,110 @@ CK_DEFINE_FUNCTION(CK_RV, C_EncryptFinal)
return rv;
}
+typedef struct rsa_pkcs_oaep_params {
+ yh_algorithm mgf_algo;
+ yh_algorithm oaep_algo;
+ uint8_t oaep_label[64];
+ u_int oaep_label_len;
+} rsa_pkcs_oaep_params_t;
+
+static CK_RV parse_rsa_pkcs_oaep_params(CK_RSA_PKCS_OAEP_PARAMS *p,
+ rsa_pkcs_oaep_params_t *r) {
+ const EVP_MD *md = NULL;
+ switch (p->mgf) {
+ case CKG_MGF1_SHA1:
+ r->mgf_algo = YH_ALGO_MGF1_SHA1;
+ break;
+ case CKG_MGF1_SHA256:
+ r->mgf_algo = YH_ALGO_MGF1_SHA256;
+ break;
+ case CKG_MGF1_SHA384:
+ r->mgf_algo = YH_ALGO_MGF1_SHA384;
+ break;
+ case CKG_MGF1_SHA512:
+ r->mgf_algo = YH_ALGO_MGF1_SHA512;
+ break;
+ default:
+ DBG_ERR("Invalid mgf parameter (%lx)", p->mgf);
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ switch (p->hashAlg) {
+ case CKM_SHA_1:
+ r->oaep_algo = YH_ALGO_RSA_OAEP_SHA1;
+ md = EVP_sha1();
+ break;
+ case CKM_SHA256:
+ r->oaep_algo = YH_ALGO_RSA_OAEP_SHA256;
+ md = EVP_sha256();
+ break;
+ case CKM_SHA384:
+ r->oaep_algo = YH_ALGO_RSA_OAEP_SHA384;
+ md = EVP_sha384();
+ break;
+ case CKM_SHA512:
+ r->oaep_algo = YH_ALGO_RSA_OAEP_SHA512;
+ md = EVP_sha512();
+ break;
+ default:
+ DBG_ERR("Invalid hashAlg parameter (%lx)", p->hashAlg);
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ switch (p->source) {
+ case 0:
+ if (p->ulSourceDataLen) {
+ DBG_ERR("Invalid ulSourceDataLen (%lu) parameter for source == 0",
+ p->ulSourceDataLen);
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ case CKZ_DATA_SPECIFIED:
+ if (p->ulSourceDataLen && p->pSourceData == NULL) {
+ DBG_ERR(
+ "Invalid pSourceData parameter (NULL) for ulSourceDataLen != 0");
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ break;
+ default:
+ DBG_ERR("Invalid source parameter (%lx)", p->source);
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
+ if (mdctx == NULL) {
+ DBG_ERR("Failed to digest source");
+ return CKR_FUNCTION_FAILED;
+ }
+ r->oaep_label_len = sizeof(r->oaep_label);
+ EVP_DigestInit_ex(mdctx, md, NULL);
+ EVP_DigestUpdate(mdctx, p->pSourceData, p->ulSourceDataLen);
+ EVP_DigestFinal_ex(mdctx, r->oaep_label, &r->oaep_label_len);
+ EVP_MD_CTX_destroy(mdctx);
+ return CKR_OK;
+}
+
+typedef struct rsa_aes_key_wrap_params {
+ yh_algorithm aes_algo;
+ rsa_pkcs_oaep_params_t oaep_params;
+} rsa_aes_key_wrap_params_t;
+
+static CK_RV parse_rsa_aes_key_wrap_params(CK_RSA_AES_KEY_WRAP_PARAMS *p,
+ rsa_aes_key_wrap_params_t *r) {
+
+ switch (p->ulAESKeyBits) {
+ case 128:
+ r->aes_algo = YH_ALGO_AES128;
+ break;
+ case 192:
+ r->aes_algo = YH_ALGO_AES192;
+ break;
+ case 256:
+ r->aes_algo = YH_ALGO_AES256;
+ break;
+ default:
+ DBG_ERR("Invalid ulAESKeyBits parameter");
+ return CKR_MECHANISM_PARAM_INVALID;
+ }
+ return parse_rsa_pkcs_oaep_params(p->pOAEPParams, &r->oaep_params);
+}
+
CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)
(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
CK_OBJECT_HANDLE hKey) {
@@ -3186,7 +3389,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)
rv = check_decrypt_mechanism(session->slot, pMechanism);
if (rv != CKR_OK) {
- DBG_ERR("Decryption mechanism %lu not supported", pMechanism->mechanism);
+ DBG_ERR("Decryption mechanism 0x%lx not supported", pMechanism->mechanism);
goto c_di_out;
}
session->operation.mechanism.mechanism = pMechanism->mechanism;
@@ -3226,67 +3429,17 @@ CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)
goto c_di_out;
}
- switch (params->mgf) {
- case CKG_MGF1_SHA1:
- session->operation.mechanism.oaep.mgf1Algo = YH_ALGO_MGF1_SHA1;
- break;
- case CKG_MGF1_SHA256:
- session->operation.mechanism.oaep.mgf1Algo = YH_ALGO_MGF1_SHA256;
- break;
- case CKG_MGF1_SHA384:
- session->operation.mechanism.oaep.mgf1Algo = YH_ALGO_MGF1_SHA384;
- break;
- case CKG_MGF1_SHA512:
- session->operation.mechanism.oaep.mgf1Algo = YH_ALGO_MGF1_SHA512;
- break;
- default:
- DBG_ERR("Unknown value in parameter mgf");
- rv = CKR_MECHANISM_PARAM_INVALID;
- goto c_di_out;
- };
-
- const EVP_MD *md = NULL;
-
- switch (params->hashAlg) {
- case CKM_SHA_1:
- md = EVP_sha1();
- break;
- case CKM_SHA256:
- md = EVP_sha256();
- break;
- case CKM_SHA384:
- md = EVP_sha384();
- break;
- case CKM_SHA512:
- md = EVP_sha512();
- break;
- default:
- DBG_ERR("Unknown value in parameter hashAlg");
- rv = CKR_MECHANISM_PARAM_INVALID;
- goto c_di_out;
- }
- mdctx = EVP_MD_CTX_create();
- if (mdctx == NULL) {
- rv = CKR_HOST_MEMORY;
+ rsa_pkcs_oaep_params_t oaep_params;
+ rv = parse_rsa_pkcs_oaep_params(params, &oaep_params);
+ if (rv != CKR_OK) {
goto c_di_out;
}
- if (EVP_DigestInit_ex(mdctx, md, NULL) == 0) {
- rv = CKR_MECHANISM_PARAM_INVALID;
- goto c_di_out;
- }
+ session->operation.mechanism.oaep.mgf1Algo = oaep_params.mgf_algo;
+ session->operation.mechanism.oaep.label_len = oaep_params.oaep_label_len;
+ memcpy(session->operation.mechanism.oaep.label, oaep_params.oaep_label,
+ oaep_params.oaep_label_len);
- if (EVP_DigestUpdate(mdctx, params->pSourceData,
- params->ulSourceDataLen) != 1) {
- rv = CKR_FUNCTION_FAILED;
- goto c_di_out;
- }
- if (EVP_DigestFinal_ex(mdctx, session->operation.mechanism.oaep.label,
- &session->operation.mechanism.oaep.label_len) !=
- 1) {
- rv = CKR_FUNCTION_FAILED;
- goto c_di_out;
- }
} else if (pMechanism->mechanism != CKM_RSA_PKCS) {
DBG_ERR("Mechanism %lu not supported", pMechanism->mechanism);
rv = CKR_MECHANISM_INVALID;
@@ -4054,7 +4207,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_SignInit)
rv = check_sign_mechanism(session->slot, pMechanism);
if (rv != CKR_OK) {
- DBG_ERR("Signing mechanism %lu not supported", pMechanism->mechanism);
+ DBG_ERR("Signing mechanism 0x%lx not supported", pMechanism->mechanism);
goto c_si_out;
}
session->operation.mechanism.mechanism =
@@ -4483,7 +4636,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_VerifyInit)
rv = check_sign_mechanism(session->slot, pMechanism);
if (rv != CKR_OK) {
- DBG_ERR("Verification mechanism %lu not supported", pMechanism->mechanism);
+ DBG_ERR("Verification mechanism 0x%lx not supported", pMechanism->mechanism);
goto c_vi_out;
}
session->operation.mechanism.mechanism =
@@ -5046,36 +5199,10 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKey)
DBG_INFO("parsed WRAP key, objlen: %d", template.objlen);
- if (template.wrap == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("export-wrapped", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_gk_out;
- }
- }
-
- if (template.unwrap == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("import-wrapped", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_gk_out;
- }
- }
-
- if (template.encrypt == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("wrap-data", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_gk_out;
- }
- }
-
- if (template.decrypt == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("unwrap-data", &capabilities);
- if (rc != YHR_SUCCESS) {
- rv = yrc_to_rv(rc);
- goto c_gk_out;
- }
+ rc = set_wrapkey_capabilities(&template, &capabilities);
+ if (rc != YHR_SUCCESS) {
+ rv = yrc_to_rv(rc);
+ goto c_gk_out;
}
rc = yh_string_to_capabilities("all", &delegated_capabilities);
@@ -5251,27 +5378,47 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)
// TODO(adma): check more return values
if (yh_is_rsa(template.algorithm)) {
-
- if (template.sign == ATTRIBUTE_TRUE) {
- rc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities);
+ if (template.unwrap) { // This is a wrap key
+ rc = set_wrapkey_capabilities(&template, &capabilities);
if (rc != YHR_SUCCESS) {
rv = yrc_to_rv(rc);
goto c_gkp_out;
}
- }
- if (template.decrypt == ATTRIBUTE_TRUE) {
- rc =
- yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep", &capabilities);
+ yh_capabilities delegated_capabilities = {{0}};
+ rc = yh_string_to_capabilities("all", &delegated_capabilities);
if (rc != YHR_SUCCESS) {
rv = yrc_to_rv(rc);
goto c_gkp_out;
}
- }
- rc = yh_util_generate_rsa_key(session->slot->device_session, &template.id,
+ rc =
+ yh_util_generate_wrap_key(session->slot->device_session, &template.id,
template.label, 0xffff, &capabilities,
- template.algorithm);
+ template.algorithm, &delegated_capabilities);
+
+ } else {
+ if (template.sign == ATTRIBUTE_TRUE) {
+ rc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities);
+ if (rc != YHR_SUCCESS) {
+ rv = yrc_to_rv(rc);
+ goto c_gkp_out;
+ }
+ }
+
+ if (template.decrypt == ATTRIBUTE_TRUE) {
+ rc =
+ yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep", &capabilities);
+ if (rc != YHR_SUCCESS) {
+ rv = yrc_to_rv(rc);
+ goto c_gkp_out;
+ }
+ }
+
+ rc = yh_util_generate_rsa_key(session->slot->device_session, &template.id,
+ template.label, 0xffff, &capabilities,
+ template.algorithm);
+ }
if (rc != YHR_SUCCESS) {
DBG_ERR("Failed generating RSA key on device: %s", yh_strerror(rc));
rv = yrc_to_rv(rc);
@@ -5324,8 +5471,14 @@ CK_DEFINE_FUNCTION(CK_RV, C_GenerateKeyPair)
}
}
- yubihsm_pkcs11_object_desc *object_desc =
- _get_object_desc(session->slot, template.id, YH_ASYMMETRIC_KEY, 0xffff);
+ yubihsm_pkcs11_object_desc *object_desc = NULL;
+ if (template.unwrap) {
+ object_desc =
+ _get_object_desc(session->slot, template.id, YH_WRAP_KEY, 0xffff);
+ } else {
+ object_desc =
+ _get_object_desc(session->slot, template.id, YH_ASYMMETRIC_KEY, 0xffff);
+ }
if (object_desc == NULL) {
rv = CKR_OBJECT_HANDLE_INVALID;
goto c_gkp_out;
@@ -5405,9 +5558,10 @@ CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)
// NOTE: pWrappedKey is NULL so we just return the length we need
if (pWrappedKey == NULL) {
- *pulWrappedKeyLen =
- sizeof(yh_object_descriptor) + object->object.len + YH_CCM_WRAP_OVERHEAD;
- DBG_INFO("Calculated that wrapping will need %lu bytes", *pulWrappedKeyLen);
+ *pulWrappedKeyLen = YH_MSG_BUF_SIZE;
+ // CKM_YUBICO_AES_CCM_WRAP len = sizeof(yh_object_descriptor) +
+ // object->object.len + YH_CCM_WRAP_OVERHEAD;
+ DBG_INFO("Wrapping will need maximum of %lu bytes", *pulWrappedKeyLen);
rv = CKR_OK;
goto c_wk_out;
}
@@ -5420,7 +5574,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)
rv = check_wrap_mechanism(session->slot, pMechanism);
if (rv != CKR_OK) {
- DBG_ERR("Wrapping mechanism %lu not supported", pMechanism->mechanism);
+ DBG_ERR("Wrapping mechanism 0x%lx not supported", pMechanism->mechanism);
goto c_wk_out;
}
@@ -5446,26 +5600,66 @@ CK_DEFINE_FUNCTION(CK_RV, C_WrapKey)
goto c_wk_out;
}
- uint8_t buf[2048] = {0};
- size_t len = sizeof(buf);
+ size_t len = *pulWrappedKeyLen;
+
+ yh_rc yrc = YHR_SUCCESS;
+ if (pMechanism->mechanism == CKM_YUBICO_AES_CCM_WRAP) {
+ if (pMechanism->pParameter &&
+ pMechanism->ulParameterLen != sizeof(CKM_YUBICO_AES_CCM_WRAP_PARAMS)) {
+ DBG_ERR("Wrong mechanism parameter length");
+ rv = CKR_MECHANISM_PARAM_INVALID;
+ goto c_wk_out;
+ }
+
+ CKM_YUBICO_AES_CCM_WRAP_PARAMS *params = pMechanism->pParameter;
+ CK_ULONG format = 0; // None = Do not include seed
+ if (params != NULL) {
+ format = params->format;
+ }
+ yrc =
+ yh_util_export_wrapped_ex(session->slot->device_session, key->object.id,
+ object->object.type, object->object.id, format,
+ pWrappedKey, &len);
+ } else { // CKM_RSA_AES_KEY_WRAP or CKM_YUBICO_RSA_WRAP
+ if (pMechanism->pParameter == NULL ||
+ pMechanism->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) {
+ DBG_ERR("Wrong mechanism parameter length");
+ rv = CKR_MECHANISM_PARAM_INVALID;
+ goto c_wk_out;
+ }
- yh_rc yrc =
- yh_util_export_wrapped(session->slot->device_session, key->object.id,
- object->object.type, object->object.id, buf, &len);
+ rsa_aes_key_wrap_params_t params = {0};
+ rv = parse_rsa_aes_key_wrap_params(pMechanism->pParameter, ¶ms);
+ if (rv != CKR_OK) {
+ goto c_wk_out;
+ }
+
+ if (pMechanism->mechanism == CKM_RSA_AES_KEY_WRAP) {
+ yrc = yh_util_get_rsa_wrapped_key(session->slot->device_session,
+ key->object.id, object->object.type,
+ object->object.id, params.aes_algo,
+ params.oaep_params.oaep_algo,
+ params.oaep_params.mgf_algo,
+ params.oaep_params.oaep_label,
+ params.oaep_params.oaep_label_len,
+ pWrappedKey, &len);
+ } else { // CKM_YUBICO_RSA_WRAP
+ yrc = yh_util_export_rsa_wrapped(session->slot->device_session,
+ key->object.id, object->object.type,
+ object->object.id, params.aes_algo,
+ params.oaep_params.oaep_algo,
+ params.oaep_params.mgf_algo,
+ params.oaep_params.oaep_label,
+ params.oaep_params.oaep_label_len,
+ pWrappedKey, &len);
+ }
+ }
if (yrc != YHR_SUCCESS) {
DBG_ERR("Wrapping failed: %s", yh_strerror(yrc));
rv = yrc_to_rv(yrc);
goto c_wk_out;
}
- if (len > *pulWrappedKeyLen) {
- DBG_ERR("buffer too small, needed %lu, got %lu", (unsigned long) len,
- *pulWrappedKeyLen);
- rv = CKR_BUFFER_TOO_SMALL;
- goto c_wk_out;
- }
-
- memcpy(pWrappedKey, buf, len);
*pulWrappedKeyLen = len;
DOUT;
@@ -5485,10 +5679,6 @@ CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)
DIN;
- // NOTE: since the wrap is opaque we just ignore the template..
- UNUSED(pTemplate);
- UNUSED(ulAttributeCount);
-
if (g_yh_initialized == false) {
DBG_ERR("libyubihsm is not initialized or already finalized");
return CKR_CRYPTOKI_NOT_INITIALIZED;
@@ -5521,7 +5711,7 @@ CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)
rv = check_wrap_mechanism(session->slot, pMechanism);
if (rv != CKR_OK) {
- DBG_ERR("Wrapping mechanism %lu not supported", pMechanism->mechanism);
+ DBG_ERR("Wrapping mechanism 0x%lx not supported", pMechanism->mechanism);
goto c_uk_out;
}
@@ -5542,9 +5732,145 @@ CK_DEFINE_FUNCTION(CK_RV, C_UnwrapKey)
uint16_t target_id = 0;
yh_object_type target_type = 0;
- yh_rc yrc = yh_util_import_wrapped(session->slot->device_session,
- key->object.id, pWrappedKey,
- ulWrappedKeyLen, &target_type, &target_id);
+ yh_rc yrc = YHR_SUCCESS;
+ if (pMechanism->mechanism == CKM_YUBICO_AES_CCM_WRAP) {
+ yrc = yh_util_import_wrapped(session->slot->device_session, key->object.id,
+ pWrappedKey, ulWrappedKeyLen, &target_type,
+ &target_id);
+ } else { // CKM_RSA_AES_KEY_WRAP or CKM_YUBICO_RSA_WRAP
+
+ if (pMechanism->pParameter == NULL ||
+ pMechanism->ulParameterLen != sizeof(CK_RSA_AES_KEY_WRAP_PARAMS)) {
+ DBG_ERR("Wrong mechanism parameter length");
+ rv = CKR_MECHANISM_PARAM_INVALID;
+ goto c_uk_out;
+ }
+
+ rsa_aes_key_wrap_params_t params = {0};
+ rv = parse_rsa_aes_key_wrap_params(pMechanism->pParameter, ¶ms);
+ if (rv != CKR_OK) {
+ goto c_uk_out;
+ }
+
+ if (pMechanism->mechanism == CKM_YUBICO_RSA_WRAP) {
+ yrc =
+ yh_util_import_rsa_wrapped(session->slot->device_session,
+ key->object.id, params.oaep_params.oaep_algo,
+ params.oaep_params.mgf_algo,
+ params.oaep_params.oaep_label,
+ params.oaep_params.oaep_label_len,
+ pWrappedKey, ulWrappedKeyLen, &target_type,
+ &target_id);
+ } else { // CKM_RSA_AES_KEY_WRAP
+
+ pkcs11_meta_object pkcs11meta;
+ yubihsm_pkcs11_object_template object_template = {0};
+ rv = parse_rsa_wrappedkey_template(pTemplate, ulAttributeCount,
+ &object_template, &pkcs11meta,
+ (CK_BYTE *) &target_type);
+ if (rv != CKR_OK) {
+ DBG_ERR("Failed to parse wrapped key template");
+ goto c_uk_out;
+ }
+
+ yh_capabilities capabilities = {{0}};
+ if (object_template.exportable == ATTRIBUTE_TRUE) {
+ yrc = yh_string_to_capabilities("exportable-under-wrap", &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = yrc_to_rv(yrc);
+ goto c_uk_out;
+ }
+ }
+ if (object_template.sign == ATTRIBUTE_TRUE) {
+ if (yh_is_rsa(object_template.algorithm)) {
+ yrc = yh_string_to_capabilities("sign-pkcs,sign-pss", &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = yrc_to_rv(yrc);
+ goto c_uk_out;
+ }
+ } else if (yh_is_ec(object_template.algorithm)) {
+ yrc = yh_string_to_capabilities("sign-ecdsa", &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = yrc_to_rv(yrc);
+ goto c_uk_out;
+ }
+ } else if (yh_is_ed(object_template.algorithm)) {
+ yrc = yh_string_to_capabilities("sign-eddsa", &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = yrc_to_rv(yrc);
+ goto c_uk_out;
+ }
+ } else {
+ DBG_ERR(
+ "Key type unsupported for unwrap or for signing capabilities");
+ rv = CKR_TEMPLATE_INCONSISTENT;
+ goto c_uk_out;
+ }
+ }
+ if (object_template.decrypt == ATTRIBUTE_TRUE) {
+ if (yh_is_rsa(object_template.algorithm)) {
+ yrc = yh_string_to_capabilities("decrypt-pkcs,decrypt-oaep",
+ &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = yrc_to_rv(yrc);
+ goto c_uk_out;
+ }
+ } else if (yh_is_aes(object_template.algorithm)) {
+ if (object_template.decrypt == ATTRIBUTE_TRUE) {
+ yrc = yh_string_to_capabilities("decrypt-ecb,decrypt-cbc",
+ &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = CKR_FUNCTION_FAILED;
+ goto c_uk_out;
+ }
+ }
+ } else {
+ DBG_ERR(
+ "Key type unsupported for unwrap or for decryptions capabilities");
+ rv = CKR_TEMPLATE_INCONSISTENT;
+ goto c_uk_out;
+ }
+ }
+ if (object_template.encrypt == ATTRIBUTE_TRUE) {
+ if (!yh_is_aes(object_template.algorithm)) {
+ DBG_ERR(
+ "Key type unsupported for unwrap or for encryption capabilities");
+ rv = CKR_TEMPLATE_INCONSISTENT;
+ goto c_uk_out;
+ }
+ yrc =
+ yh_string_to_capabilities("encrypt-ecb,encrypt-cbc", &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = CKR_FUNCTION_FAILED;
+ goto c_uk_out;
+ }
+ }
+ if (object_template.derive == ATTRIBUTE_TRUE) {
+ if (!yh_is_ec(object_template.algorithm)) {
+ DBG_ERR("Key type unsupported for unwrap or for ECDH derivation "
+ "capabilities");
+ rv = CKR_TEMPLATE_INCONSISTENT;
+ goto c_uk_out;
+ }
+ yrc = yh_string_to_capabilities("derive-ecdh", &capabilities);
+ if (yrc != YHR_SUCCESS) {
+ rv = yrc_to_rv(yrc);
+ goto c_uk_out;
+ }
+ }
+
+ yrc =
+ yh_util_put_rsa_wrapped_key(session->slot->device_session,
+ key->object.id, target_type, &target_id,
+ object_template.algorithm,
+ object_template.label, 0xffff,
+ &capabilities, params.oaep_params.oaep_algo,
+ params.oaep_params.mgf_algo,
+ params.oaep_params.oaep_label,
+ params.oaep_params.oaep_label_len,
+ pWrappedKey, ulWrappedKeyLen);
+ }
+ }
if (yrc != YHR_SUCCESS) {
DBG_ERR("Unwrapping failed: %s", yh_strerror(yrc));
rv = yrc_to_rv(yrc);
diff --git a/resources/tests/bash/test_wrapkey.sh b/resources/tests/bash/test_wrapkey.sh
index a379c7445..8fa3d3bf8 100755
--- a/resources/tests/bash/test_wrapkey.sh
+++ b/resources/tests/bash/test_wrapkey.sh
@@ -11,16 +11,33 @@ then
rm -rf yubihsm-shell_test_dir
fi
mkdir yubihsm-shell_test_dir; cd yubihsm-shell_test_dir
+
+test () {
+ set +e
+ $1 > output.txt 2>&1
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo $1
+ cat output.txt
+ rm output.txt
+ exit 1
+ else
+ echo "$2 ... OK!"
+ rm output.txt
+ fi
+ set -e
+}
+
set -e
-#set -x
+
echo "**********************************"
echo " aes128-ccm-wrap"
echo "**********************************"
echo "=== Generate on YubiHSM"
-$BIN -p password -a generate-wrap-key -i 0 -l "wrapkey" -d "1" -c "export-wrapped,import-wrapped" --delegated "export-wrapped,import-wrapped" -A "aes128-ccm-wrap"
-cat resp.txt
-keyid=$(tail -1 resp.txt | awk '{print $4}')
+keyid=0x0005
+$BIN -p password -a generate-wrap-key -i $keyid -l "wrapkey" -d "1" -c "export-wrapped,import-wrapped" --delegated "export-wrapped,import-wrapped" -A "aes128-ccm-wrap"
+echo keyid: $keyid
info=$($BIN -p password -a get-object-info -i $keyid -t wrap-key)
echo $info | grep "id: $keyid"
echo $info | grep "type: wrap-key"
@@ -33,6 +50,24 @@ echo $info | grep "delegated_capabilities: export-wrapped:import-wrapped"
echo "=== Delete key"
$BIN -p password -a delete-object -i $keyid -t wrap-key
+echo "**********************************"
+echo " aes128-ccm-wrap"
+echo "**********************************"
+test "$BIN -p password -a generate-asymmetric-key -i 100 -l ecKey -d 5,8,13 -c exportable-under-wrap -A ecp224" " Generate EC Key to wrap"
+test "$BIN -p password -a generate-wrap-key -i 200 -l wrapkey -d 5,8,13 -c all --delegated all -A rsa2048" " Generate RSA wrap key"
+test "$BIN -p password -a get-public-key -i 200 -t wrap-key --out public_wrapkey.pem" " Export rsa public wrap key"
+test "$BIN -p password -a put-public-wrapkey -i 200 --delegated all -c all --in public_wrapkey.pem" " Import RSA public wrap key"
+test "$BIN -p password -a get-rsa-wrapped --wrap-id 200 -i 100 -t asymmetric-key --out rsawrapped.object" " Export wrapped EC object"
+test "$BIN -p password -a get-rsa-wrapped-key --wrap-id 200 -i 100 -t asymmetric-key --out rsawrapped.key" " Export wrapped EC key"
+test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Delete original EC key"
+test "$BIN -p password -a put-rsa-wrapped --wrap-id 200 --in rsawrapped.object" " Import wrapped EC object"
+test "$BIN -p password -a put-rsa-wrapped-key --wrap-id 200 -i 300 -t asymmetric-key -A ecp224 --in rsawrapped.key" " Import wrapped EC key"
+test "$BIN -p password -a delete-object -i 100 -t asymmetric-key" " Delete EC key"
+test "$BIN -p password -a delete-object -i 300 -t asymmetric-key" " Delete EC key"
+test "$BIN -p password -a delete-object -i 200 -t wrap-key" " Delete RSA wrap key"
+test "$BIN -p password -a delete-object -i 200 -t public-wrap-key" " Delete public RSA wrap key"
+
+
cd ..
rm -rf yubihsm-shell_test_dir
diff --git a/src/cmdline.ggo b/src/cmdline.ggo
index 350d53033..63e41ccb1 100644
--- a/src/cmdline.ggo
+++ b/src/cmdline.ggo
@@ -43,6 +43,8 @@ option "action" a "Action to perform" values="benchmark",
"get-storage-info",
"get-template",
"get-wrapped",
+ "get-rsa-wrapped",
+ "get-rsa-wrapped-key",
"get-device-pubkey",
"list-objects",
"put-asymmetric-key",
@@ -54,7 +56,11 @@ option "action" a "Action to perform" values="benchmark",
"put-symmetric-key",
"put-template",
"put-wrap-key",
+ "put-rsa-wrapkey",
+ "put-public-wrapkey",
"put-wrapped",
+ "put-rsa-wrapped",
+ "put-rsa-wrapped-key",
"randomize-otp-aead",
"reset",
"set-log-index",
@@ -78,11 +84,14 @@ option "ykhsmauth-reader" r "Only use a matching YubiKey reader name" string opt
option "delegated" - "Delegated capabilities" string optional default="0"
option "new-password" - "New authentication password" string optional
option "algorithm" A "Operation algorithm" string optional default="any"
+option "oaep" - "OAEP algorithm. Used primarily with asymmetric wrap" string optional default="rsa-oaep-sha256"
+option "mgf1" - "MGF1 algorithm. Used primarily with asymmetric wrap" string optional default="mgf1-sha256"
option "nonce" - "OTP nonce" int optional
option "iv" - "An initialization vector as a hexadecimal string" string optional
option "count" - "Number of bytes to request" int optional default="256"
option "duration" - "Blink duration in seconds" int optional default="10"
option "wrap-id" - "Wrap key ID" int optional
+option "include-seed" - "Include seed when exporting an ED25519 key under wrap" flag off
option "template-id" - "Template ID" int optional
option "attestation-id" - "Attestation ID" int optional
option "log-index" - "Log index" int optional
diff --git a/src/commands.c b/src/commands.c
index 108a2ddff..8cb6b0868 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -711,7 +711,7 @@ int yh_com_echo(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
UNUSED(fmt);
uint8_t data[YH_MSG_BUF_SIZE] = {0};
- uint16_t data_len = 0;
+ size_t data_len = 0;
uint8_t response[YH_MSG_BUF_SIZE] = {0};
size_t response_len = 0;
@@ -1022,7 +1022,8 @@ int yh_com_get_storage(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
// argc = 3
// arg 0: e:session
// arg 1: w:key_id
-// arg 2: f:filename
+// arg 2: t:key_type
+// arg 3: f:filename
int yh_com_get_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
cmd_format fmt) {
@@ -1034,8 +1035,8 @@ int yh_com_get_pubkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
yh_algorithm algo = 0;
EVP_PKEY *public_key = NULL;
- yh_rc yrc = yh_util_get_public_key(argv[0].e, argv[1].w, response,
- &response_len, &algo);
+ yh_rc yrc = yh_util_get_public_key_ex(argv[0].e, argv[2].t, argv[1].w,
+ response, &response_len, &algo);
if (yrc != YHR_SUCCESS) {
fprintf(stderr, "Failed to get public key: %s\n", yh_strerror(yrc));
return -1;
@@ -1367,7 +1368,8 @@ int yh_com_get_object_info(yubihsm_context *ctx, Argument *argv,
// arg 1: w:keyid
// arg 2: t:type
// arg 3: w:id
-// arg 4: f:file
+// arg 4: b:include_seed
+// arg 5: f:file
int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
cmd_format fmt) {
uint8_t response[YH_MSG_BUF_SIZE] = {0};
@@ -1375,8 +1377,11 @@ int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
UNUSED(in_fmt);
- yh_rc yrc = yh_util_export_wrapped(argv[0].e, argv[1].w, argv[2].b, argv[3].w,
- response, &response_len);
+ uint8_t format = argv[4].b ? 1 : 0;
+
+ yh_rc yrc =
+ yh_util_export_wrapped_ex(argv[0].e, argv[1].w, argv[2].b, argv[3].w,
+ format, response, &response_len);
if (yrc != YHR_SUCCESS) {
fprintf(stderr, "Failed to get wrapped object: %s\n", yh_strerror(yrc));
@@ -1390,6 +1395,96 @@ int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
return -1;
}
+// NOTE: Get an RSA wrapped key or object
+// argc = 7
+// arg 0: e:session
+// arg 1: w:keyid
+// arg 2: t:type
+// arg 3: w:id
+// arg 4: a:aes
+// arg 5: a:oaep
+// arg 6: a:mgf1
+// arg 7: f:file
+static int do_rsa_wrap(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
+ cmd_format fmt, bool key_wrap) {
+ UNUSED(in_fmt);
+
+ int hash = 0;
+ yh_algorithm aes = argv[4].a;
+ yh_algorithm oaep = argv[5].a;
+ yh_algorithm mgf1 = argv[6].a;
+ yh_rc yrc;
+
+ if (aes == 0) {
+ aes = YH_ALGO_AES256;
+ }
+
+ switch (oaep) {
+ case YH_ALGO_RSA_OAEP_SHA1:
+ hash = _SHA1;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA256:
+ hash = _SHA256;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA384:
+ hash = _SHA384;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA512:
+ hash = _SHA512;
+ break;
+
+ default:
+ fprintf(stderr, "Unrecognized OAEP algorithm\n");
+ return -1;
+ }
+
+ uint8_t label[64] = {0};
+ size_t label_len = sizeof(label);
+
+ if (hash_bytes(NULL, 0, hash, label, &label_len) == false) {
+ fprintf(stderr, "Unable to hash data\n");
+ return -1;
+ }
+
+ uint8_t response[YH_MSG_BUF_SIZE] = {0};
+ size_t response_len = sizeof(response);
+
+ if (key_wrap) {
+ yrc = yh_util_get_rsa_wrapped_key(argv[0].e, argv[1].w, argv[2].b,
+ argv[3].w, aes, oaep, mgf1, label,
+ label_len, response, &response_len);
+ } else {
+ yrc = yh_util_export_rsa_wrapped(argv[0].e, argv[1].w, argv[2].b, argv[3].w,
+ aes, oaep, mgf1, label, label_len,
+ response, &response_len);
+ }
+
+ if (yrc != YHR_SUCCESS) {
+ fprintf(stderr, "Failed to encrypt data with OAEP: %s\n", yh_strerror(yrc));
+ return yrc;
+ }
+
+ if (!write_file(response, response_len, ctx->out, fmt_to_fmt(fmt))) {
+ fprintf(stderr, "Failed to write wrapped object to file");
+ return YHR_GENERIC_ERROR;
+ }
+
+ return YHR_SUCCESS;
+}
+
+int yh_com_get_rsa_wrapped(yubihsm_context *ctx, Argument *argv,
+ cmd_format in_fmt, cmd_format fmt) {
+ return do_rsa_wrap(ctx, argv, in_fmt, fmt, false);
+}
+
+int yh_com_get_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv,
+ cmd_format in_fmt, cmd_format fmt) {
+ return do_rsa_wrap(ctx, argv, in_fmt, fmt, true);
+}
+
// NOTE(adma): Get a template object
// argc = 2
// arg 0: e:session,
@@ -1990,7 +2085,7 @@ int yh_com_put_symmetric(yubihsm_context *ctx, Argument *argv,
// arg 2: s:label
// arg 3: w:domains
// arg 4: c:capabilities
-// arg 5: i:key
+// arg 5: x:key
int yh_com_put_asymmetric(yubihsm_context *ctx, Argument *argv,
cmd_format in_fmt, cmd_format fmt) {
@@ -2284,6 +2379,7 @@ int yh_com_put_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
UNUSED(ctx);
UNUSED(in_fmt);
UNUSED(fmt);
+
yh_algorithm algo = 0;
if (argv[6].len == 16) {
@@ -2310,6 +2406,140 @@ int yh_com_put_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
return 0;
}
+// NOTE: Store an RSA wrapping key
+// argc = 6
+// arg 0: e:session
+// arg 1: w:key_id
+// arg 2: s:label
+// arg 3: w:domains
+// arg 4: c:capabilities
+// arg 5: c:delegated_capabilities
+// arg 6: x:key
+int yh_com_put_rsa_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
+ cmd_format fmt) {
+ UNUSED(ctx);
+ UNUSED(in_fmt);
+ UNUSED(fmt);
+
+ uint8_t key[512] = {0};
+ size_t key_material_len = sizeof(key);
+ yh_algorithm algo = 0;
+
+ bool ret = read_private_key(argv[6].x, argv[6].len, &algo, key,
+ &key_material_len, false);
+ if (ret == false) {
+ fprintf(stderr, "Unable to read wrap key\n");
+ return -1;
+ }
+
+ yh_rc yrc = yh_util_import_wrap_key(argv[0].e, &argv[1].w, argv[2].s,
+ argv[3].w, &argv[4].c, algo, &argv[5].c,
+ key, key_material_len);
+ if (yrc != YHR_SUCCESS) {
+ fprintf(stderr, "Failed to store wrapkey: %s\n", yh_strerror(yrc));
+ return -1;
+ }
+
+ fprintf(stderr, "Stored Wrap key 0x%04x\n", argv[1].w);
+
+ return 0;
+}
+
+static bool read_rsa_pubkey(const uint8_t *buf, size_t len,
+ uint8_t *bytes, size_t *bytes_len) {
+ BIO *bio;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return false;
+
+ (void) BIO_write(bio, buf, len);
+
+ RSA *rsa = NULL;
+ EVP_PKEY *pubkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
+ BIO_free_all(bio);
+
+ if (pubkey == NULL || EVP_PKEY_base_id(pubkey) != EVP_PKEY_RSA ||
+ (rsa = EVP_PKEY_get1_RSA(pubkey)) == NULL) {
+ fprintf(stderr, "Failed to parse RSA public key\n");
+ EVP_PKEY_free(pubkey);
+ return false;
+ }
+
+ bool ret = false;
+ const BIGNUM *n = NULL;
+ RSA_get0_key(rsa, &n, NULL, NULL);
+ if (n == NULL) {
+ goto fail;
+ }
+
+ size_t nn = BN_num_bytes(n);
+ if (*bytes_len < nn) {
+ fprintf(stderr, "%s: insufficient dst buffer space\n", __func__);
+ goto fail;
+ }
+
+ *bytes_len = (size_t) BN_bn2bin(n, bytes);
+
+ ret = true;
+fail:
+ RSA_free(rsa);
+ EVP_PKEY_free(pubkey);
+ return ret;
+
+}
+
+// NOTE: Store a public wrap key
+// argc = 6
+// arg 0: e:session
+// arg 1: w:key_id
+// arg 2: s:label
+// arg 3: w:domains
+// arg 4: c:capabilities
+// arg 5: c:delegated_capabilities
+// arg 6: i:pubkey
+int yh_com_put_public_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
+ cmd_format fmt) {
+ UNUSED(ctx);
+ UNUSED(in_fmt);
+ UNUSED(fmt);
+
+ uint8_t pubkey[512];
+ size_t pubkey_len = sizeof(pubkey);
+ yh_algorithm algo = 0;
+
+ if (!read_rsa_pubkey(argv[6].x, argv[6].len, pubkey, &pubkey_len)) {
+ fprintf(stderr, "Failed to read public key\n");
+ return -1;
+ }
+
+ switch (pubkey_len) {
+ case 256:
+ algo = YH_ALGO_RSA_2048;
+ break;
+ case 384:
+ algo = YH_ALGO_RSA_3072;
+ break;
+ case 512:
+ algo = YH_ALGO_RSA_4096;
+ break;
+ default:
+ fprintf(stderr, "Invalid public key length (%zu)\n", pubkey_len);
+ return -1;
+ }
+
+ yh_rc yrc = yh_util_import_public_wrap_key(argv[0].e, &argv[1].w, argv[2].s,
+ argv[3].w, &argv[4].c, algo,
+ &argv[5].c, pubkey, pubkey_len);
+ if (yrc != YHR_SUCCESS) {
+ fprintf(stderr, "Failed to store public wrap key: %s\n", yh_strerror(yrc));
+ return -1;
+ }
+
+ fprintf(stderr, "Stored public wrap key 0x%04x\n", argv[1].w);
+
+ return 0;
+}
+
// NOTE: Store a wrapped object
// argc = 3
// arg 0: e:session
@@ -2339,6 +2569,146 @@ int yh_com_put_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
return 0;
}
+// NOTE: Store an asymetrically wrapped object
+// argc = 3
+// arg 0: e:session
+// arg 1: w:key_id
+// arg 2: a:oaep
+// arg 3: a:mgf1
+// arg 4: i:data
+int yh_com_put_rsa_wrapped(yubihsm_context *ctx, Argument *argv,
+ cmd_format in_fmt, cmd_format fmt) {
+ UNUSED(ctx);
+ UNUSED(in_fmt);
+ UNUSED(fmt);
+
+ yh_object_type object_type = 0;
+ uint16_t object_id = 0;
+
+ yh_algorithm mgf1 = argv[3].a;
+ yh_algorithm oaep = argv[2].a;
+ int hash = 0;
+
+ switch (oaep) {
+ case YH_ALGO_RSA_OAEP_SHA1:
+ hash = _SHA1;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA256:
+ hash = _SHA256;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA384:
+ hash = _SHA384;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA512:
+ hash = _SHA512;
+ break;
+
+ default:
+ fprintf(stderr, "Unrecognized OAEP algorithm\n");
+ return -1;
+ }
+
+ uint8_t label[64] = {0};
+ size_t label_len = sizeof(label);
+
+ if (hash_bytes(NULL, 0, hash, label, &label_len) == false) {
+ fprintf(stderr, "Unable to hash data.\n");
+ return -1;
+ }
+
+ yh_rc yrc = yh_util_import_rsa_wrapped(argv[0].e, argv[1].w, oaep, mgf1,
+ label, label_len, argv[4].x,
+ argv[4].len, &object_type, &object_id);
+ if (yrc != YHR_SUCCESS) {
+ fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc));
+ return -1;
+ }
+
+ const char *type = "";
+ yh_type_to_string(object_type, &type);
+
+ fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type);
+
+ return 0;
+}
+
+// NOTE: Store an asymetrically wrapped key object
+// argc = 3
+// arg 0: e:session
+// arg 1: w:wrapkey_id
+// arg 2: t:type
+// arg 3: w:key_id
+// arg 4: a:key_algorithm
+// arg 5: s:label
+// arg 6: w:domains
+// arg 7: c:capabilities
+// arg 8: a:oaep
+// arg 9: a:mgf1
+// arg 10: i:data
+int yh_com_put_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv,
+ cmd_format in_fmt, cmd_format fmt) {
+ UNUSED(ctx);
+ UNUSED(in_fmt);
+ UNUSED(fmt);
+
+ yh_object_type object_type = argv[2].t;
+ uint16_t object_id = argv[3].w;
+
+ yh_algorithm mgf1 = argv[9].a;
+ yh_algorithm oaep = argv[8].a;
+ int hash = 0;
+
+ switch (oaep) {
+ case YH_ALGO_RSA_OAEP_SHA1:
+ hash = _SHA1;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA256:
+ hash = _SHA256;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA384:
+ hash = _SHA384;
+ break;
+
+ case YH_ALGO_RSA_OAEP_SHA512:
+ hash = _SHA512;
+ break;
+
+ default:
+ fprintf(stderr, "Unrecognized OAEP algorithm\n");
+ return -1;
+ }
+
+ uint8_t label[64] = {0};
+ size_t label_len = sizeof(label);
+
+ if (hash_bytes(NULL, 0, hash, label, &label_len) == false) {
+ fprintf(stderr, "Unable to hash data\n");
+ return -1;
+ }
+
+ yh_rc yrc =
+ yh_util_put_rsa_wrapped_key(argv[0].e, argv[1].w, object_type, &object_id,
+ argv[4].a, argv[5].s, argv[6].w, &argv[7].c,
+ oaep, mgf1, label, label_len, argv[10].x,
+ argv[10].len);
+ if (yrc != YHR_SUCCESS) {
+ fprintf(stderr, "Failed to store wrapped object: %s\n", yh_strerror(yrc));
+ return -1;
+ }
+
+ const char *type = "";
+ yh_type_to_string(object_type, &type);
+
+ fprintf(stderr, "Object imported as 0x%04x of type %s\n", object_id, type);
+
+ return 0;
+}
+
// NOTE(adma): Store a template object
// argc = 7
// arg 0: e:session
@@ -2604,6 +2974,7 @@ int yh_com_get_device_info(yubihsm_context *ctx, Argument *argv,
yh_algorithm algorithms[YH_MAX_ALGORITHM_COUNT] = {0};
size_t n_algorithms = sizeof(algorithms);
+
yh_rc yrc =
yh_util_get_device_info(ctx->connector, &major, &minor, &patch, &serial,
&log_total, &log_used, algorithms, &n_algorithms);
@@ -2627,6 +2998,14 @@ int yh_com_get_device_info(yubihsm_context *ctx, Argument *argv,
}
fprintf(ctx->out, "\n");
+ char part_number[256] = {0};
+ size_t part_number_len = sizeof(part_number);
+ yrc =
+ yh_util_get_partnumber(ctx->connector, part_number, &part_number_len);
+ if (yrc == YHR_SUCCESS && part_number_len > 0) {
+ fprintf(ctx->out, "Part number:\t\t%s\n", part_number);
+ }
+
return 0;
}
diff --git a/src/commands.h b/src/commands.h
index 4f68c56b2..76146d213 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -112,6 +112,8 @@ int yh_com_get_object_info(yubihsm_context *ctx, Argument *argv,
cmd_format in_fmt, cmd_format fmt);
int yh_com_get_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
cmd_format fmt);
+int yh_com_get_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt);
+int yh_com_get_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt, cmd_format fmt);
int yh_com_get_device_info(yubihsm_context *ctx, Argument *argv,
cmd_format in_fmt, cmd_format fmt);
int yh_com_get_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
@@ -152,8 +154,16 @@ int yh_com_put_hmac(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
cmd_format fmt);
int yh_com_put_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
cmd_format fmt);
+int yh_com_put_rsa_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
+ cmd_format fmt);
+int yh_com_put_public_wrapkey(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
+ cmd_format fmt);
int yh_com_put_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
cmd_format fmt);
+int yh_com_put_rsa_wrapped(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
+ cmd_format fmt);
+int yh_com_put_rsa_wrapped_key(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
+ cmd_format fmt);
int yh_com_put_template(yubihsm_context *ctx, Argument *argv, cmd_format in_fmt,
cmd_format fmt);
int yh_com_put_otp_aead_key(yubihsm_context *ctx, Argument *argv,
diff --git a/src/main.c b/src/main.c
index 4a4abe0cd..172b80890 100644
--- a/src/main.c
+++ b/src/main.c
@@ -388,7 +388,7 @@ static void create_command_list(CommandList *c) {
fmt_nofmt, fmt_nofmt, "Get storages stats",
NULL, NULL});
register_subcommand(*c, (Command){"pubkey", yh_com_get_pubkey,
- "e:session,w:key_id,F:file=-", fmt_nofmt,
+ "e:session,w:key_id,t:key_type=asymmetric-key,F:file=-", fmt_nofmt,
fmt_PEM, "Get a public key", NULL, NULL});
register_subcommand(*c,
(Command){"objectinfo", yh_com_get_object_info,
@@ -396,9 +396,19 @@ static void create_command_list(CommandList *c) {
"Get information about an object", NULL, NULL});
register_subcommand(*c,
(Command){"wrapped", yh_com_get_wrapped,
- "e:session,w:wrapkey_id,t:type,w:id,F:file=-",
+ "e:session,w:wrapkey_id,t:type,w:id,b:include_seed=0,F:file=-",
fmt_nofmt, fmt_base64,
"Get an object under wrap", NULL, NULL});
+ register_subcommand(*c,
+ (Command){"rsa_wrapped", yh_com_get_rsa_wrapped,
+ "e:session,w:wrapkey_id,t:type,w:id,a:aes=aes256,a:hash=rsa-oaep-sha256,mgf1=mgf1-sha256,F:file=-",
+ fmt_nofmt, fmt_binary,
+ "Get an object under RSA wrap", NULL, NULL});
+ register_subcommand(*c,
+ (Command){"rsa_wrapped_key", yh_com_get_rsa_wrapped_key,
+ "e:session,w:wrapkey_id,t:type,w:id,a:aes=aes256,a:hash=rsa-oaep-sha256,mgf1=mgf1-sha256,F:file=-",
+ fmt_nofmt, fmt_binary,
+ "Get a (a)symmetric key under RSA wrap", NULL, NULL});
register_subcommand(*c, (Command){"deviceinfo", yh_com_get_device_info, NULL,
fmt_nofmt, fmt_nofmt,
"Extract the version number, serial number "
@@ -493,10 +503,30 @@ static void create_command_list(CommandList *c) {
"capabilities,c:delegated_capabilities,i:key",
fmt_hex, fmt_nofmt, "Store a wrapping key",
NULL, NULL});
+ register_subcommand(*c,
+ (Command){"rsa_wrapkey", yh_com_put_rsa_wrapkey,
+ "e:session,w:key_id,s:label,d:domains,c:"
+ "capabilities,c:delegated_capabilities,i:key=-",
+ fmt_PEM, fmt_nofmt, "Store an RSA wrapping key",
+ NULL, NULL});
+ register_subcommand(*c,
+ (Command){"pub_wrapkey", yh_com_put_public_wrapkey,
+ "e:session,w:key_id,s:label,d:domains,c:"
+ "capabilities,c:delegated_capabilities,i:key=-",
+ fmt_PEM, fmt_nofmt, "Store an RSA wrapping key",
+ NULL, NULL});
register_subcommand(*c, (Command){"wrapped", yh_com_put_wrapped,
"e:session,w:wrapkey_id,i:data=-",
fmt_base64, fmt_nofmt,
"Store a wrapped object", NULL, NULL});
+ register_subcommand(*c, (Command){"rsa_wrapped", yh_com_put_rsa_wrapped,
+ "e:session,w:wrapkey_id,a:hash=rsa-oaep-sha256,mgf1=mgf1-sha256,i:data=-",
+ fmt_binary, fmt_nofmt,
+ "Store a wrapped object", NULL, NULL});
+ register_subcommand(*c, (Command){"rsa_wrapped_key", yh_com_put_rsa_wrapped_key,
+ "e:session,w:wrapkey_id,t:type,w:key_id,a:algorithm,s:label,d:domains,c:capabilities,a:hash=rsa-oaep-sha256,mgf1=mgf1-sha256,i:data=-",
+ fmt_binary, fmt_nofmt,
+ "Store a wrapped object", NULL, NULL});
register_subcommand(*c, (Command){"template", yh_com_put_template,
"e:session,w:object_id,s:label,d:domains,c:"
"capabilities,a:algorithm,i:data=-",
@@ -2049,7 +2079,7 @@ int main(int argc, char *argv[]) {
}
}
- Argument arg[7];
+ Argument arg[11];
if (requires_session == true) {
uint8_t *buf = 0;
@@ -2362,8 +2392,14 @@ int main(int argc, char *argv[]) {
case action_arg_getMINUS_publicMINUS_key: {
arg[1].w = args_info.object_id_arg;
- arg[2].s = args_info.out_arg;
- arg[2].len = strlen(args_info.out_arg);
+ if(args_info.object_type_given) {
+ yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: ");
+ } else {
+ arg[2].t = YH_ASYMMETRIC_KEY;
+ }
+ arg[3].s = args_info.out_arg;
+ arg[3].len = strlen(args_info.out_arg);
comrc =
yh_com_get_pubkey(&g_ctx, arg, fmt_nofmt,
@@ -2412,8 +2448,10 @@ int main(int argc, char *argv[]) {
arg[3].w = args_info.object_id_arg;
- arg[4].s = args_info.out_arg;
- arg[4].len = strlen(args_info.out_arg);
+ arg[4].b = args_info.include_seed_given;
+
+ arg[5].s = args_info.out_arg;
+ arg[5].len = strlen(args_info.out_arg);
comrc =
yh_com_get_wrapped(&g_ctx, arg, fmt_nofmt,
@@ -2421,6 +2459,80 @@ int main(int argc, char *argv[]) {
COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object");
} break;
+ case action_arg_getMINUS_rsaMINUS_wrapped: {
+ if (args_info.object_type_given == 0) {
+ fprintf(stderr, "Missing argument object-type\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ if (args_info.wrap_id_given == 0) {
+ fprintf(stderr, "Missing argument wrap-id\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ arg[1].w = args_info.wrap_id_arg;
+ yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: ");
+
+ arg[3].w = args_info.object_id_arg;
+
+ yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: ");
+
+ yrc = yh_string_to_algo(args_info.oaep_arg, &arg[5].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: ");
+
+ yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[6].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: ");
+
+ arg[7].s = args_info.out_arg;
+ arg[7].len = strlen(args_info.out_arg);
+
+ comrc =
+ yh_com_get_rsa_wrapped(&g_ctx, arg, fmt_nofmt,
+ g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt);
+ COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object");
+ } break;
+
+ case action_arg_getMINUS_rsaMINUS_wrappedMINUS_key: {
+ if (args_info.object_type_given == 0) {
+ fprintf(stderr, "Missing argument object-type\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ if (args_info.wrap_id_given == 0) {
+ fprintf(stderr, "Missing argument wrap-id\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ arg[1].w = args_info.wrap_id_arg;
+ yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse type: ");
+
+ arg[3].w = args_info.object_id_arg;
+
+ yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse algorithm: ");
+
+ yrc = yh_string_to_algo(args_info.oaep_arg, &arg[5].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: ");
+
+ yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[6].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: ");
+
+ arg[7].s = args_info.out_arg;
+ arg[7].len = strlen(args_info.out_arg);
+
+ comrc =
+ yh_com_get_rsa_wrapped_key(&g_ctx, arg, fmt_nofmt,
+ g_out_fmt == fmt_nofmt ? fmt_binary : g_out_fmt);
+ COM_SUCCEED_OR_DIE(comrc, "Unable to get wrapped object");
+ } break;
+
case action_arg_getMINUS_deviceMINUS_info:
comrc = yh_com_get_device_info(&g_ctx, arg, fmt_nofmt, fmt_nofmt);
COM_SUCCEED_OR_DIE(comrc, "Unable to get device info");
@@ -2633,6 +2745,82 @@ int main(int argc, char *argv[]) {
COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey");
} break;
+ case action_arg_putMINUS_rsaMINUS_wrapkey: {
+
+ if (args_info.delegated_given == 0) {
+ fprintf(stderr, "Missing delegated capabilities\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ arg[1].w = args_info.object_id_arg;
+
+ arg[2].s = args_info.label_arg;
+ arg[2].len = strlen(args_info.label_arg);
+
+ yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: ");
+
+ memset(&arg[4].c, 0, sizeof(yh_capabilities));
+ yrc =
+ yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: ");
+
+ memset(&arg[5].c, 0, sizeof(yh_capabilities));
+ yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: ");
+
+ if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len,
+ g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) ==
+ false) {
+ fprintf(stderr, "Failed to get input data\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ comrc = yh_com_put_rsa_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt);
+ free(arg[6].x);
+ COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey");
+ } break;
+
+ case action_arg_putMINUS_publicMINUS_wrapkey: {
+
+ if (args_info.delegated_given == 0) {
+ fprintf(stderr, "Missing delegated capabilities\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ arg[1].w = args_info.object_id_arg;
+
+ arg[2].s = args_info.label_arg;
+ arg[2].len = strlen(args_info.label_arg);
+
+ yrc = yh_string_to_domains(args_info.domains_arg, &arg[3].w);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: ");
+
+ memset(&arg[4].c, 0, sizeof(yh_capabilities));
+ yrc =
+ yh_string_to_capabilities(args_info.capabilities_arg, &arg[4].c);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: ");
+
+ memset(&arg[5].c, 0, sizeof(yh_capabilities));
+ yrc = yh_string_to_capabilities(args_info.delegated_arg, &arg[5].c);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: ");
+
+ if (get_input_data(args_info.in_arg, &arg[6].x, &arg[6].len,
+ g_in_fmt == fmt_nofmt ? fmt_PEM : g_in_fmt) ==
+ false) {
+ fprintf(stderr, "Failed to get input data\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ comrc = yh_com_put_public_wrapkey(&g_ctx, arg, fmt_nofmt, fmt_nofmt);
+ free(arg[6].x);
+ COM_SUCCEED_OR_DIE(comrc, "Unable to put wrapkey");
+ } break;
+
case action_arg_putMINUS_symmetricMINUS_key: {
if (args_info.algorithm_given == 0) {
fprintf(stderr, "Missing argument algorithm\n");
@@ -2688,6 +2876,91 @@ int main(int argc, char *argv[]) {
COM_SUCCEED_OR_DIE(comrc, "Unable to store wrapped object");
} break;
+ case action_arg_putMINUS_rsaMINUS_wrapped: {
+ if (args_info.wrap_id_given == 0) {
+ fprintf(stderr, "Missing argument wrap-id\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ arg[1].w = args_info.wrap_id_arg;
+
+ yrc = yh_string_to_algo(args_info.oaep_arg, &arg[2].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: ");
+
+ yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[3].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: ");
+
+ if (get_input_data(args_info.in_arg, &arg[4].x, &arg[4].len,
+ g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) ==
+ false) {
+ fprintf(stderr, "Failed to get input data\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ comrc = yh_com_put_rsa_wrapped(&g_ctx, arg, fmt_nofmt, fmt_nofmt);
+ free(arg[4].x);
+ COM_SUCCEED_OR_DIE(comrc, "Unable to store RSA wrapped object");
+ } break;
+
+ case action_arg_putMINUS_rsaMINUS_wrappedMINUS_key: {
+ if (args_info.wrap_id_given == 0) {
+ fprintf(stderr, "Missing argument wrap-id\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ if (args_info.object_type_given == 0) {
+ fprintf(stderr, "Missing argument type\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ if (args_info.algorithm_given == 0) {
+ fprintf(stderr, "Missing argument key-algorithm\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ arg[1].w = args_info.wrap_id_arg;
+
+ yrc = yh_string_to_type(args_info.object_type_arg, &arg[2].t);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse object type: ");
+
+ arg[3].w = args_info.object_id_arg;
+
+ yrc = yh_string_to_algo(args_info.algorithm_arg, &arg[4].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse key algorithm: ");
+
+ arg[5].s = args_info.label_arg;
+ arg[5].len = strlen(args_info.label_arg);
+
+ yrc = yh_string_to_domains(args_info.domains_arg, &arg[6].w);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse domains: ");
+
+ yrc = yh_string_to_capabilities(args_info.capabilities_arg, &arg[7].c);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse capabilities: ");
+
+ yrc = yh_string_to_algo(args_info.oaep_arg, &arg[8].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse OAEP algorithm: ");
+
+ yrc = yh_string_to_algo(args_info.mgf1_arg, &arg[9].a);
+ LIB_SUCCEED_OR_DIE(yrc, "Unable to parse MGF1 algorithm: ");
+
+ if (get_input_data(args_info.in_arg, &arg[10].x, &arg[10].len,
+ g_in_fmt == fmt_nofmt ? fmt_binary : g_in_fmt) ==
+ false) {
+ fprintf(stderr, "Failed to get input data\n");
+ rc = EXIT_FAILURE;
+ break;
+ }
+
+ comrc = yh_com_put_rsa_wrapped_key(&g_ctx, arg, fmt_nofmt, fmt_nofmt);
+ free(arg[10].x);
+ COM_SUCCEED_OR_DIE(comrc, "Unable to store RSA wrapped object");
+ } break;
+
case action_arg_putMINUS_template: {
if (args_info.algorithm_given == 0) {
fprintf(stderr, "Missing argument algorithm\n");