4432
|
1 /**
|
|
2 * Orthanc - A Lightweight, RESTful DICOM Store
|
|
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
|
|
4 * Department, University Hospital of Liege, Belgium
|
|
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
|
|
6 *
|
|
7 * This program is free software: you can redistribute it and/or
|
|
8 * modify it under the terms of the GNU Lesser General Public License
|
|
9 * as published by the Free Software Foundation, either version 3 of
|
|
10 * the License, or (at your option) any later version.
|
|
11 *
|
|
12 * This program is distributed in the hope that it will be useful, but
|
|
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
15 * Lesser General Public License for more details.
|
|
16 *
|
|
17 * You should have received a copy of the GNU Lesser General Public
|
|
18 * License along with this program. If not, see
|
|
19 * <http://www.gnu.org/licenses/>.
|
|
20 **/
|
|
21
|
|
22
|
|
23 #include "../../PrecompiledHeaders.h"
|
|
24 #include "DicomTls.h"
|
|
25
|
|
26 #include "../../Logging.h"
|
|
27 #include "../../OrthancException.h"
|
|
28 #include "../../SystemToolbox.h"
|
|
29
|
|
30
|
|
31 #if DCMTK_VERSION_NUMBER < 364
|
|
32 # define DCF_Filetype_PEM SSL_FILETYPE_PEM
|
|
33 # if OPENSSL_VERSION_NUMBER >= 0x0090700fL
|
|
34 // This seems to correspond to TSP_Profile_AES: https://support.dcmtk.org/docs/tlsciphr_8h.html
|
|
35 static std::string opt_ciphersuites(TLS1_TXT_RSA_WITH_AES_128_SHA ":" SSL3_TXT_RSA_DES_192_CBC3_SHA);
|
|
36 # else
|
|
37 // This seems to correspond to TSP_Profile_Basic in DCMTK >= 3.6.4: https://support.dcmtk.org/docs/tlsciphr_8h.html
|
|
38 static std::string opt_ciphersuites(SSL3_TXT_RSA_DES_192_CBC3_SHA);
|
|
39 # endif
|
|
40 #endif
|
|
41
|
|
42
|
|
43 namespace Orthanc
|
|
44 {
|
|
45 namespace Internals
|
|
46 {
|
|
47 DcmTLSTransportLayer* InitializeDicomTls(T_ASC_Network *network,
|
|
48 T_ASC_NetworkRole role,
|
|
49 const std::string& ownPrivateKeyFile,
|
|
50 const std::string& ownCertificateFile,
|
|
51 const std::string& trustedCertificatesFile)
|
|
52 {
|
|
53 if (network == NULL)
|
|
54 {
|
|
55 throw OrthancException(ErrorCode_NullPointer);
|
|
56 }
|
|
57
|
|
58 if (role != NET_ACCEPTOR &&
|
|
59 role != NET_REQUESTOR)
|
|
60 {
|
|
61 throw OrthancException(ErrorCode_ParameterOutOfRange, "Unknown role");
|
|
62 }
|
|
63
|
|
64 if (!SystemToolbox::IsRegularFile(trustedCertificatesFile))
|
|
65 {
|
|
66 throw OrthancException(ErrorCode_InexistentFile, "Cannot read file with trusted certificates for DICOM TLS: " +
|
|
67 trustedCertificatesFile);
|
|
68 }
|
|
69
|
|
70 if (!SystemToolbox::IsRegularFile(ownPrivateKeyFile))
|
|
71 {
|
|
72 throw OrthancException(ErrorCode_InexistentFile, "Cannot read file with own private key for DICOM TLS: " +
|
|
73 ownPrivateKeyFile);
|
|
74 }
|
|
75
|
|
76 if (!SystemToolbox::IsRegularFile(ownCertificateFile))
|
|
77 {
|
|
78 throw OrthancException(ErrorCode_InexistentFile, "Cannot read file with own certificate for DICOM TLS: " +
|
|
79 ownCertificateFile);
|
|
80 }
|
|
81
|
|
82 CLOG(INFO, DICOM) << "Initializing DICOM TLS for Orthanc "
|
|
83 << (role == NET_ACCEPTOR ? "SCP" : "SCU");
|
|
84
|
|
85 #if DCMTK_VERSION_NUMBER >= 364
|
|
86 const T_ASC_NetworkRole tmpRole = role;
|
|
87 #else
|
|
88 int tmpRole;
|
|
89 switch (role)
|
|
90 {
|
|
91 case NET_ACCEPTOR:
|
|
92 tmpRole = DICOM_APPLICATION_ACCEPTOR;
|
|
93 break;
|
|
94
|
|
95 case NET_REQUESTOR:
|
|
96 tmpRole = DICOM_APPLICATION_REQUESTOR;
|
|
97 break;
|
|
98
|
|
99 default:
|
|
100 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
101 }
|
|
102 #endif
|
|
103
|
|
104 std::unique_ptr<DcmTLSTransportLayer> tls(
|
|
105 new DcmTLSTransportLayer(tmpRole /*opt_networkRole*/, NULL /*opt_readSeedFile*/,
|
|
106 OFFalse /*initializeOpenSSL, done by Orthanc::Toolbox::InitializeOpenSsl()*/));
|
|
107
|
|
108 if (tls->addTrustedCertificateFile(trustedCertificatesFile.c_str(), DCF_Filetype_PEM /*opt_keyFileFormat*/) != TCS_ok)
|
|
109 {
|
|
110 throw OrthancException(ErrorCode_BadFileFormat, "Cannot parse PEM file with trusted certificates for DICOM TLS: " +
|
|
111 trustedCertificatesFile);
|
|
112 }
|
|
113
|
|
114 if (tls->setPrivateKeyFile(ownPrivateKeyFile.c_str(), DCF_Filetype_PEM /*opt_keyFileFormat*/) != TCS_ok)
|
|
115 {
|
|
116 throw OrthancException(ErrorCode_BadFileFormat, "Cannot parse PEM file with private key for DICOM TLS: " +
|
|
117 ownPrivateKeyFile);
|
|
118 }
|
|
119
|
|
120 if (tls->setCertificateFile(ownCertificateFile.c_str(), DCF_Filetype_PEM /*opt_keyFileFormat*/) != TCS_ok)
|
|
121 {
|
|
122 throw OrthancException(ErrorCode_BadFileFormat, "Cannot parse PEM file with own certificate for DICOM TLS: " +
|
|
123 ownCertificateFile);
|
|
124 }
|
|
125
|
|
126 if (!tls->checkPrivateKeyMatchesCertificate())
|
|
127 {
|
|
128 throw OrthancException(ErrorCode_BadFileFormat, "The private key doesn't match the own certificate: " +
|
|
129 ownPrivateKeyFile + " vs. " + ownCertificateFile);
|
|
130 }
|
|
131
|
|
132 #if DCMTK_VERSION_NUMBER >= 364
|
|
133 if (tls->setTLSProfile(TSP_Profile_BCP195 /*opt_tlsProfile*/) != TCS_ok)
|
|
134 {
|
|
135 throw OrthancException(ErrorCode_InternalError, "Cannot set the DICOM TLS profile");
|
|
136 }
|
|
137
|
|
138 if (tls->activateCipherSuites())
|
|
139 {
|
|
140 throw OrthancException(ErrorCode_InternalError, "Cannot activate the cipher suites for DICOM TLS");
|
|
141 }
|
|
142 #else
|
|
143 CLOG(INFO, DICOM) << "Using the following cipher suites for DICOM TLS: " << opt_ciphersuites;
|
|
144 if (tls->setCipherSuites(opt_ciphersuites.c_str()) != TCS_ok)
|
|
145 {
|
|
146 throw OrthancException(ErrorCode_InternalError, "Unable to set cipher suites to: " + opt_ciphersuites);
|
|
147 }
|
|
148 #endif
|
|
149
|
|
150 tls->setCertificateVerification(DCV_requireCertificate /*opt_certVerification*/);
|
|
151
|
|
152 if (ASC_setTransportLayer(network, tls.get(), 0).bad())
|
|
153 {
|
|
154 throw OrthancException(ErrorCode_InternalError, "Cannot enable DICOM TLS in the Orthanc " +
|
|
155 std::string(role == NET_ACCEPTOR ? "SCP" : "SCU"));
|
|
156 }
|
|
157
|
|
158 return tls.release();
|
|
159 }
|
|
160 }
|
|
161 }
|