Mercurial > hg > orthanc
diff OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp @ 4438:4a4e33c9082d
configuration options for DICOM TLS in Orthanc SCU
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 07 Jan 2021 16:53:35 +0100 |
parents | d9473bd5ed43 |
children | f4dbdb2dcba6 |
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp Wed Jan 06 17:27:28 2021 +0100 +++ b/OrthancFramework/Sources/DicomNetworking/DicomAssociationParameters.cpp Thu Jan 07 16:53:35 2021 +0100 @@ -27,13 +27,17 @@ #include "../Logging.h" #include "../OrthancException.h" #include "../SerializationToolbox.h" +#include "../SystemToolbox.h" #include "NetworkingCompatibility.h" #include <boost/thread/mutex.hpp> -// By default, the timeout for client DICOM connections is set to 10 seconds -static boost::mutex defaultTimeoutMutex_; -static uint32_t defaultTimeout_ = 10; +// By default, the default timeout for client DICOM connections is set to 10 seconds +static boost::mutex defaultConfigurationMutex_; +static uint32_t defaultTimeout_ = 10; +static std::string defaultOwnPrivateKeyPath_; +static std::string defaultOwnCertificatePath_; +static std::string defaultTrustedCertificatesPath_; namespace Orthanc @@ -50,25 +54,37 @@ uint32_t DicomAssociationParameters::GetDefaultTimeout() { - boost::mutex::scoped_lock lock(defaultTimeoutMutex_); + boost::mutex::scoped_lock lock(defaultConfigurationMutex_); return defaultTimeout_; } + void DicomAssociationParameters::SetDefaultParameters() + { + boost::mutex::scoped_lock lock(defaultConfigurationMutex_); + timeout_ = defaultTimeout_; + ownPrivateKeyPath_ = defaultOwnPrivateKeyPath_; + ownCertificatePath_ = defaultOwnCertificatePath_; + trustedCertificatesPath_ = defaultTrustedCertificatesPath_; + } + + DicomAssociationParameters::DicomAssociationParameters() : localAet_("ORTHANC"), - timeout_(GetDefaultTimeout()) + timeout_(0) // Will be set by SetDefaultParameters() { remote_.SetApplicationEntityTitle("ANY-SCP"); + SetDefaultParameters(); } DicomAssociationParameters::DicomAssociationParameters(const std::string& localAet, const RemoteModalityParameters& remote) : localAet_(localAet), - timeout_(GetDefaultTimeout()) + timeout_(0) // Will be set by SetDefaultParameters() { SetRemoteModality(remote); + SetDefaultParameters(); } const std::string &DicomAssociationParameters::GetLocalApplicationEntityTitle() const @@ -142,9 +158,67 @@ } + void DicomAssociationParameters::CheckDicomTlsConfiguration() const + { + if (!remote_.IsDicomTlsEnabled()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls, "DICOM TLS is not enabled"); + } + else if (ownPrivateKeyPath_.empty()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls, + "DICOM TLS - No path to the private key of the local certificate was provided"); + } + else if (ownCertificatePath_.empty()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls, + "DICOM TLS - No path to the local certificate was provided"); + } + else if (trustedCertificatesPath_.empty()) + { + throw OrthancException(ErrorCode_BadSequenceOfCalls, + "DICOM TLS - No path to the trusted remote certificates was provided"); + } + } + + void DicomAssociationParameters::SetOwnCertificatePath(const std::string& privateKeyPath, + const std::string& certificatePath) + { + ownPrivateKeyPath_ = privateKeyPath; + ownCertificatePath_ = certificatePath; + } + + void DicomAssociationParameters::SetTrustedCertificatesPath(const std::string& path) + { + trustedCertificatesPath_ = path; + } + + const std::string& DicomAssociationParameters::GetOwnPrivateKeyPath() const + { + CheckDicomTlsConfiguration(); + return ownPrivateKeyPath_; + } + + const std::string& DicomAssociationParameters::GetOwnCertificatePath() const + { + CheckDicomTlsConfiguration(); + return ownCertificatePath_; + } + + const std::string& DicomAssociationParameters::GetTrustedCertificatesPath() const + { + CheckDicomTlsConfiguration(); + return trustedCertificatesPath_; + } + + + static const char* const LOCAL_AET = "LocalAet"; static const char* const REMOTE = "Remote"; - static const char* const TIMEOUT = "Timeout"; // New in Orthanc in 1.7.0 + static const char* const TIMEOUT = "Timeout"; // New in Orthanc in 1.7.0 + static const char* const OWN_PRIVATE_KEY = "OwnPrivateKey"; // New in Orthanc 1.9.0 + static const char* const OWN_CERTIFICATE = "OwnCertificate"; // New in Orthanc 1.9.0 + static const char* const TRUSTED_CERTIFICATES = "TrustedCertificates"; // New in Orthanc 1.9.0 void DicomAssociationParameters::SerializeJob(Json::Value& target) const @@ -158,6 +232,34 @@ target[LOCAL_AET] = localAet_; remote_.Serialize(target[REMOTE], true /* force advanced format */); target[TIMEOUT] = timeout_; + + // Don't write the DICOM TLS parameters if they are not required + if (ownPrivateKeyPath_.empty()) + { + target.removeMember(OWN_PRIVATE_KEY); + } + else + { + target[OWN_PRIVATE_KEY] = ownPrivateKeyPath_; + } + + if (ownCertificatePath_.empty()) + { + target.removeMember(OWN_CERTIFICATE); + } + else + { + target[OWN_CERTIFICATE] = ownCertificatePath_; + } + + if (trustedCertificatesPath_.empty()) + { + target.removeMember(TRUSTED_CERTIFICATES); + } + else + { + target[TRUSTED_CERTIFICATES] = trustedCertificatesPath_; + } } } @@ -167,11 +269,43 @@ if (serialized.type() == Json::objectValue) { DicomAssociationParameters result; - + + if (!serialized.isMember(REMOTE)) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + result.remote_ = RemoteModalityParameters(serialized[REMOTE]); result.localAet_ = SerializationToolbox::ReadString(serialized, LOCAL_AET); result.timeout_ = SerializationToolbox::ReadInteger(serialized, TIMEOUT, GetDefaultTimeout()); + if (serialized.isMember(OWN_PRIVATE_KEY)) + { + result.ownPrivateKeyPath_ = SerializationToolbox::ReadString(serialized, OWN_PRIVATE_KEY); + } + else + { + result.ownPrivateKeyPath_.clear(); + } + + if (serialized.isMember(OWN_CERTIFICATE)) + { + result.ownCertificatePath_ = SerializationToolbox::ReadString(serialized, OWN_CERTIFICATE); + } + else + { + result.ownCertificatePath_.clear(); + } + + if (serialized.isMember(TRUSTED_CERTIFICATES)) + { + result.trustedCertificatesPath_ = SerializationToolbox::ReadString(serialized, TRUSTED_CERTIFICATES); + } + else + { + result.trustedCertificatesPath_.clear(); + } + return result; } else @@ -187,8 +321,77 @@ << seconds << " seconds (0 = no timeout)"; { - boost::mutex::scoped_lock lock(defaultTimeoutMutex_); + boost::mutex::scoped_lock lock(defaultConfigurationMutex_); defaultTimeout_ = seconds; } } + + + void DicomAssociationParameters::SetDefaultOwnCertificatePath(const std::string& privateKeyPath, + const std::string& certificatePath) + { + if (!privateKeyPath.empty() && + !certificatePath.empty()) + { + CLOG(INFO, DICOM) << "Setting the default TLS certificate for DICOM SCU 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); + } + + { + boost::mutex::scoped_lock lock(defaultConfigurationMutex_); + defaultOwnPrivateKeyPath_ = privateKeyPath; + defaultOwnCertificatePath_ = certificatePath; + } + } + else + { + boost::mutex::scoped_lock lock(defaultConfigurationMutex_); + defaultOwnPrivateKeyPath_.clear(); + defaultOwnCertificatePath_.clear(); + } + } + + + void DicomAssociationParameters::SetDefaultTrustedCertificatesPath(const std::string& path) + { + if (!path.empty()) + { + CLOG(INFO, DICOM) << "Setting the default trusted certificates for DICOM SCU connections: " << path; + + if (!SystemToolbox::IsRegularFile(path)) + { + throw OrthancException(ErrorCode_InexistentFile, "Inexistent file: " + path); + } + + { + boost::mutex::scoped_lock lock(defaultConfigurationMutex_); + defaultTrustedCertificatesPath_ = path; + } + } + else + { + boost::mutex::scoped_lock lock(defaultConfigurationMutex_); + defaultTrustedCertificatesPath_.clear(); + } + } }