Skip to content

Commit

Permalink
add support for pkcs11 engine signing
Browse files Browse the repository at this point in the history
  • Loading branch information
embetrix committed Dec 13, 2024
1 parent d8ff0a3 commit 858bd4a
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cmake-single-platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- uses: actions/checkout@v4

- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y openssl libssl-dev python3
run: sudo apt-get update && sudo apt-get install -y openssl libssl-dev python3 softhsm2
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
Expand Down
90 changes: 72 additions & 18 deletions stm32mp-sign-tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/ecdsa.h>
#include <openssl/engine.h>

static bool verbose = false;
static ENGINE* engine = nullptr;

struct STM32Header {
char magic[4];
Expand Down Expand Up @@ -108,23 +110,70 @@ void print_hex(const std::string& label, const std::vector<unsigned char>& data)
std::cout << std::endl;
}

EC_KEY* load_key(const char* key_file) {
FILE* key_fp = fopen(key_file, "r");
if (!key_fp) {
throw std::runtime_error("Failed to open key file");
}
EC_KEY* load_key(const char* key_file, const char* passphrase) {
if (std::strncmp(key_file, "pkcs11:", 7) == 0) {
// Load key using PKCS#11
EC_KEY* ec_key = nullptr;

EC_KEY* key = PEM_read_ECPrivateKey(key_fp, nullptr, nullptr, nullptr);
fclose(key_fp);
if (!key) {
throw std::runtime_error("Failed to read key");
}
// Load the engine
ENGINE_load_builtin_engines();
engine = ENGINE_by_id("pkcs11");
if (!engine) {
throw std::runtime_error("Failed to load PKCS#11 engine");
}

// Initialize the engine
if (!ENGINE_init(engine)) {
ENGINE_free(engine);
throw std::runtime_error("Failed to initialize PKCS#11 engine");
}

// Set the PIN
if (passphrase && !ENGINE_ctrl_cmd_string(engine, "PIN", passphrase, 0)) {
ENGINE_finish(engine);
ENGINE_free(engine);
throw std::runtime_error("Failed to set PKCS#11 PIN");
}

// Load the private key
EVP_PKEY* pkey = ENGINE_load_private_key(engine, key_file, nullptr, (void*)passphrase);
if (!pkey) {
ENGINE_finish(engine);
ENGINE_free(engine);
throw std::runtime_error("Failed to load private key from PKCS#11");
}

// Extract the EC_KEY from the EVP_PKEY
ec_key = EVP_PKEY_get1_EC_KEY(pkey);
EVP_PKEY_free(pkey);

return key;
if (!ec_key) {
ENGINE_finish(engine);
ENGINE_free(engine);
throw std::runtime_error("Failed to extract EC_KEY from EVP_PKEY");
}

return ec_key;
}
else {
// Load key from file
FILE* key_fp = fopen(key_file, "r");
if (!key_fp) {
throw std::runtime_error("Failed to open key file");
}

EC_KEY* key = PEM_read_ECPrivateKey(key_fp, nullptr, nullptr, (void*)passphrase);
fclose(key_fp);
if (!key) {
throw std::runtime_error("Failed to read key from file");
}

return key;
}
}

int verify_stm32_image(const std::vector<unsigned char>& image, const char* key_file) {
EC_KEY* key = load_key(key_file);
int verify_stm32_image(const std::vector<unsigned char>& image, const char* key_file, const char* passphrase) {
EC_KEY* key = load_key(key_file, passphrase);
STM32Header header = unpack_stm32_header(image);

if (std::strncmp(header.magic, "STM2", sizeof(header.magic)) != 0) {
Expand Down Expand Up @@ -196,8 +245,8 @@ int verify_stm32_image(const std::vector<unsigned char>& image, const char* key_
}
}

int sign_stm32_image(std::vector<unsigned char>& image, const char* key_file) {
EC_KEY* key = load_key(key_file);
int sign_stm32_image(std::vector<unsigned char>& image, const char* key_file, const char* passphrase) {
EC_KEY* key = load_key(key_file, passphrase);
STM32Header header = unpack_stm32_header(image);

if (std::strncmp(header.magic, "STM2", sizeof(header.magic)) != 0) {
Expand Down Expand Up @@ -264,7 +313,7 @@ int sign_stm32_image(std::vector<unsigned char>& image, const char* key_file) {
EC_KEY_free(key);

// Verify the signature
if (verify_stm32_image(image, key_file)) {
if (verify_stm32_image(image, key_file, passphrase)) {
return 1;
}

Expand Down Expand Up @@ -296,7 +345,7 @@ int main(int argc, char* argv[]) {
output_file = optarg;
break;
default:
std::cerr << "Usage: " << argv[0] << " -k key_file [-p passphrase] [-v] [-i input_file] [-o output_file]" << std::endl;
std::cerr << "Usage: " << argv[0] << " -k key_file [-p passphrase/pin] [-v] [-i input_file] [-o output_file]" << std::endl;
return 1;
}
}
Expand All @@ -311,7 +360,7 @@ int main(int argc, char* argv[]) {
std::vector<unsigned char> image((std::istreambuf_iterator<char>(image_file)), std::istreambuf_iterator<char>());
image_file.close();

if (sign_stm32_image(image, key_file) != 0) {
if (sign_stm32_image(image, key_file, passphrase) != 0) {
return 1;
}

Expand All @@ -322,5 +371,10 @@ int main(int argc, char* argv[]) {
}
}

if (engine) {
ENGINE_finish(engine);
ENGINE_free(engine);
}

return 0;
}
22 changes: 21 additions & 1 deletion stm32mp-sign-tool_test.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#!/bin/bash -e
#!/bin/sh -e
#
# Copyright (c) 2024
# Embetrix Embedded Systems Solutions, [email protected]
#


dd if=/dev/urandom of=image.bin bs=1M count=1 > /dev/null 2>&1
Expand All @@ -8,4 +12,20 @@ python3 stm32mp-gen-image.py image.stm32 image.bin
openssl ecparam -name prime256v1 -genkey -out private_key.pem
openssl ec -in private_key.pem -pubout -out public_key.pem

# test plain key file
./stm32mp-sign-tool -v -k private_key.pem -i image.stm32 -o image.stm32.signed

# test pkcs11 key
export PKCS11_MODULE_PATH=/usr/lib/softhsm/libsofthsm2.so
export PIN="12345"
export SO_PIN="1234"
export SOFTHSM2_CONF=$PWD/.softhsm/softhsm2.conf
export TOKEN_NAME="token0"

mkdir -p .softhsm/tokens
echo "directories.tokendir = $PWD/.softhsm/tokens" > .softhsm/softhsm2.conf
pkcs11-tool --pin $PIN --module $PKCS11_MODULE_PATH --slot-index=0 --init-token --label=$TOKEN_NAME --so-pin $SO_PIN --init-pin
pkcs11-tool --pin $PIN --module $PKCS11_MODULE_PATH --keypairgen --key-type EC:prime256v1 --id 1 --label "testkeyECp256"
./stm32mp-sign-tool -v -k "pkcs11:object=testkeyECp256" -i image.stm32 -p 12345 -o image.stm32.signed


0 comments on commit 858bd4a

Please sign in to comment.