Mercurial > hg > orthanc
comparison 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 |
comparison
equal
deleted
inserted
replaced
4437:d9473bd5ed43 | 4438:4a4e33c9082d |
---|---|
25 | 25 |
26 #include "../Compatibility.h" | 26 #include "../Compatibility.h" |
27 #include "../Logging.h" | 27 #include "../Logging.h" |
28 #include "../OrthancException.h" | 28 #include "../OrthancException.h" |
29 #include "../SerializationToolbox.h" | 29 #include "../SerializationToolbox.h" |
30 #include "../SystemToolbox.h" | |
30 #include "NetworkingCompatibility.h" | 31 #include "NetworkingCompatibility.h" |
31 | 32 |
32 #include <boost/thread/mutex.hpp> | 33 #include <boost/thread/mutex.hpp> |
33 | 34 |
34 // By default, the timeout for client DICOM connections is set to 10 seconds | 35 // By default, the default timeout for client DICOM connections is set to 10 seconds |
35 static boost::mutex defaultTimeoutMutex_; | 36 static boost::mutex defaultConfigurationMutex_; |
36 static uint32_t defaultTimeout_ = 10; | 37 static uint32_t defaultTimeout_ = 10; |
38 static std::string defaultOwnPrivateKeyPath_; | |
39 static std::string defaultOwnCertificatePath_; | |
40 static std::string defaultTrustedCertificatesPath_; | |
37 | 41 |
38 | 42 |
39 namespace Orthanc | 43 namespace Orthanc |
40 { | 44 { |
41 void DicomAssociationParameters::CheckHost(const std::string& host) | 45 void DicomAssociationParameters::CheckHost(const std::string& host) |
48 } | 52 } |
49 | 53 |
50 | 54 |
51 uint32_t DicomAssociationParameters::GetDefaultTimeout() | 55 uint32_t DicomAssociationParameters::GetDefaultTimeout() |
52 { | 56 { |
53 boost::mutex::scoped_lock lock(defaultTimeoutMutex_); | 57 boost::mutex::scoped_lock lock(defaultConfigurationMutex_); |
54 return defaultTimeout_; | 58 return defaultTimeout_; |
59 } | |
60 | |
61 | |
62 void DicomAssociationParameters::SetDefaultParameters() | |
63 { | |
64 boost::mutex::scoped_lock lock(defaultConfigurationMutex_); | |
65 timeout_ = defaultTimeout_; | |
66 ownPrivateKeyPath_ = defaultOwnPrivateKeyPath_; | |
67 ownCertificatePath_ = defaultOwnCertificatePath_; | |
68 trustedCertificatesPath_ = defaultTrustedCertificatesPath_; | |
55 } | 69 } |
56 | 70 |
57 | 71 |
58 DicomAssociationParameters::DicomAssociationParameters() : | 72 DicomAssociationParameters::DicomAssociationParameters() : |
59 localAet_("ORTHANC"), | 73 localAet_("ORTHANC"), |
60 timeout_(GetDefaultTimeout()) | 74 timeout_(0) // Will be set by SetDefaultParameters() |
61 { | 75 { |
62 remote_.SetApplicationEntityTitle("ANY-SCP"); | 76 remote_.SetApplicationEntityTitle("ANY-SCP"); |
77 SetDefaultParameters(); | |
63 } | 78 } |
64 | 79 |
65 | 80 |
66 DicomAssociationParameters::DicomAssociationParameters(const std::string& localAet, | 81 DicomAssociationParameters::DicomAssociationParameters(const std::string& localAet, |
67 const RemoteModalityParameters& remote) : | 82 const RemoteModalityParameters& remote) : |
68 localAet_(localAet), | 83 localAet_(localAet), |
69 timeout_(GetDefaultTimeout()) | 84 timeout_(0) // Will be set by SetDefaultParameters() |
70 { | 85 { |
71 SetRemoteModality(remote); | 86 SetRemoteModality(remote); |
87 SetDefaultParameters(); | |
72 } | 88 } |
73 | 89 |
74 const std::string &DicomAssociationParameters::GetLocalApplicationEntityTitle() const | 90 const std::string &DicomAssociationParameters::GetLocalApplicationEntityTitle() const |
75 { | 91 { |
76 return localAet_; | 92 return localAet_; |
140 { | 156 { |
141 return timeout_ != 0; | 157 return timeout_ != 0; |
142 } | 158 } |
143 | 159 |
144 | 160 |
161 void DicomAssociationParameters::CheckDicomTlsConfiguration() const | |
162 { | |
163 if (!remote_.IsDicomTlsEnabled()) | |
164 { | |
165 throw OrthancException(ErrorCode_BadSequenceOfCalls, "DICOM TLS is not enabled"); | |
166 } | |
167 else if (ownPrivateKeyPath_.empty()) | |
168 { | |
169 throw OrthancException(ErrorCode_BadSequenceOfCalls, | |
170 "DICOM TLS - No path to the private key of the local certificate was provided"); | |
171 } | |
172 else if (ownCertificatePath_.empty()) | |
173 { | |
174 throw OrthancException(ErrorCode_BadSequenceOfCalls, | |
175 "DICOM TLS - No path to the local certificate was provided"); | |
176 } | |
177 else if (trustedCertificatesPath_.empty()) | |
178 { | |
179 throw OrthancException(ErrorCode_BadSequenceOfCalls, | |
180 "DICOM TLS - No path to the trusted remote certificates was provided"); | |
181 } | |
182 } | |
183 | |
184 void DicomAssociationParameters::SetOwnCertificatePath(const std::string& privateKeyPath, | |
185 const std::string& certificatePath) | |
186 { | |
187 ownPrivateKeyPath_ = privateKeyPath; | |
188 ownCertificatePath_ = certificatePath; | |
189 } | |
190 | |
191 void DicomAssociationParameters::SetTrustedCertificatesPath(const std::string& path) | |
192 { | |
193 trustedCertificatesPath_ = path; | |
194 } | |
195 | |
196 const std::string& DicomAssociationParameters::GetOwnPrivateKeyPath() const | |
197 { | |
198 CheckDicomTlsConfiguration(); | |
199 return ownPrivateKeyPath_; | |
200 } | |
201 | |
202 const std::string& DicomAssociationParameters::GetOwnCertificatePath() const | |
203 { | |
204 CheckDicomTlsConfiguration(); | |
205 return ownCertificatePath_; | |
206 } | |
207 | |
208 const std::string& DicomAssociationParameters::GetTrustedCertificatesPath() const | |
209 { | |
210 CheckDicomTlsConfiguration(); | |
211 return trustedCertificatesPath_; | |
212 } | |
213 | |
214 | |
215 | |
145 static const char* const LOCAL_AET = "LocalAet"; | 216 static const char* const LOCAL_AET = "LocalAet"; |
146 static const char* const REMOTE = "Remote"; | 217 static const char* const REMOTE = "Remote"; |
147 static const char* const TIMEOUT = "Timeout"; // New in Orthanc in 1.7.0 | 218 static const char* const TIMEOUT = "Timeout"; // New in Orthanc in 1.7.0 |
219 static const char* const OWN_PRIVATE_KEY = "OwnPrivateKey"; // New in Orthanc 1.9.0 | |
220 static const char* const OWN_CERTIFICATE = "OwnCertificate"; // New in Orthanc 1.9.0 | |
221 static const char* const TRUSTED_CERTIFICATES = "TrustedCertificates"; // New in Orthanc 1.9.0 | |
148 | 222 |
149 | 223 |
150 void DicomAssociationParameters::SerializeJob(Json::Value& target) const | 224 void DicomAssociationParameters::SerializeJob(Json::Value& target) const |
151 { | 225 { |
152 if (target.type() != Json::objectValue) | 226 if (target.type() != Json::objectValue) |
156 else | 230 else |
157 { | 231 { |
158 target[LOCAL_AET] = localAet_; | 232 target[LOCAL_AET] = localAet_; |
159 remote_.Serialize(target[REMOTE], true /* force advanced format */); | 233 remote_.Serialize(target[REMOTE], true /* force advanced format */); |
160 target[TIMEOUT] = timeout_; | 234 target[TIMEOUT] = timeout_; |
235 | |
236 // Don't write the DICOM TLS parameters if they are not required | |
237 if (ownPrivateKeyPath_.empty()) | |
238 { | |
239 target.removeMember(OWN_PRIVATE_KEY); | |
240 } | |
241 else | |
242 { | |
243 target[OWN_PRIVATE_KEY] = ownPrivateKeyPath_; | |
244 } | |
245 | |
246 if (ownCertificatePath_.empty()) | |
247 { | |
248 target.removeMember(OWN_CERTIFICATE); | |
249 } | |
250 else | |
251 { | |
252 target[OWN_CERTIFICATE] = ownCertificatePath_; | |
253 } | |
254 | |
255 if (trustedCertificatesPath_.empty()) | |
256 { | |
257 target.removeMember(TRUSTED_CERTIFICATES); | |
258 } | |
259 else | |
260 { | |
261 target[TRUSTED_CERTIFICATES] = trustedCertificatesPath_; | |
262 } | |
161 } | 263 } |
162 } | 264 } |
163 | 265 |
164 | 266 |
165 DicomAssociationParameters DicomAssociationParameters::UnserializeJob(const Json::Value& serialized) | 267 DicomAssociationParameters DicomAssociationParameters::UnserializeJob(const Json::Value& serialized) |
166 { | 268 { |
167 if (serialized.type() == Json::objectValue) | 269 if (serialized.type() == Json::objectValue) |
168 { | 270 { |
169 DicomAssociationParameters result; | 271 DicomAssociationParameters result; |
170 | 272 |
273 if (!serialized.isMember(REMOTE)) | |
274 { | |
275 throw OrthancException(ErrorCode_BadFileFormat); | |
276 } | |
277 | |
171 result.remote_ = RemoteModalityParameters(serialized[REMOTE]); | 278 result.remote_ = RemoteModalityParameters(serialized[REMOTE]); |
172 result.localAet_ = SerializationToolbox::ReadString(serialized, LOCAL_AET); | 279 result.localAet_ = SerializationToolbox::ReadString(serialized, LOCAL_AET); |
173 result.timeout_ = SerializationToolbox::ReadInteger(serialized, TIMEOUT, GetDefaultTimeout()); | 280 result.timeout_ = SerializationToolbox::ReadInteger(serialized, TIMEOUT, GetDefaultTimeout()); |
174 | 281 |
282 if (serialized.isMember(OWN_PRIVATE_KEY)) | |
283 { | |
284 result.ownPrivateKeyPath_ = SerializationToolbox::ReadString(serialized, OWN_PRIVATE_KEY); | |
285 } | |
286 else | |
287 { | |
288 result.ownPrivateKeyPath_.clear(); | |
289 } | |
290 | |
291 if (serialized.isMember(OWN_CERTIFICATE)) | |
292 { | |
293 result.ownCertificatePath_ = SerializationToolbox::ReadString(serialized, OWN_CERTIFICATE); | |
294 } | |
295 else | |
296 { | |
297 result.ownCertificatePath_.clear(); | |
298 } | |
299 | |
300 if (serialized.isMember(TRUSTED_CERTIFICATES)) | |
301 { | |
302 result.trustedCertificatesPath_ = SerializationToolbox::ReadString(serialized, TRUSTED_CERTIFICATES); | |
303 } | |
304 else | |
305 { | |
306 result.trustedCertificatesPath_.clear(); | |
307 } | |
308 | |
175 return result; | 309 return result; |
176 } | 310 } |
177 else | 311 else |
178 { | 312 { |
179 throw OrthancException(ErrorCode_BadFileFormat); | 313 throw OrthancException(ErrorCode_BadFileFormat); |
185 { | 319 { |
186 CLOG(INFO, DICOM) << "Default timeout for DICOM connections if Orthanc acts as SCU (client): " | 320 CLOG(INFO, DICOM) << "Default timeout for DICOM connections if Orthanc acts as SCU (client): " |
187 << seconds << " seconds (0 = no timeout)"; | 321 << seconds << " seconds (0 = no timeout)"; |
188 | 322 |
189 { | 323 { |
190 boost::mutex::scoped_lock lock(defaultTimeoutMutex_); | 324 boost::mutex::scoped_lock lock(defaultConfigurationMutex_); |
191 defaultTimeout_ = seconds; | 325 defaultTimeout_ = seconds; |
192 } | 326 } |
193 } | 327 } |
328 | |
329 | |
330 void DicomAssociationParameters::SetDefaultOwnCertificatePath(const std::string& privateKeyPath, | |
331 const std::string& certificatePath) | |
332 { | |
333 if (!privateKeyPath.empty() && | |
334 !certificatePath.empty()) | |
335 { | |
336 CLOG(INFO, DICOM) << "Setting the default TLS certificate for DICOM SCU connections: " | |
337 << privateKeyPath << " (key), " << certificatePath << " (certificate)"; | |
338 | |
339 if (certificatePath.empty()) | |
340 { | |
341 throw OrthancException(ErrorCode_ParameterOutOfRange, "No path to the default DICOM TLS certificate was provided"); | |
342 } | |
343 | |
344 if (privateKeyPath.empty()) | |
345 { | |
346 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
347 "No path to the private key for the default DICOM TLS certificate was provided"); | |
348 } | |
349 | |
350 if (!SystemToolbox::IsRegularFile(privateKeyPath)) | |
351 { | |
352 throw OrthancException(ErrorCode_InexistentFile, "Inexistent file: " + privateKeyPath); | |
353 } | |
354 | |
355 if (!SystemToolbox::IsRegularFile(certificatePath)) | |
356 { | |
357 throw OrthancException(ErrorCode_InexistentFile, "Inexistent file: " + certificatePath); | |
358 } | |
359 | |
360 { | |
361 boost::mutex::scoped_lock lock(defaultConfigurationMutex_); | |
362 defaultOwnPrivateKeyPath_ = privateKeyPath; | |
363 defaultOwnCertificatePath_ = certificatePath; | |
364 } | |
365 } | |
366 else | |
367 { | |
368 boost::mutex::scoped_lock lock(defaultConfigurationMutex_); | |
369 defaultOwnPrivateKeyPath_.clear(); | |
370 defaultOwnCertificatePath_.clear(); | |
371 } | |
372 } | |
373 | |
374 | |
375 void DicomAssociationParameters::SetDefaultTrustedCertificatesPath(const std::string& path) | |
376 { | |
377 if (!path.empty()) | |
378 { | |
379 CLOG(INFO, DICOM) << "Setting the default trusted certificates for DICOM SCU connections: " << path; | |
380 | |
381 if (!SystemToolbox::IsRegularFile(path)) | |
382 { | |
383 throw OrthancException(ErrorCode_InexistentFile, "Inexistent file: " + path); | |
384 } | |
385 | |
386 { | |
387 boost::mutex::scoped_lock lock(defaultConfigurationMutex_); | |
388 defaultTrustedCertificatesPath_ = path; | |
389 } | |
390 } | |
391 else | |
392 { | |
393 boost::mutex::scoped_lock lock(defaultConfigurationMutex_); | |
394 defaultTrustedCertificatesPath_.clear(); | |
395 } | |
396 } | |
194 } | 397 } |