Skip to content

Commit

Permalink
Added TLS support to getscu.
Browse files Browse the repository at this point in the history
Added TLS support to the getscu tool.
  • Loading branch information
Marco Eichelberg committed Jan 29, 2024
1 parent c791af7 commit 392e6a5
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 18 deletions.
2 changes: 1 addition & 1 deletion dcmnet/apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ endif()
foreach(PROGRAM dcmrecv dcmsend echoscu findscu getscu movescu storescp storescu termscu)
DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmnet dcmdata oflog ofstd)
endforeach()
foreach(PROGRAM dcmrecv echoscu findscu storescp storescu)
foreach(PROGRAM dcmrecv echoscu findscu storescp storescu getscu)
DCMTK_TARGET_LINK_MODULES(${PROGRAM} dcmtls)
endforeach()

Expand Down
2 changes: 1 addition & 1 deletion dcmnet/apps/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ termscu: termscu.o
$(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)

getscu: getscu.o
$(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(LIBS)
$(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(LOCALLIBS) $(DCMTLSLIBS) $(OPENSSLLIBS) $(LIBS)

dcmsend: dcmsend.o
$(CXX) $(CXXFLAGS) $(LIBDIRS) $(LDFLAGS) -o $@ $@.o $(COMPR_LIBS) $(LOCALLIBS) $(TIFFLIBS) $(PNGLIBS) $(LIBS)
Expand Down
49 changes: 43 additions & 6 deletions dcmnet/apps/getscu.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (C) 2011-2022, OFFIS e.V.
* Copyright (C) 2011-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
Expand All @@ -27,6 +27,7 @@
#include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version name */
#include "dcmtk/dcmdata/dcostrmz.h" /* for dcmZlibCompressionLevel */
#include "dcmtk/dcmdata/dcpath.h" /* for DcmPathProcessor */
#include "dcmtk/dcmtls/tlsopt.h" /* for DcmTLSOptions */

#ifdef WITH_ZLIB
#include <zlib.h> /* for zlibVersion() */
Expand Down Expand Up @@ -85,12 +86,16 @@ main(int argc, char *argv[])
const char *opt_peerTitle = PEERAPPLICATIONTITLE;
const char *opt_ourTitle = APPLICATIONTITLE;
OFList<OFString> fileNameList;

DcmTLSOptions tlsOptions(NET_REQUESTOR);
char tempstr[20];
OFString temp_str;
OFConsoleApplication app(OFFIS_CONSOLE_APPLICATION , "DICOM retrieve (C-GET) SCU", rcsid);
OFCommandLine cmd;

#ifdef WITH_OPENSSL
DcmTLSTransportLayer::initializeOpenSSL();
#endif

cmd.setParamColumn(LONGCOL + SHORTCOL + 4);
cmd.addParam("peer", "hostname of DICOM peer");
cmd.addParam("port", "tcp/ip port number of peer");
Expand Down Expand Up @@ -172,6 +177,10 @@ main(int argc, char *argv[])
cmd.addOption("--max-pdu", "-pdu", 1, opt4.c_str(), opt3.c_str());
cmd.addOption("--repeat", 1, "[n]umber: integer", "repeat n times");
cmd.addOption("--abort", "abort association instead of releasing it");

// add TLS specific command line options if (and only if) we are compiling with OpenSSL
tlsOptions.addTLSCommandlineOptions(cmd);

cmd.addGroup("output options:");
cmd.addSubGroup("general:");
cmd.addOption("--output-directory", "-od", 1, "[d]irectory: string (default: \".\")", "write received objects to existing directory d");
Expand All @@ -191,15 +200,26 @@ main(int argc, char *argv[])
{
app.printHeader(OFTrue /*print host identifier*/);
COUT << OFendl << "External libraries used:";
#ifdef WITH_ZLIB
#ifdef WITH_ZLIB
COUT << OFendl << "- ZLIB, Version " << zlibVersion() << OFendl;
#else
#endif
// print OpenSSL version if (and only if) we are compiling with OpenSSL
tlsOptions.printLibraryVersion();

#if !defined(WITH_ZLIB) && !defined(WITH_OPENSSL)
COUT << " none" << OFendl;
#endif
#endif
return 0;
}
}

// check if the command line contains the --list-ciphers option
if (tlsOptions.listOfCiphersRequested(cmd))
{
tlsOptions.printSupportedCiphersuites(app, COUT);
return 0;
}

/* general options */
OFLog::configureFromCommandLine(cmd, app);
if (cmd.findOption("--verbose-pc"))
Expand Down Expand Up @@ -292,6 +312,9 @@ main(int argc, char *argv[])
if (cmd.findOption("--abort")) opt_abortAssociation = OFTrue;
if (cmd.findOption("--ignore")) opt_storageMode = DCMSCU_STORAGE_IGNORE;

// evaluate (most of) the TLS command line options (if we are compiling with OpenSSL)
tlsOptions.parseArguments(app, cmd);

/* output options */
if (cmd.findOption("--output-directory"))
{
Expand Down Expand Up @@ -396,13 +419,27 @@ main(int argc, char *argv[])
scu.setStorageDir(opt_outputDirectory);
}

/* create a secure transport layer if requested and OpenSSL is available */
OFCondition cond = tlsOptions.createTransportLayer(NULL, NULL, app, cmd);
if (cond.bad())
{
OFString tempStr;
OFLOG_FATAL(getscuLogger, DimseCondition::dump(tempStr, cond));
exit(1);
}

/* initialize network and negotiate association */
OFCondition cond = scu.initNetwork();
cond = scu.initNetwork();
if (cond.bad())
{
OFLOG_FATAL(getscuLogger, DimseCondition::dump(temp_str, cond));
exit(1);
}

/* make sure the server connection uses TLS if requested */
if (tlsOptions.secureConnectionRequested())
scu.useSecureConnection(tlsOptions.getTransportLayer());

cond = scu.negotiateAssociation();
if (cond.bad())
{
Expand Down
118 changes: 118 additions & 0 deletions dcmnet/docs/getscu.man
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,124 @@ other network options:
abort association instead of releasing it
\endverbatim

\subsection getscu_tls_options transport layer security (TLS) options
\verbatim
transport protocol stack:

-tls --disable-tls
use normal TCP/IP connection (default)

+tls --enable-tls [p]rivate key file, [c]ertificate file: string
use authenticated secure TLS connection

+tla --anonymous-tls
use secure TLS connection without certificate

private key password (only with --enable-tls):

+ps --std-passwd
prompt user to type password on stdin (default)

+pw --use-passwd [p]assword: string
use specified password

-pw --null-passwd
use empty string as password

key and certificate file format:

-pem --pem-keys
read keys and certificates as PEM file (default)

-der --der-keys
read keys and certificates as DER file

certification authority:

+cf --add-cert-file [f]ilename: string
add certificate file to list of certificates

+cd --add-cert-dir [d]irectory: string
add certificates in d to list of certificates

+crl --add-crl-file [f]ilename: string
add certificate revocation list file
(implies --enable-crl-vfy)

+crv --enable-crl-vfy
enable leaf CRL verification

+cra --enable-crl-all
enable full chain CRL verification

security profile:

+pg --profile-8996
BCP 195 RFC 8996 TLS Profile (default)

+pm --profile-8996-mod
Modified BCP 195 RFC 8996 TLS Profile

# only available if underlying TLS library supports
# all TLS features required for this profile

+py --profile-bcp195-nd
Non-downgrading BCP 195 TLS Profile (retired)

+px --profile-bcp195
BCP 195 TLS Profile (retired)

+pz --profile-bcp195-ex
Extended BCP 195 TLS Profile (retired)

+pb --profile-basic
Basic TLS Secure Transport Connection Profile (retired)

# only available if underlying TLS library supports 3DES

+pa --profile-aes
AES TLS Secure Transport Connection Profile (retired)

+pn --profile-null
Authenticated unencrypted communication
(retired, was used in IHE ATNA)

ciphersuite:

+cc --list-ciphers
list supported TLS ciphersuites and exit

+cs --cipher [c]iphersuite name: string
add ciphersuite to list of negotiated suites

server name indication:

--no-sni
do not use SNI (default)

--request-sni [s]erver name: string
request server name s

pseudo random generator:

+rs --seed [f]ilename: string
seed random generator with contents of f

+ws --write-seed
write back modified seed (only with --seed)

+wf --write-seed-file [f]ilename: string (only with --seed)
write modified seed to file f

peer authentication:

-rc --require-peer-cert
verify peer certificate, fail if absent (default)

-ic --ignore-peer-cert
don't verify peer certificate
\endverbatim

\subsection getscu_output_options output options
\verbatim
general:
Expand Down
23 changes: 14 additions & 9 deletions dcmnet/include/dcmtk/dcmnet/scu.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
* Copyright (C) 2008-2023, OFFIS e.V.
* Copyright (C) 2008-2024, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were developed by
Expand Down Expand Up @@ -822,13 +822,21 @@ class DCMTK_DCMNET_EXPORT DcmSCU
OFBool getProgressNotificationMode() const;

/** Returns whether SCU is configured to create a TLS connection with the SCP
* @return OFFalse for this class but may be overridden by derived classes
* @return OFTrue if TLS mode has been enabled, OFFalse otherwise
*/
OFBool getTLSEnabled() const;
virtual OFBool getTLSEnabled() const;

/** Deletes internal networking structures from memory */
void freeNetwork();

/** Tells DcmSCU to use a secure TLS connection described by the given TLS layer.
* The DcmSCU instance does not take ownership of the TLS layer object, i.e.
* it is the caller's responsibility to delete it after its use has ended.
* @param tlayer [in] The TLS transport layer including all TLS parameters
* @return EC_Normal if given transport layer is ok, an error code otherwise
*/
OFCondition useSecureConnection(DcmTransportLayer* tlayer);

protected:
/** Sends a DIMSE command and possibly also a dataset from a data object via network to
* another DICOM application
Expand Down Expand Up @@ -861,12 +869,6 @@ class DCMTK_DCMNET_EXPORT DcmSCU
OFString& sopInstanceUID,
E_TransferSyntax& transferSyntax);

/** Tells DcmSCU to use a secure TLS connection described by the given TLS layer
* @param tlayer [in] The TLS transport layer including all TLS parameters
* @return EC_Normal if given transport layer is ok, an error code otherwise
*/
OFCondition useSecureConnection(DcmTransportLayer* tlayer);

/** Receive DIMSE command (excluding dataset!) over the currently open association
* @param presID [out] Contains in the end the ID of the presentation context
* which was specified in the DIMSE command received
Expand Down Expand Up @@ -1120,6 +1122,9 @@ class DCMTK_DCMNET_EXPORT DcmSCU

/// Progress notification mode (default: enabled)
OFBool m_progressNotificationMode;

/// Flag indicating whether secure mode has been enabled (default: disabled)
OFBool m_secureConnectionEnabled;
};

#endif // SCU_H
5 changes: 4 additions & 1 deletion dcmnet/libsrc/scu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ DcmSCU::DcmSCU()
, m_verbosePCMode(OFFalse)
, m_datasetConversionMode(OFFalse)
, m_progressNotificationMode(OFTrue)
, m_secureConnectionEnabled(OFFalse)
{
OFStandard::initializeNetwork();
}
Expand Down Expand Up @@ -337,6 +338,8 @@ OFCondition DcmSCU::useSecureConnection(DcmTransportLayer* tlayer)
OFCondition cond = ASC_setTransportLayer(m_net, tlayer, OFFalse /* do not take over ownership */);
if (cond.good())
cond = ASC_setTransportLayerType(m_params, OFTrue /* use TLS */);

if (cond.good()) m_secureConnectionEnabled = OFTrue;
return cond;
}

Expand Down Expand Up @@ -2607,7 +2610,7 @@ Uint32 DcmSCU::getMaxReceivePDULength() const

OFBool DcmSCU::getTLSEnabled() const
{
return OFFalse;
return m_secureConnectionEnabled;
}

T_DIMSE_BlockingMode DcmSCU::getDIMSEBlockingMode() const
Expand Down

0 comments on commit 392e6a5

Please sign in to comment.