# HG changeset patch # User Sebastien Jodogne # Date 1610039919 -3600 # Node ID 5209a9ff6e389b0bbd7a0f52844edacb083fa5df # Parent 4a4e33c9082d4fa69b2b4e5f4bdaf9356f111fed configuration options for DICOM TLS in Orthanc SCP diff -r 4a4e33c9082d -r 5209a9ff6e38 OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Thu Jan 07 16:53:35 2021 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociation.cpp Thu Jan 07 18:18:39 2021 +0100 @@ -265,8 +265,9 @@ "No presentation context was proposed"); } - CLOG(INFO, DICOM) << "Opening a DICOM SCU connection from AET \"" - << parameters.GetLocalApplicationEntityTitle() + CLOG(INFO, DICOM) << "Opening a DICOM SCU connection " + << (parameters.GetRemoteModality().IsDicomTlsEnabled() ? "using DICOM TLS" : "without DICOM TLS") + << " from AET \"" << parameters.GetLocalApplicationEntityTitle() << "\" to AET \"" << parameters.GetRemoteModality().GetApplicationEntityTitle() << "\" on host " << parameters.GetRemoteModality().GetHost() << ":" << parameters.GetRemoteModality().GetPortNumber() diff -r 4a4e33c9082d -r 5209a9ff6e38 OrthancFramework/Sources/DicomNetworking/DicomServer.cpp --- a/OrthancFramework/Sources/DicomNetworking/DicomServer.cpp Thu Jan 07 16:53:35 2021 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomServer.cpp Thu Jan 07 18:18:39 2021 +0100 @@ -86,7 +86,8 @@ DicomServer::DicomServer() : pimpl_(new PImpl), - aet_("ANY-SCP") + aet_("ANY-SCP"), + useDicomTls_(false) { port_ = 104; modalities_ = NULL; @@ -368,6 +369,16 @@ throw OrthancException(ErrorCode_BadSequenceOfCalls, "No list of modalities was provided to the DICOM server"); } + + if (useDicomTls_) + { + if (ownCertificatePath_.empty() || + ownPrivateKeyPath_.empty()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "DICOM TLS is enabled in Orthanc SCP, but no certificate was provided"); + } + } Stop(); @@ -381,16 +392,15 @@ ") cannot create network: " + std::string(cond.text())); } - bool useDicomTls = false; // TODO - Read from configuration option - #if ORTHANC_ENABLE_SSL == 1 assert(pimpl_->tls_.get() == NULL); - if (useDicomTls) + if (useDicomTls_) { + CLOG(INFO, DICOM) << "Orthanc SCP will use DICOM TLS"; + try { - // TODO - Configuration options pimpl_->tls_.reset(Internals::InitializeDicomTls(pimpl_->network_, NET_ACCEPTOR, "/tmp/j/Server.key", "/tmp/j/Server.crt", "/tmp/j/Client.crt")); } @@ -400,20 +410,17 @@ throw; } } -#endif - - if (useDicomTls) - { - CLOG(INFO, DICOM) << "Orthanc SCP will use DICOM TLS"; - } else { CLOG(INFO, DICOM) << "Orthanc SCP will *not* use DICOM TLS"; } +#else + CLOG(INFO, DICOM) << "Orthanc SCP will *not* use DICOM TLS"; +#endif continue_ = true; pimpl_->workers_.reset(new RunnableWorkersPool(4)); // Use 4 workers - TODO as a parameter? - pimpl_->thread_ = boost::thread(ServerThread, this, useDicomTls); + pimpl_->thread_ = boost::thread(ServerThread, this, useDicomTls_); } @@ -462,4 +469,94 @@ return modalities_->IsSameAETitle(aet, GetApplicationEntityTitle()); } } + + + void DicomServer::SetDicomTlsEnabled(bool enabled) + { + Stop(); + useDicomTls_ = enabled; + } + + bool DicomServer::IsDicomTlsEnabled() const + { + return useDicomTls_; + } + + void DicomServer::SetOwnCertificatePath(const std::string& privateKeyPath, + const std::string& certificatePath) + { + Stop(); + + if (!privateKeyPath.empty() && + !certificatePath.empty()) + { + CLOG(INFO, DICOM) << "Setting the TLS certificate for DICOM SCP connections: " + << privateKeyPath << " (key), " << certificatePath << " (certificate)"; + + if (certificatePath.empty()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, "No path to the default DICOM TLS certificate was provided"); + } + + if (privateKeyPath.empty()) + { + throw OrthancException(ErrorCode_ParameterOutOfRange, + "No path to the private key for the default DICOM TLS certificate was provided"); + } + + if (!SystemToolbox::IsRegularFile(privateKeyPath)) + { + throw OrthancException(ErrorCode_InexistentFile, "Inexistent file: " + privateKeyPath); + } + + if (!SystemToolbox::IsRegularFile(certificatePath)) + { + throw OrthancException(ErrorCode_InexistentFile, "Inexistent file: " + certificatePath); + } + + ownPrivateKeyPath_ = privateKeyPath; + ownCertificatePath_ = certificatePath; + } + else + { + ownPrivateKeyPath_.clear(); + ownCertificatePath_.clear(); + } + } + + const std::string& DicomServer::GetOwnPrivateKeyPath() const + { + return ownPrivateKeyPath_; + } + + const std::string& DicomServer::GetOwnCertificatePath() const + { + return ownCertificatePath_; + } + + void DicomServer::SetTrustedCertificatesPath(const std::string& path) + { + Stop(); + + if (!path.empty()) + { + CLOG(INFO, DICOM) << "Setting the trusted certificates for DICOM SCP connections: " << path; + + if (!SystemToolbox::IsRegularFile(path)) + { + throw OrthancException(ErrorCode_InexistentFile, "Inexistent file: " + path); + } + + trustedCertificatesPath_ = path; + } + else + { + trustedCertificatesPath_.clear(); + } + } + + const std::string& DicomServer::GetTrustedCertificatesPath() const + { + return trustedCertificatesPath_; + } } diff -r 4a4e33c9082d -r 5209a9ff6e38 OrthancFramework/Sources/DicomNetworking/DicomServer.h --- a/OrthancFramework/Sources/DicomNetworking/DicomServer.h Thu Jan 07 16:53:35 2021 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomServer.h Thu Jan 07 18:18:39 2021 +0100 @@ -81,6 +81,12 @@ IStorageCommitmentRequestHandlerFactory* storageCommitmentFactory_; IApplicationEntityFilter* applicationEntityFilter_; + // New in Orthanc 1.9.0 for DICOM TLS + bool useDicomTls_; + std::string ownPrivateKeyPath_; + std::string ownCertificatePath_; + std::string trustedCertificatesPath_; + static void ServerThread(DicomServer* server, bool useDicomTls); @@ -137,6 +143,17 @@ void Stop(); bool IsMyAETitle(const std::string& aet) const; + + void SetDicomTlsEnabled(bool enabled); + bool IsDicomTlsEnabled() const; + + void SetOwnCertificatePath(const std::string& privateKeyPath, + const std::string& certificatePath); + const std::string& GetOwnPrivateKeyPath() const; + const std::string& GetOwnCertificatePath() const; + + void SetTrustedCertificatesPath(const std::string& path); + const std::string& GetTrustedCertificatesPath() const; }; } diff -r 4a4e33c9082d -r 5209a9ff6e38 OrthancServer/Sources/main.cpp --- a/OrthancServer/Sources/main.cpp Thu Jan 07 16:53:35 2021 +0100 +++ b/OrthancServer/Sources/main.cpp Thu Jan 07 18:18:39 2021 +0100 @@ -64,6 +64,12 @@ using namespace Orthanc; +static const char* const KEY_DICOM_TLS_PRIVATE_KEY = "DicomTlsPrivateKey"; +static const char* const KEY_DICOM_TLS_ENABLED = "DicomTlsEnabled"; +static const char* const KEY_DICOM_TLS_CERTIFICATE = "DicomTlsCertificate"; +static const char* const KEY_DICOM_TLS_TRUSTED_CERTIFICATES = "DicomTlsTrustedCertificates"; + + class OrthancStoreRequestHandler : public IStoreRequestHandler { private: @@ -1189,6 +1195,17 @@ dicomServer.SetAssociationTimeout(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomScpTimeout", 30)); dicomServer.SetPortNumber(lock.GetConfiguration().GetUnsignedIntegerParameter("DicomPort", 4242)); dicomServer.SetApplicationEntityTitle(lock.GetConfiguration().GetOrthancAET()); + + // Configuration of DICOM TLS for Orthanc SCP (since Orthanc 1.9.0) + dicomServer.SetDicomTlsEnabled(lock.GetConfiguration().GetBooleanParameter(KEY_DICOM_TLS_ENABLED, false)); + if (dicomServer.IsDicomTlsEnabled()) + { + dicomServer.SetOwnCertificatePath( + lock.GetConfiguration().GetStringParameter(KEY_DICOM_TLS_PRIVATE_KEY, ""), + lock.GetConfiguration().GetStringParameter(KEY_DICOM_TLS_CERTIFICATE, "")); + dicomServer.SetTrustedCertificatesPath( + lock.GetConfiguration().GetStringParameter(KEY_DICOM_TLS_TRUSTED_CERTIFICATES, "")); + } } #if ORTHANC_ENABLE_PLUGINS == 1 @@ -1438,12 +1455,12 @@ LOG(WARNING) << "Setting option \"JobsHistorySize\" to zero is not recommended"; } - // Configuration of DICOM TLS (since Orthanc 1.9.0) + // Configuration of DICOM TLS for Orthanc SCU (since Orthanc 1.9.0) DicomAssociationParameters::SetDefaultOwnCertificatePath( - lock.GetConfiguration().GetStringParameter("DicomTlsPrivateKey", ""), - lock.GetConfiguration().GetStringParameter("DicomTlsCertificate", "")); + lock.GetConfiguration().GetStringParameter(KEY_DICOM_TLS_PRIVATE_KEY, ""), + lock.GetConfiguration().GetStringParameter(KEY_DICOM_TLS_CERTIFICATE, "")); DicomAssociationParameters::SetDefaultTrustedCertificatesPath( - lock.GetConfiguration().GetStringParameter("DicomTlsTrustedCertificates", "")); + lock.GetConfiguration().GetStringParameter(KEY_DICOM_TLS_TRUSTED_CERTIFICATES, "")); } ServerContext context(database, storageArea, false /* not running unit tests */, maxCompletedJobs);