# HG changeset patch # User Sebastien Jodogne # Date 1466421822 -7200 # Node ID e7e1858d950422bcbb974b074cc08b6d28ccdfa0 # Parent 944b255035a04ec62e6c0216c9725c5e98d2af6d reorganization diff -r 944b255035a0 -r e7e1858d9504 CMakeLists.txt --- a/CMakeLists.txt Sat Jun 18 12:03:32 2016 +0200 +++ b/CMakeLists.txt Mon Jun 20 13:23:42 2016 +0200 @@ -48,7 +48,7 @@ SET(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL") SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib") SET(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml") -SET(USE_SYSTEM_LIBP11 ON CACHE BOOL "Use the system version of libp11 (PKCS#11 wrapper library)") +SET(USE_SYSTEM_LIBP11 OFF CACHE BOOL "Use the system version of libp11 (PKCS#11 wrapper library)") # Experimental options SET(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)") @@ -334,8 +334,10 @@ if (ENABLE_PKCS11) if (ENABLE_SSL) + include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibP11Configuration.cmake) + add_definitions(-DORTHANC_PKCS11_ENABLED=1) - include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibP11Configuration.cmake) + list(APPEND ORTHANC_CORE_SOURCES Core/Pkcs11.cpp) else() message(FATAL_ERROR "OpenSSL is required to enable PKCS#11") endif() @@ -442,7 +444,6 @@ ) - ##################################################################### ## Build the Orthanc server ##################################################################### diff -r 944b255035a0 -r e7e1858d9504 Core/HttpClient.cpp --- a/Core/HttpClient.cpp Sat Jun 18 12:03:32 2016 +0200 +++ b/Core/HttpClient.cpp Mon Jun 20 13:23:42 2016 +0200 @@ -44,17 +44,7 @@ #if ORTHANC_PKCS11_ENABLED == 1 - -#include -#include - -// Include the "libengine-pkcs11-openssl" from the libp11 package -extern "C" -{ -#pragma GCC diagnostic error "-fpermissive" -#include -} - +# include "Pkcs11.h" #endif @@ -97,42 +87,10 @@ std::string httpsCACertificates_; std::string proxy_; long timeout_; - bool pkcs11Initialized_; - -#if ORTHANC_PKCS11_ENABLED == 1 - static ENGINE* LoadPkcs11Engine() - { - // This function mimics the "ENGINE_load_dynamic" function from - // OpenSSL, in file "crypto/engine/eng_dyn.c" - - ENGINE* engine = ENGINE_new(); - if (!engine) - { - LOG(ERROR) << "Cannot create an OpenSSL engine for PKCS11"; - throw OrthancException(ErrorCode_InternalError); - } - - if (!bind_helper(engine) || - !ENGINE_add(engine)) - { - LOG(ERROR) << "Cannot initialize the OpenSSL engine for PKCS11"; - ENGINE_free(engine); - throw OrthancException(ErrorCode_InternalError); - } - - // If the "ENGINE_add" worked, it gets a structural - // reference. We release our just-created reference. - ENGINE_free(engine); - - assert(!strcmp("pkcs11", PKCS11_ENGINE_ID)); - return ENGINE_by_id(PKCS11_ENGINE_ID); - } -#endif GlobalParameters() : httpsVerifyPeers_(true), - timeout_(0), - pkcs11Initialized_(false) + timeout_(0) { } @@ -192,66 +150,19 @@ return timeout_; } +#if ORTHANC_PKCS11_ENABLED == 1 bool IsPkcs11Initialized() { boost::mutex::scoped_lock lock(mutex_); - return pkcs11Initialized_; + return Pkcs11::IsInitialized(); } - -#if ORTHANC_PKCS11_ENABLED == 1 void InitializePkcs11(const std::string& module, const std::string& pin, bool verbose) { boost::mutex::scoped_lock lock(mutex_); - - if (pkcs11Initialized_) - { - LOG(ERROR) << "The PKCS11 engine has already been initialized"; - throw OrthancException(ErrorCode_BadSequenceOfCalls); - } - - if (module.empty() || - !Toolbox::IsRegularFile(module)) - { - LOG(ERROR) << "The PKCS11 module must be a path to one shared library (DLL or .so)"; - throw OrthancException(ErrorCode_InexistentFile); - } - - ENGINE* engine = LoadPkcs11Engine(); - if (!engine) - { - LOG(ERROR) << "Cannot create an OpenSSL engine for PKCS11"; - throw OrthancException(ErrorCode_InternalError); - } - - if (!ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", module.c_str(), 0)) - { - LOG(ERROR) << "Cannot configure the OpenSSL dynamic engine for PKCS11"; - throw OrthancException(ErrorCode_InternalError); - } - - if (verbose) - { - ENGINE_ctrl_cmd_string(engine, "VERBOSE", NULL, 0); - } - - if (!pin.empty() && - !ENGINE_ctrl_cmd_string(engine, "PIN", pin.c_str(), 0)) - { - LOG(ERROR) << "Cannot set the PIN code for PKCS11"; - throw OrthancException(ErrorCode_InternalError); - } - - if (!ENGINE_init(engine)) - { - LOG(ERROR) << "Cannot initialize the OpenSSL dynamic engine for PKCS11"; - throw OrthancException(ErrorCode_InternalError); - } - - LOG(WARNING) << "The PKCS11 engine has been successfully initialized"; - pkcs11Initialized_ = true; + Pkcs11::Initialize(module, pin, verbose); } #endif }; @@ -288,6 +199,13 @@ static CURLcode CheckCode(CURLcode code) { + if (code == CURLE_NOT_BUILT_IN) + { + LOG(ERROR) << "Your libcurl does not contain a required feature, " + << "please recompile Orthanc with -DUSE_SYSTEM_CURL=OFF"; + throw OrthancException(ErrorCode_InternalError); + } + if (code != CURLE_OK) { LOG(ERROR) << "libCURL error: " + std::string(curl_easy_strerror(code)); @@ -471,17 +389,17 @@ #if ORTHANC_PKCS11_ENABLED == 1 if (GlobalParameters::GetInstance().IsPkcs11Initialized()) { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLENGINE, "pkcs11")); + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLENGINE, Pkcs11::GetEngineIdentifier())); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEYTYPE, "ENG")); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "ENG")); } else { - LOG(ERROR) << "Cannot use PKCS11 for a HTTPS request, because it has not been initialized"; + LOG(ERROR) << "Cannot use PKCS#11 for a HTTPS request, because it has not been initialized"; throw OrthancException(ErrorCode_BadSequenceOfCalls); } #else - LOG(ERROR) << "This version of Orthanc is compiled without support for PKCS11"; + LOG(ERROR) << "This version of Orthanc is compiled without support for PKCS#11"; throw OrthancException(ErrorCode_InternalError); #endif } @@ -704,6 +622,10 @@ void HttpClient::GlobalFinalize() { curl_global_cleanup(); + +#if ORTHANC_PKCS11_ENABLED == 1 + Pkcs11::Finalize(); +#endif } @@ -773,7 +695,7 @@ << (pin.empty() ? " (no PIN provided)" : " (PIN is provided)"); GlobalParameters::GetInstance().InitializePkcs11(module, pin, verbose); #else - LOG(ERROR) << "This version of Orthanc is compiled without support for PKCS11"; + LOG(ERROR) << "This version of Orthanc is compiled without support for PKCS#11"; throw OrthancException(ErrorCode_InternalError); #endif } diff -r 944b255035a0 -r e7e1858d9504 Core/Pkcs11.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/Pkcs11.cpp Mon Jun 20 13:23:42 2016 +0200 @@ -0,0 +1,312 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "PrecompiledHeaders.h" +#include "Pkcs11.h" + +#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1 +# error This file cannot be used if OpenSSL or PKCS#11 support is disabled +#endif + + +#if defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_ECDH) +# error OpenSSL was compiled without support for RSA, EC, ECDSA or ECDH +#endif + + +#include "Logging.h" +#include "OrthancException.h" +#include "Toolbox.h" + +extern "C" +{ +#include // This is P11's "engine.h" +} + +#include +#include + + +namespace Orthanc +{ + namespace Pkcs11 + { + static const char* PKCS11_ENGINE_ID = "pkcs11"; + static const char* PKCS11_ENGINE_NAME = "PKCS#11 for Orthanc"; + static const ENGINE_CMD_DEFN PKCS11_ENGINE_COMMANDS[] = + { + { + CMD_MODULE_PATH, + "MODULE_PATH", + "Specifies the path to the PKCS#11 module shared library", + ENGINE_CMD_FLAG_STRING + }, + { + CMD_PIN, + "PIN", + "Specifies the pin code", + ENGINE_CMD_FLAG_STRING + }, + { + CMD_VERBOSE, + "VERBOSE", + "Print additional details", + ENGINE_CMD_FLAG_NO_INPUT + }, + { + CMD_LOAD_CERT_CTRL, + "LOAD_CERT_CTRL", + "Get the certificate from card", + ENGINE_CMD_FLAG_INTERNAL + }, + { + 0, + NULL, + NULL, + 0 + } + }; + + + static bool pkcs11Initialized_ = false; + static ENGINE_CTX *context_ = NULL; + + static int EngineInitialize(ENGINE* engine) + { + if (context_ == NULL) + { + return 0; + } + else + { + return pkcs11_init(context_); + } + } + + + static int EngineFinalize(ENGINE* engine) + { + if (context_ == NULL) + { + return 0; + } + else + { + return pkcs11_finish(context_); + } + } + + + static int EngineDestroy(ENGINE* engine) + { + return (context_ == NULL ? 0 : 1); + } + + + static int EngineControl(ENGINE *engine, + int command, + long i, + void *p, + void (*f) ()) + { + if (context_ == NULL) + { + return 0; + } + else + { + return pkcs11_engine_ctrl(context_, command, i, p, f); + } + } + + + static EVP_PKEY *EngineLoadPublicKey(ENGINE *engine, + const char *s_key_id, + UI_METHOD *ui_method, + void *callback_data) + { + if (context_ == NULL) + { + return 0; + } + else + { + return pkcs11_load_public_key(context_, s_key_id, ui_method, callback_data); + } + } + + + static EVP_PKEY *EngineLoadPrivateKey(ENGINE *engine, + const char *s_key_id, + UI_METHOD *ui_method, + void *callback_data) + { + if (context_ == NULL) + { + return 0; + } + else + { + return pkcs11_load_private_key(context_, s_key_id, ui_method, callback_data); + } + } + + + static ENGINE* LoadEngine() + { + // This function creates an engine for PKCS#11 and inspired by + // the "ENGINE_load_dynamic" function from OpenSSL, in file + // "crypto/engine/eng_dyn.c" + + ENGINE* engine = ENGINE_new(); + if (!engine) + { + LOG(ERROR) << "Cannot create an OpenSSL engine for PKCS#11"; + throw OrthancException(ErrorCode_InternalError); + } + + // Create a PKCS#11 context using libp11 + context_ = pkcs11_new(); + if (!context_) + { + LOG(ERROR) << "Cannot create a libp11 context for PKCS#11"; + ENGINE_free(engine); + throw OrthancException(ErrorCode_InternalError); + } + + if (!ENGINE_set_id(engine, PKCS11_ENGINE_ID) || + !ENGINE_set_name(engine, PKCS11_ENGINE_NAME) || + !ENGINE_set_cmd_defns(engine, PKCS11_ENGINE_COMMANDS) || + + // Register the callback functions + !ENGINE_set_init_function(engine, EngineInitialize) || + !ENGINE_set_finish_function(engine, EngineFinalize) || + !ENGINE_set_destroy_function(engine, EngineDestroy) || + !ENGINE_set_ctrl_function(engine, EngineControl) || + !ENGINE_set_load_pubkey_function(engine, EngineLoadPublicKey) || + !ENGINE_set_load_privkey_function(engine, EngineLoadPrivateKey) || + + !ENGINE_set_RSA(engine, PKCS11_get_rsa_method()) || + !ENGINE_set_ECDSA(engine, PKCS11_get_ecdsa_method()) || + !ENGINE_set_ECDH(engine, PKCS11_get_ecdh_method()) || + +#if OPENSSL_VERSION_NUMBER >= 0x10100002L + !ENGINE_set_EC(engine, PKCS11_get_ec_key_method()) || +#endif + + // Make OpenSSL know about our PKCS#11 engine + !ENGINE_add(engine)) + { + LOG(ERROR) << "Cannot initialize the OpenSSL engine for PKCS#11"; + pkcs11_finish(context_); + ENGINE_free(engine); + throw OrthancException(ErrorCode_InternalError); + } + + // If the "ENGINE_add" worked, it gets a structural + // reference. We release our just-created reference. + ENGINE_free(engine); + + return ENGINE_by_id(PKCS11_ENGINE_ID); + } + + + bool IsInitialized() + { + return pkcs11Initialized_; + } + + const char* GetEngineIdentifier() + { + return PKCS11_ENGINE_ID; + } + + void Initialize(const std::string& module, + const std::string& pin, + bool verbose) + { + if (pkcs11Initialized_) + { + LOG(ERROR) << "The PKCS#11 engine has already been initialized"; + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } + + if (module.empty() || + !Toolbox::IsRegularFile(module)) + { + LOG(ERROR) << "The PKCS#11 module must be a path to one shared library (DLL or .so)"; + throw OrthancException(ErrorCode_InexistentFile); + } + + ENGINE* engine = LoadEngine(); + if (!engine) + { + LOG(ERROR) << "Cannot create an OpenSSL engine for PKCS#11"; + throw OrthancException(ErrorCode_InternalError); + } + + if (!ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", module.c_str(), 0)) + { + LOG(ERROR) << "Cannot configure the OpenSSL dynamic engine for PKCS#11"; + throw OrthancException(ErrorCode_InternalError); + } + + if (verbose) + { + ENGINE_ctrl_cmd_string(engine, "VERBOSE", NULL, 0); + } + + if (!pin.empty() && + !ENGINE_ctrl_cmd_string(engine, "PIN", pin.c_str(), 0)) + { + LOG(ERROR) << "Cannot set the PIN code for PKCS#11"; + throw OrthancException(ErrorCode_InternalError); + } + + if (!ENGINE_init(engine)) + { + LOG(ERROR) << "Cannot initialize the OpenSSL dynamic engine for PKCS#11"; + throw OrthancException(ErrorCode_InternalError); + } + + LOG(WARNING) << "The PKCS#11 engine has been successfully initialized"; + pkcs11Initialized_ = true; + } + + + void Finalize() + { + // Nothing to do, the unregistration of the engine is + // automatically done by OpenSSL + } + } +} diff -r 944b255035a0 -r e7e1858d9504 Core/Pkcs11.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Core/Pkcs11.h Mon Jun 20 13:23:42 2016 +0200 @@ -0,0 +1,56 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1 +# error This file cannot be used if OpenSSL or PKCS#11 support is disabled +#endif + + +#include + +namespace Orthanc +{ + namespace Pkcs11 + { + const char* GetEngineIdentifier(); + + bool IsInitialized(); + + void Initialize(const std::string& module, + const std::string& pin, + bool verbose); + + void Finalize(); + } +} diff -r 944b255035a0 -r e7e1858d9504 Resources/CMake/LibP11Configuration.cmake --- a/Resources/CMake/LibP11Configuration.cmake Sat Jun 18 12:03:32 2016 +0200 +++ b/Resources/CMake/LibP11Configuration.cmake Mon Jun 20 13:23:42 2016 +0200 @@ -1,21 +1,14 @@ -SET(LIBP11_SOURCES_DIR ${CMAKE_BINARY_DIR}/libp11-0.4.0) -SET(LIBP11_URL "www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/beid/libp11-0.4.0.tar.gz") -SET(LIBP11_MD5 "00b3e41db5be840d822bda12f3ab2ca7") -DownloadPackage(${LIBP11_MD5} ${LIBP11_URL} "${LIBP11_SOURCES_DIR}") +if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11) + SET(LIBP11_SOURCES_DIR ${CMAKE_BINARY_DIR}/libp11-0.4.0) + SET(LIBP11_URL "www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/beid/libp11-0.4.0.tar.gz") + SET(LIBP11_MD5 "00b3e41db5be840d822bda12f3ab2ca7") + DownloadPackage(${LIBP11_MD5} ${LIBP11_URL} "${LIBP11_SOURCES_DIR}") -file(COPY - ${LIBP11_SOURCES_DIR}/src/eng_front.c - DESTINATION ${AUTOGENERATED_DIR}/libp11) - -# Create an empty "config.h" to make "eng_front.c" happy -file(WRITE ${LIBP11_SOURCES_DIR}/src/config.h "") - -if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11) include_directories(${LIBP11_SOURCES_DIR}/src) set(LIBP11_SOURCES + #${LIBP11_SOURCES_DIR}/src/eng_front.c ${LIBP11_SOURCES_DIR}/src/eng_back.c - #${LIBP11_SOURCES_DIR}/src/eng_front.c ${LIBP11_SOURCES_DIR}/src/eng_parse.c ${LIBP11_SOURCES_DIR}/src/libpkcs11.c ${LIBP11_SOURCES_DIR}/src/p11_attr.c