Mercurial > hg > orthanc
diff OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp @ 5643:b1a18218860c
2 new configurations: DicomTlsMinimumProtocolVersion + DicomTlsCiphersAccepted
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Fri, 31 May 2024 16:56:35 +0200 |
parents | f7adfb22e20e |
children | 343149762476 |
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp Fri May 31 09:20:35 2024 +0200 +++ b/OrthancFramework/Sources/DicomNetworking/Internals/DicomTls.cpp Fri May 31 16:56:35 2024 +0200 @@ -28,6 +28,9 @@ #include "../../Logging.h" #include "../../OrthancException.h" #include "../../SystemToolbox.h" +#include "../../Toolbox.h" +#include <openssl/ssl.h> +#include <openssl/err.h> #if DCMTK_VERSION_NUMBER < 364 # define DCF_Filetype_PEM SSL_FILETYPE_PEM @@ -63,7 +66,9 @@ const std::string& ownPrivateKeyPath, const std::string& ownCertificatePath, const std::string& trustedCertificatesPath, - bool requireRemoteCertificate) + bool requireRemoteCertificate, + unsigned int minimalTlsVersion, + const std::set<std::string>& ciphers) { if (network == NULL) { @@ -156,14 +161,94 @@ } #if DCMTK_VERSION_NUMBER >= 364 - if (IsFailure(tls->setTLSProfile(TSP_Profile_BCP195 /*opt_tlsProfile*/))) + if (minimalTlsVersion == 0) // use the default values (same behavior as before 1.12.4) { - throw OrthancException(ErrorCode_InternalError, "Cannot set the DICOM TLS profile"); + if (ciphers.size() > 0) + { + throw OrthancException(ErrorCode_BadFileFormat, "The cipher suites can not be specified when using the default BCP profile"); + } + + if (IsFailure(tls->setTLSProfile(TSP_Profile_BCP195 /*opt_tlsProfile*/))) + { + throw OrthancException(ErrorCode_InternalError, "Cannot set the DICOM TLS profile"); + } + + if (IsFailure(tls->activateCipherSuites())) + { + throw OrthancException(ErrorCode_InternalError, "Cannot activate the cipher suites for DICOM TLS"); + } } - - if (IsFailure(tls->activateCipherSuites())) + else { - throw OrthancException(ErrorCode_InternalError, "Cannot activate the cipher suites for DICOM TLS"); + // Fine tune the SSL context + if (IsFailure(tls->setTLSProfile(TSP_Profile_None))) + { + throw OrthancException(ErrorCode_InternalError, "Cannot set the DICOM TLS profile"); + } + + DcmTLSTransportLayer::native_handle_type sslNativeHandle = tls->getNativeHandle(); + SSL_CTX_clear_options(sslNativeHandle, SSL_OP_NO_SSL_MASK); + if (minimalTlsVersion > 1) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_SSLv3); + } + if (minimalTlsVersion > 2) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_TLSv1); + } + if (minimalTlsVersion > 3) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_TLSv1_1); + } + if (minimalTlsVersion > 4) + { + SSL_CTX_set_options(sslNativeHandle, SSL_OP_NO_TLSv1_2); + } + + std::set<std::string> ciphersTls; + std::set<std::string> ciphersTls13; + + // DCMTK 3.8 is missing a method to add TLS13 cipher suite in the DcmTLSTransportLayer interface. + // And, anyway, since we do not run dcmtkPrepare.cmake, DCMTK is not aware of TLS v1.3 cipher suite names. + for (std::set<std::string>::const_iterator it = ciphers.begin(); it != ciphers.end(); ++it) + { + bool isValid = false; + if (DcmTLSCiphersuiteHandler::lookupCiphersuiteByOpenSSLName(it->c_str()) != DcmTLSCiphersuiteHandler::unknownCipherSuiteIndex) + { + ciphersTls.insert(it->c_str()); + isValid = true; + } + + // list of TLS v1.3 ciphers according to https://www.openssl.org/docs/man3.3/man1/openssl-ciphers.html + if (strstr("TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_128_CCM_8_SHA256", it->c_str()) != NULL) + { + ciphersTls13.insert(it->c_str()); + isValid = true; + } + + if (!isValid) + { + throw OrthancException(ErrorCode_BadFileFormat, "The cipher suite " + *it + " is not recognized as valid cipher suite by OpenSSL "); + } + } + + std::string joinedCiphersTls; + std::string joinedCiphersTls13; + Toolbox::JoinStrings(joinedCiphersTls, ciphersTls, ":"); + Toolbox::JoinStrings(joinedCiphersTls13, ciphersTls13, ":"); + + if (joinedCiphersTls.size() > 0 && SSL_CTX_set_cipher_list(sslNativeHandle, joinedCiphersTls.c_str()) != 1) + { + OFCondition cond = DcmTLSTransportLayer::convertOpenSSLError(ERR_get_error(), OFTrue); + throw OrthancException(ErrorCode_InternalError, "Unable to configure cipher suite. OpenSSL error: " + boost::lexical_cast<std::string>(cond.code()) + " - " + cond.text()); + } + + if (joinedCiphersTls13.size() > 0 && SSL_CTX_set_ciphersuites(sslNativeHandle, joinedCiphersTls13.c_str()) != 1) + { + OFCondition cond = DcmTLSTransportLayer::convertOpenSSLError(ERR_get_error(), OFTrue); + throw OrthancException(ErrorCode_InternalError, "Unable to configure cipher suite for TLS 1.3. OpenSSL error: " + boost::lexical_cast<std::string>(cond.code()) + " - " + cond.text()); + } + } #else CLOG(INFO, DICOM) << "Using the following cipher suites for DICOM TLS: " << opt_ciphersuites;