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(
"Engine command failed: SO_PATH ") + pkcs11Path.string());
96 if (ENGINE_ctrl_cmd_string(engine,
"ID",
"pkcs11", 0) == 0) {
97 throw std::runtime_error(
"Engine command failed: ID pksc11");
100 if (ENGINE_ctrl_cmd_string(engine,
"LIST_ADD",
"1", 0) == 0) {
101 throw std::runtime_error(
"Engine command failed: LIST_ADD 1");
104 if (ENGINE_ctrl_cmd_string(engine,
"LOAD",
nullptr, 0) == 0) {
105 throw std::runtime_error(
"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(
"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(
"Engine command failed: PIN"));
116 if (ENGINE_init(engine) == 0) {
117 throw std::runtime_error(
"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;
207 long length = BIO_get_mem_data(mem.get(), &pem_key);
208 key_out->assign(pem_key, static_cast<size_t>(length));
213 bool P11Engine::generateUptaneKeyPair() {
214 PKCS11_SLOT* slot = findTokenSlot();
215 if (slot ==
nullptr) {
219 std::vector<unsigned char> id_hex;
220 boost::algorithm::unhex(config_.uptane_key_id, std::back_inserter(id_hex));
227 StructGuard<EVP_PKEY> pkey = Crypto::generateRSAKeyPairEVP(KeyType::kRSA2048);
228 if (pkey ==
nullptr) {
229 LOG_ERROR <<
"Error generating keypair on the device:" << ERR_error_string(ERR_get_error(),
nullptr);
233 if (PKCS11_store_private_key(slot->token, pkey.get(),
nullptr, id_hex.data(), id_hex.size()) != 0) {
234 LOG_ERROR <<
"Could not store private key on the token";
237 if (PKCS11_store_public_key(slot->token, pkey.get(),
nullptr, id_hex.data(), id_hex.size()) != 0) {
238 LOG_ERROR <<
"Could not store public key on the token";
245 bool P11Engine::readTlsCert(std::string* cert_out)
const {
246 const std::string&
id = config_.tls_clientcert_id;
248 if (config_.module.empty()) {
251 if ((
id.length() % 2) != 0U) {
255 PKCS11_SLOT* slot = findTokenSlot();
256 if (slot ==
nullptr) {
262 int rc = PKCS11_enumerate_certs(slot->token, &certs, &ncerts);
264 LOG_ERROR <<
"Error enumerating certificates in PKCS11 device: " << ERR_error_string(ERR_get_error(),
nullptr);
268 PKCS11_CERT* cert =
nullptr;
270 std::vector<unsigned char> id_hex;
271 boost::algorithm::unhex(
id, std::back_inserter(id_hex));
273 for (
unsigned int i = 0; i < ncerts; i++) {
275 if ((certs[i].id_len ==
id.length() / 2) && (memcmp(certs[i].
id, id_hex.data(),
id.length() / 2) == 0)) {
282 if (cert ==
nullptr) {
283 LOG_ERROR <<
"Requested certificate was not found";
286 StructGuard<BIO> mem(BIO_new(BIO_s_mem()), BIO_vfree);
287 PEM_write_bio_X509(mem.get(), cert->x509);
289 char* pem_key =
nullptr;
290 long length = BIO_get_mem_data(mem.get(), &pem_key);
291 cert_out->assign(pem_key, static_cast<size_t>(length));