8 #include <openssl/evp.h>
9 #include <openssl/pem.h>
10 #include <boost/algorithm/hex.hpp>
11 #include <boost/filesystem.hpp>
12 #include <boost/scoped_array.hpp>
14 #include "crypto/crypto.h"
15 #include "utilities/config_utils.h"
16 #include "utilities/utils.h"
18 P11Engine* P11EngineGuard::instance =
nullptr;
19 int P11EngineGuard::ref_counter = 0;
21 P11ContextWrapper::P11ContextWrapper(
const boost::filesystem::path& module) {
27 ctx = PKCS11_CTX_new();
28 if (PKCS11_CTX_load(ctx, module.c_str()) != 0) {
30 LOG_ERROR <<
"Couldn't load PKCS11 module " << module.string() <<
": "
31 << ERR_error_string(ERR_get_error(),
nullptr);
32 throw std::runtime_error(
"PKCS11 error");
36 P11ContextWrapper::~P11ContextWrapper() {
38 PKCS11_CTX_unload(ctx);
43 P11SlotsWrapper::P11SlotsWrapper(PKCS11_ctx_st* ctx_in) {
50 if (PKCS11_enumerate_slots(ctx, &wslots_, &nslots) != 0) {
51 LOG_ERROR <<
"Couldn't enumerate slots"
52 <<
": " << ERR_error_string(ERR_get_error(),
nullptr);
53 throw std::runtime_error(
"PKCS11 error");
57 P11SlotsWrapper::~P11SlotsWrapper() {
58 if ((wslots_ !=
nullptr) && (nslots != 0U)) {
59 PKCS11_release_all_slots(ctx, wslots_, nslots);
63 P11Engine::P11Engine(
P11Config config) : config_(std::move(config)), ctx_(config_.module), slots_(ctx_.get()) {
64 if (config_.module.empty()) {
68 PKCS11_SLOT* slot = PKCS11_find_token(ctx_.get(), slots_.get_slots(), slots_.get_nslots());
69 if ((slot ==
nullptr) || (slot->token ==
nullptr)) {
70 throw std::runtime_error(
"Couldn't find pkcs11 token");
73 LOG_DEBUG <<
"Slot manufacturer......: " << slot->manufacturer;
74 LOG_DEBUG <<
"Slot description.......: " << slot->description;
75 LOG_DEBUG <<
"Slot token label.......: " << slot->token->label;
76 LOG_DEBUG <<
"Slot token manufacturer: " << slot->token->manufacturer;
77 LOG_DEBUG <<
"Slot token model.......: " << slot->token->model;
78 LOG_DEBUG <<
"Slot token serialnr....: " << slot->token->serialnr;
80 uri_prefix_ = std::string(
"pkcs11:serial=") + slot->token->serialnr +
";pin-value=" + config_.pass +
";id=%";
82 ENGINE_load_builtin_engines();
83 ENGINE* engine = ENGINE_by_id(
"dynamic");
85 if (engine ==
nullptr) {
86 throw std::runtime_error(
"SSL pkcs11 engine initialization failed");
90 const boost::filesystem::path pkcs11Path = findPkcsLibrary();
91 LOG_INFO <<
"Loading PKCS#11 engine library: " << pkcs11Path.string();
92 if (ENGINE_ctrl_cmd_string(engine,
"SO_PATH", pkcs11Path.c_str(), 0) == 0) {
93 throw std::runtime_error(std::string(
"P11 engine command failed: SO_PATH ") + pkcs11Path.string());
96 if (ENGINE_ctrl_cmd_string(engine,
"ID",
"pkcs11", 0) == 0) {
97 throw std::runtime_error(
"P11 engine command failed: ID pksc11");
100 if (ENGINE_ctrl_cmd_string(engine,
"LIST_ADD",
"1", 0) == 0) {
101 throw std::runtime_error(
"P11 engine command failed: LIST_ADD 1");
104 if (ENGINE_ctrl_cmd_string(engine,
"LOAD",
nullptr, 0) == 0) {
105 throw std::runtime_error(
"P11 engine command failed: LOAD");
108 if (ENGINE_ctrl_cmd_string(engine,
"MODULE_PATH", config_.module.c_str(), 0) == 0) {
109 throw std::runtime_error(std::string(
"P11 engine command failed: MODULE_PATH ") + config_.module.string());
112 if (ENGINE_ctrl_cmd_string(engine,
"PIN", config_.pass.c_str(), 0) == 0) {
113 throw std::runtime_error(std::string(
"P11 engine command failed: PIN"));
116 if (ENGINE_init(engine) == 0) {
117 throw std::runtime_error(
"P11 engine initialization failed");
119 }
catch (
const std::runtime_error& exc) {
127 ssl_engine_ = engine;
130 boost::filesystem::path P11Engine::findPkcsLibrary() {
131 static const boost::filesystem::path engine_path = PKCS11_ENGINE_PATH;
133 if (!boost::filesystem::exists(engine_path)) {
134 LOG_ERROR <<
"PKCS11 engine not available (" << engine_path <<
")";
141 PKCS11_SLOT* P11Engine::findTokenSlot()
const {
142 PKCS11_SLOT* slot = PKCS11_find_token(ctx_.get(), slots_.get_slots(), slots_.get_nslots());
143 if ((slot ==
nullptr) || (slot->token ==
nullptr)) {
144 LOG_ERROR <<
"Couldn't find a token";
148 PKCS11_is_logged_in(slot, 1, &rv);
150 if (PKCS11_open_session(slot, 1) != 0) {
151 LOG_ERROR <<
"Error creating rw session in to the slot: " << ERR_error_string(ERR_get_error(),
nullptr);
154 if (PKCS11_login(slot, 0, config_.pass.c_str()) != 0) {
155 LOG_ERROR <<
"Error logging in to the token: " << ERR_error_string(ERR_get_error(),
nullptr);
162 bool P11Engine::readUptanePublicKey(std::string* key_out) {
163 if (config_.module.empty()) {
166 if ((config_.uptane_key_id.length() % 2) != 0U) {
170 PKCS11_SLOT* slot = findTokenSlot();
171 if (slot ==
nullptr) {
177 int rc = PKCS11_enumerate_public_keys(slot->token, &keys, &nkeys);
179 LOG_ERROR <<
"Error enumerating public keys in PKCS11 device: " << ERR_error_string(ERR_get_error(),
nullptr);
182 PKCS11_KEY* key =
nullptr;
184 std::vector<unsigned char> id_hex;
185 boost::algorithm::unhex(config_.uptane_key_id, std::back_inserter(id_hex));
187 for (
unsigned int i = 0; i < nkeys; i++) {
189 if ((keys[i].id_len == config_.uptane_key_id.length() / 2) &&
191 (memcmp(keys[i].
id, id_hex.data(), config_.uptane_key_id.length() / 2) == 0)) {
198 if (key ==
nullptr) {
199 LOG_ERROR <<
"Requested public key was not found";
202 StructGuard<EVP_PKEY> evp_key(PKCS11_get_public_key(key), EVP_PKEY_free);
203 StructGuard<BIO> mem(BIO_new(BIO_s_mem()), BIO_vfree);
204 PEM_write_bio_PUBKEY(mem.get(), evp_key.get());
206 char* pem_key =
nullptr;
208 long length = BIO_get_mem_data(mem.get(), &pem_key);
209 key_out->assign(pem_key,
static_cast<size_t>(length));
214 bool P11Engine::generateUptaneKeyPair() {
215 PKCS11_SLOT* slot = findTokenSlot();
216 if (slot ==
nullptr) {
220 std::vector<unsigned char> id_hex;
221 boost::algorithm::unhex(config_.uptane_key_id, std::back_inserter(id_hex));
228 StructGuard<EVP_PKEY> pkey = Crypto::generateRSAKeyPairEVP(KeyType::kRSA2048);
229 if (pkey ==
nullptr) {
230 LOG_ERROR <<
"Error generating keypair on the device:" << ERR_error_string(ERR_get_error(),
nullptr);
234 if (PKCS11_store_private_key(slot->token, pkey.get(),
nullptr, id_hex.data(), id_hex.size()) != 0) {
235 LOG_ERROR <<
"Could not store private key on the token";
238 if (PKCS11_store_public_key(slot->token, pkey.get(),
nullptr, id_hex.data(), id_hex.size()) != 0) {
239 LOG_ERROR <<
"Could not store public key on the token";
246 bool P11Engine::readTlsCert(std::string* cert_out)
const {
247 const std::string&
id = config_.tls_clientcert_id;
249 if (config_.module.empty()) {
252 if ((
id.length() % 2) != 0U) {
256 PKCS11_SLOT* slot = findTokenSlot();
257 if (slot ==
nullptr) {
263 int rc = PKCS11_enumerate_certs(slot->token, &certs, &ncerts);
265 LOG_ERROR <<
"Error enumerating certificates in PKCS11 device: " << ERR_error_string(ERR_get_error(),
nullptr);
269 PKCS11_CERT* cert =
nullptr;
271 std::vector<unsigned char> id_hex;
272 boost::algorithm::unhex(
id, std::back_inserter(id_hex));
274 for (
unsigned int i = 0; i < ncerts; i++) {
276 if ((certs[i].id_len ==
id.length() / 2) && (memcmp(certs[i].
id, id_hex.data(),
id.length() / 2) == 0)) {
283 if (cert ==
nullptr) {
284 LOG_ERROR <<
"Requested certificate was not found";
287 StructGuard<BIO> mem(BIO_new(BIO_s_mem()), BIO_vfree);
288 PEM_write_bio_X509(mem.get(), cert->x509);
290 char* pem_key =
nullptr;
292 long length = BIO_get_mem_data(mem.get(), &pem_key);
293 cert_out->assign(pem_key,
static_cast<size_t>(length));