# HG changeset patch # User Sebastien Jodogne # Date 1466176190 -7200 # Node ID fefbe71c2272fef297201a5e111ffe19c312d8bf # Parent bd143a77eb7adae9a9aa7ef5401d5e3181cc031f Possibility to use PKCS#11 authentication for hardware security modules with Orthanc peers diff -r bd143a77eb7a -r fefbe71c2272 CMakeLists.txt --- a/CMakeLists.txt Wed Jun 15 17:20:52 2016 +0200 +++ b/CMakeLists.txt Fri Jun 17 17:09:50 2016 +0200 @@ -32,6 +32,7 @@ SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Build the ServeFolders plugin") SET(BUILD_MODALITY_WORKLISTS ON CACHE BOOL "Build the sample plugin to serve modality worklists") SET(USE_DCMTK_361 OFF CACHE BOOL "Use forthcoming DCMTK version 3.6.1 in static builds (instead of 3.6.0)") +SET(ENABLE_PKCS11 OFF CACHE BOOL "Enable PKCS#11 for HTTPS client authentication using hardware security modules and smart cards") # Advanced parameters to fine-tune linking against system libraries SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp") @@ -46,7 +47,8 @@ SET(USE_SYSTEM_CURL ON CACHE BOOL "Use the system version of LibCurl") 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_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)") # Experimental options SET(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)") @@ -77,7 +79,6 @@ - ##################################################################### ## List of source files ##################################################################### @@ -331,6 +332,18 @@ endif() +if (ENABLE_PKCS11) + if (ENABLE_SSL) + add_definitions(-DORTHANC_PKCS11_ENABLED=1) + include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibP11Configuration.cmake) + else() + message(FATAL_ERROR "OpenSSL is required to enable PKCS#11") + endif() +else() + add_definitions(-DORTHANC_PKCS11_ENABLED=0) +endif() + + ##################################################################### ## Autogeneration of files @@ -418,6 +431,7 @@ ${PUGIXML_SOURCES} ${SQLITE_SOURCES} ${ZLIB_SOURCES} + ${LIBP11_SOURCES} ${CMAKE_SOURCE_DIR}/Resources/ThirdParty/md5/md5.c ${CMAKE_SOURCE_DIR}/Resources/ThirdParty/base64/base64.cpp diff -r bd143a77eb7a -r fefbe71c2272 Core/HttpClient.cpp --- a/Core/HttpClient.cpp Wed Jun 15 17:20:52 2016 +0200 +++ b/Core/HttpClient.cpp Fri Jun 17 17:09:50 2016 +0200 @@ -43,6 +43,21 @@ #include +#if ORTHANC_PKCS11_ENABLED == 1 + +#include +#include + +// Include the "libengine-pkcs11-openssl" from the libp11 package +extern "C" +{ +#pragma GCC diagnostic error "-fpermissive" +#include +} + +#endif + + extern "C" { static CURLcode GetHttpStatus(CURLcode code, CURL* curl, long* status) @@ -82,10 +97,42 @@ 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) + timeout_(0), + pkcs11Initialized_(false) { } @@ -144,6 +191,69 @@ boost::mutex::scoped_lock lock(mutex_); return timeout_; } + + bool IsPkcs11Initialized() + { + boost::mutex::scoped_lock lock(mutex_); + return pkcs11Initialized_; + } + + +#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; + } +#endif }; @@ -242,7 +352,8 @@ HttpClient::HttpClient() : pimpl_(new PImpl), - verifyPeers_(true) + verifyPeers_(true), + pkcs11Enabled_(false) { Setup(); } @@ -269,6 +380,8 @@ service.GetCertificateKeyPassword()); } + SetPkcs11Enabled(service.IsPkcs11Enabled()); + SetUrl(service.GetUrl() + uri); } @@ -329,8 +442,9 @@ CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_URL, url_.c_str())); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer)); +#if ORTHANC_SSL_ENABLED == 1 // Setup HTTPS-related options -#if ORTHANC_SSL_ENABLED == 1 + if (verifyPeers_) { CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CAINFO, caCertificates_.c_str())); @@ -344,6 +458,57 @@ } #endif + // Setup the HTTPS client certificate + if (!clientCertificateFile_.empty() && + pkcs11Enabled_) + { + LOG(ERROR) << "Cannot enable both client certificates and PKCS#11 authentication"; + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + if (pkcs11Enabled_) + { +#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_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"; + throw OrthancException(ErrorCode_BadSequenceOfCalls); + } +#else + LOG(ERROR) << "This version of Orthanc is compiled without support for PKCS11"; + throw OrthancException(ErrorCode_InternalError); +#endif + } + else if (!clientCertificateFile_.empty()) + { +#if ORTHANC_SSL_ENABLED == 1 + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "PEM")); + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERT, clientCertificateFile_.c_str())); + + if (!clientCertificateKeyPassword_.empty()) + { + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_KEYPASSWD, clientCertificateKeyPassword_.c_str())); + } + + // NB: If no "clientKeyFile_" is provided, the key must be + // prepended to the certificate file + if (!clientCertificateKeyFile_.empty()) + { + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEYTYPE, "PEM")); + CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEY, clientCertificateKeyFile_.c_str())); + } +#else + LOG(ERROR) << "This version of Orthanc is compiled without OpenSSL support, cannot use HTTPS client authentication"; + throw OrthancException(ErrorCode_InternalError); +#endif + } + // Reset the parameters from previous calls to Apply() CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPHEADER, pimpl_->userHeaders_)); CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HTTPGET, 0L)); @@ -376,26 +541,6 @@ CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PROXY, proxy_.c_str())); } - // Set the HTTPS client certificate - if (!clientCertificateFile_.empty()) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "PEM")); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERT, clientCertificateFile_.c_str())); - - if (!clientCertificateKeyPassword_.empty()) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_KEYPASSWD, clientCertificateKeyPassword_.c_str())); - } - - // NB: If no "clientKeyFile_" is provided, the key must be - // prepended to the certificate file - if (!clientCertificateKeyFile_.empty()) - { - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEYTYPE, "PEM")); - CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLKEY, clientCertificateKeyFile_.c_str())); - } - } - switch (method_) { case HttpMethod_Get: @@ -540,6 +685,12 @@ void HttpClient::GlobalInitialize() { +#if ORTHANC_SSL_ENABLED == 1 + CheckCode(curl_global_init(CURL_GLOBAL_ALL)); +#else + CheckCode(curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL)); +#endif + CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT)); } @@ -605,4 +756,19 @@ clientCertificateKeyFile_ = certificateKeyFile; clientCertificateKeyPassword_ = certificateKeyPassword; } + + + void HttpClient::InitializePkcs11(const std::string& module, + const std::string& pin, + bool verbose) + { +#if ORTHANC_PKCS11_ENABLED == 1 + LOG(INFO) << "Initializing PKCS#11 using " << module + << (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"; + throw OrthancException(ErrorCode_InternalError); +#endif + } } diff -r bd143a77eb7a -r fefbe71c2272 Core/HttpClient.h --- a/Core/HttpClient.h Wed Jun 15 17:20:52 2016 +0200 +++ b/Core/HttpClient.h Fri Jun 17 17:09:50 2016 +0200 @@ -62,6 +62,7 @@ std::string clientCertificateFile_; std::string clientCertificateKeyFile_; std::string clientCertificateKeyPassword_; + bool pkcs11Enabled_; void Setup(); @@ -179,6 +180,16 @@ const std::string& certificateKeyFile, const std::string& certificateKeyPassword); + void SetPkcs11Enabled(bool enabled) + { + pkcs11Enabled_ = enabled; + } + + bool IsPkcs11Enabled() const + { + return pkcs11Enabled_; + } + const std::string& GetClientCertificateFile() const { return clientCertificateFile_; @@ -198,6 +209,10 @@ static void GlobalFinalize(); + static void InitializePkcs11(const std::string& module, + const std::string& pin, + bool verbose); + static void ConfigureSsl(bool httpsVerifyPeers, const std::string& httpsCACertificates); diff -r bd143a77eb7a -r fefbe71c2272 Core/WebServiceParameters.cpp --- a/Core/WebServiceParameters.cpp Wed Jun 15 17:20:52 2016 +0200 +++ b/Core/WebServiceParameters.cpp Fri Jun 17 17:09:50 2016 +0200 @@ -43,11 +43,20 @@ { WebServiceParameters::WebServiceParameters() : advancedFormat_(false), - url_("http://localhost:8042/") + url_("http://localhost:8042/"), + pkcs11Enabled_(false) { } + void WebServiceParameters::ClearClientCertificate() + { + certificateFile_.clear(); + certificateKeyFile_.clear(); + certificateKeyPassword_.clear(); + } + + void WebServiceParameters::SetClientCertificate(const std::string& certificateFile, const std::string& certificateKeyFile, const std::string& certificateKeyPassword) @@ -92,6 +101,7 @@ assert(peer.isArray()); advancedFormat_ = false; + pkcs11Enabled_ = false; if (peer.size() != 1 && peer.size() != 3) @@ -167,6 +177,18 @@ GetStringMember(peer, "CertificateKeyFile", ""), GetStringMember(peer, "CertificateKeyPassword", "")); } + + if (peer.isMember("Pkcs11")) + { + if (peer["Pkcs11"].type() == Json::booleanValue) + { + pkcs11Enabled_ = peer["Pkcs11"].asBool(); + } + else + { + throw OrthancException(ErrorCode_BadFileFormat); + } + } } diff -r bd143a77eb7a -r fefbe71c2272 Core/WebServiceParameters.h --- a/Core/WebServiceParameters.h Wed Jun 15 17:20:52 2016 +0200 +++ b/Core/WebServiceParameters.h Fri Jun 17 17:09:50 2016 +0200 @@ -47,6 +47,7 @@ std::string certificateFile_; std::string certificateKeyFile_; std::string certificateKeyPassword_; + bool pkcs11Enabled_; void FromJsonArray(const Json::Value& peer); @@ -85,6 +86,8 @@ password_ = password; } + void ClearClientCertificate(); + void SetClientCertificate(const std::string& certificateFile, const std::string& certificateKeyFile, const std::string& certificateKeyPassword); @@ -104,6 +107,16 @@ return certificateKeyPassword_; } + void SetPkcs11Enabled(bool pkcs11Enabled) + { + pkcs11Enabled_ = pkcs11Enabled; + } + + bool IsPkcs11Enabled() const + { + return pkcs11Enabled_; + } + void FromJson(const Json::Value& peer); void ToJson(Json::Value& value) const; diff -r bd143a77eb7a -r fefbe71c2272 NEWS --- a/NEWS Wed Jun 15 17:20:52 2016 +0200 +++ b/NEWS Fri Jun 17 17:09:50 2016 +0200 @@ -5,6 +5,7 @@ ------- * HTTPS client certificates can be associated with Orthanc peers to enhance security over Internet +* Possibility to use PKCS#11 authentication for hardware security modules with Orthanc peers * New option "--logfile" to output the Orthanc log to the given file * Support of SIGHUP signal (restart Orthanc only if the configuration files have changed) diff -r bd143a77eb7a -r fefbe71c2272 OrthancServer/OrthancInitialization.cpp --- a/OrthancServer/OrthancInitialization.cpp Wed Jun 15 17:20:52 2016 +0200 +++ b/OrthancServer/OrthancInitialization.cpp Fri Jun 17 17:09:50 2016 +0200 @@ -424,6 +424,48 @@ } + static void ConfigurePkcs11(const Json::Value& config) + { + if (config.type() != Json::objectValue || + !config.isMember("Module") || + config["Module"].type() != Json::stringValue) + { + LOG(ERROR) << "No path to the PKCS#11 module (DLL or .so) is provided for HTTPS client authentication"; + throw OrthancException(ErrorCode_BadFileFormat); + } + + std::string pin; + if (config.isMember("Pin")) + { + if (config["Pin"].type() == Json::stringValue) + { + pin = config["Pin"].asString(); + } + else + { + LOG(ERROR) << "The PIN number in the PKCS#11 configuration must be a string"; + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + bool verbose = false; + if (config.isMember("Verbose")) + { + if (config["Verbose"].type() == Json::booleanValue) + { + verbose = config["Verbose"].asBool(); + } + else + { + LOG(ERROR) << "The Verbose option in the PKCS#11 configuration must be a Boolean"; + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + HttpClient::InitializePkcs11(config["Module"].asString(), pin, verbose); + } + + void OrthancInitialize(const char* configurationFile) { @@ -435,10 +477,6 @@ SSL_load_error_strings(); OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); - - curl_global_init(CURL_GLOBAL_ALL); -#else - curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL); #endif InitializeServerEnumerations(); @@ -447,6 +485,11 @@ ReadGlobalConfiguration(configurationFile); ValidateGlobalConfiguration(); + if (configuration_.isMember("Pkcs11")) + { + ConfigurePkcs11(configuration_["Pkcs11"]); + } + HttpClient::GlobalInitialize(); RegisterUserMetadata(); @@ -488,8 +531,6 @@ DJDecoderRegistration::cleanup(); #endif - curl_global_cleanup(); - #if ORTHANC_SSL_ENABLED == 1 // Finalize OpenSSL // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup diff -r bd143a77eb7a -r fefbe71c2272 Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Wed Jun 15 17:20:52 2016 +0200 +++ b/Plugins/Engine/OrthancPlugins.cpp Fri Jun 17 17:09:50 2016 +0200 @@ -1811,6 +1811,8 @@ client.SetClientCertificate(certificate, key, password); } + client.SetPkcs11Enabled(p.pkcs11); + for (uint32_t i = 0; i < p.headersCount; i++) { if (p.headersKeys[i] == NULL || diff -r bd143a77eb7a -r fefbe71c2272 Plugins/Include/orthanc/OrthancCPlugin.h --- a/Plugins/Include/orthanc/OrthancCPlugin.h Wed Jun 15 17:20:52 2016 +0200 +++ b/Plugins/Include/orthanc/OrthancCPlugin.h Fri Jun 17 17:09:50 2016 +0200 @@ -4946,6 +4946,7 @@ const char* certificateFile; const char* certificateKeyFile; const char* certificateKeyPassword; + uint8_t pkcs11; } _OrthancPluginCallHttpClient2; @@ -4975,6 +4976,7 @@ * (can be NULL if no client certificate or if not using HTTPS). * @param certificateKeyPassword Password to unlock the key of the client certificate * (can be NULL if no client certificate or if not using HTTPS). + * @param pkcs11 Enable PKCS#11 client authentication for hardware security modules and smart cards. * @return 0 if success, or the error code if failure. **/ ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginHttpClient( @@ -4993,7 +4995,8 @@ uint32_t timeout, const char* certificateFile, const char* certificateKeyFile, - const char* certificateKeyPassword) + const char* certificateKeyPassword, + uint8_t pkcs11) { _OrthancPluginCallHttpClient2 params; memset(¶ms, 0, sizeof(params)); @@ -5013,6 +5016,7 @@ params.certificateFile = certificateFile; params.certificateKeyFile = certificateKeyFile; params.certificateKeyPassword = certificateKeyPassword; + params.pkcs11 = pkcs11; return context->InvokeService(context, _OrthancPluginService_CallHttpClient2, ¶ms); } diff -r bd143a77eb7a -r fefbe71c2272 Resources/CMake/LibCurlConfiguration.cmake --- a/Resources/CMake/LibCurlConfiguration.cmake Wed Jun 15 17:20:52 2016 +0200 +++ b/Resources/CMake/LibCurlConfiguration.cmake Fri Jun 17 17:09:50 2016 +0200 @@ -35,6 +35,7 @@ add_definitions( #-DHAVE_LIBSSL=1 -DUSE_OPENSSL=1 + -DHAVE_OPENSSL_ENGINE_H=1 -DUSE_SSLEAY=1 ) endif() diff -r bd143a77eb7a -r fefbe71c2272 Resources/CMake/LibP11Configuration.cmake --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/CMake/LibP11Configuration.cmake Fri Jun 17 17:09:50 2016 +0200 @@ -0,0 +1,52 @@ +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) + + +if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11) + include_directories(${LIBP11_SOURCES_DIR}/src) + + set(LIBP11_SOURCES + ${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 + ${LIBP11_SOURCES_DIR}/src/p11_cert.c + ${LIBP11_SOURCES_DIR}/src/p11_ec.c + ${LIBP11_SOURCES_DIR}/src/p11_err.c + ${LIBP11_SOURCES_DIR}/src/p11_front.c + ${LIBP11_SOURCES_DIR}/src/p11_key.c + ${LIBP11_SOURCES_DIR}/src/p11_load.c + ${LIBP11_SOURCES_DIR}/src/p11_misc.c + ${LIBP11_SOURCES_DIR}/src/p11_rsa.c + ${LIBP11_SOURCES_DIR}/src/p11_slot.c + ) + + if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR + ${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + list(APPEND LIBP11_SOURCES + ${LIBP11_SOURCES_DIR}/src/atfork.c + ) + endif() + +else() + check_include_file_cxx(libp11.h HAVE_LIBP11_H) + if (NOT HAVE_LIBP11_H) + message(FATAL_ERROR "Please install the libp11-dev package") + endif() + + check_library_exists(p11 PKCS11_login "" HAVE_LIBP11_LIB) + if (NOT HAVE_LIBP11_LIB) + message(FATAL_ERROR "Please install the libp11-dev package") + endif() + + link_libraries(p11) +endif() diff -r bd143a77eb7a -r fefbe71c2272 Resources/CMake/OpenSslConfiguration.cmake --- a/Resources/CMake/OpenSslConfiguration.cmake Wed Jun 15 17:20:52 2016 +0200 +++ b/Resources/CMake/OpenSslConfiguration.cmake Fri Jun 17 17:09:50 2016 +0200 @@ -25,9 +25,6 @@ -DOPENSSL_NO_BF -DOPENSSL_NO_CAMELLIA -DOPENSSL_NO_CAST - -DOPENSSL_NO_EC - -DOPENSSL_NO_ECDH - -DOPENSSL_NO_ECDSA -DOPENSSL_NO_EC_NISTP_64_GCC_128 -DOPENSSL_NO_GMP -DOPENSSL_NO_GOST @@ -99,6 +96,21 @@ ${OPENSSL_SOURCES_DIR}/ssl ) + if (ENABLE_PKCS11) + list(APPEND OPENSSL_SOURCES_SUBDIRS + # EC, ECDH and ECDSA are necessary for PKCS11 + ${OPENSSL_SOURCES_DIR}/crypto/ec + ${OPENSSL_SOURCES_DIR}/crypto/ecdh + ${OPENSSL_SOURCES_DIR}/crypto/ecdsa + ) + else() + add_definitions( + -DOPENSSL_NO_EC + -DOPENSSL_NO_ECDH + -DOPENSSL_NO_ECDSA + ) + endif() + foreach(d ${OPENSSL_SOURCES_SUBDIRS}) AUX_SOURCE_DIRECTORY(${d} OPENSSL_SOURCES) endforeach() @@ -181,8 +193,10 @@ ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3nametest.c ${OPENSSL_SOURCES_DIR}/crypto/ssl/heartbeat_test.c ${OPENSSL_SOURCES_DIR}/crypto/constant_time_test.c + ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c ) + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") set_source_files_properties( ${OPENSSL_SOURCES} diff -r bd143a77eb7a -r fefbe71c2272 Resources/Configuration.json --- a/Resources/Configuration.json Wed Jun 15 17:20:52 2016 +0200 +++ b/Resources/Configuration.json Fri Jun 17 17:09:50 2016 +0200 @@ -171,7 +171,8 @@ /** * This is another, more advanced format to define Orthanc * peers. It notably allows to specify a HTTPS client certificate - * in the PEM format, as in the "--cert" option of curl. + * in the PEM format (as in the "--cert" option of curl), or to + * enable PKCS#11 authentication for smart cards. **/ // "peer" : { // "Url" : "http://localhost:8043/", @@ -179,7 +180,8 @@ // "Password" : "alicePassword", // "CertificateFile" : "client.crt", // "CertificateKeyFile" : "client.key", - // "CertificateKeyPassword" : "certpass" + // "CertificateKeyPassword" : "certpass", + // "Pkcs11" : false // } }, @@ -288,6 +290,16 @@ // (such as PatientName). By default, the search is // case-insensitive, which does not follow the DICOM standard. "CaseSensitivePN" : false, + + // Configure PKCS#11 to use hardware security modules (HSM) and + // smart cards when carrying on HTTPS client authentication. + /** + "Pkcs11" : { + "Module" : "/usr/local/lib/libbeidpkcs11.so", + "Pin" : "1234", + "Verbose" : true + } + **/ // Register a new tag in the dictionary of DICOM tags that are known // to Orthanc. Each line must contain the tag (formatted as 2