300 lines
12 KiB
C++
300 lines
12 KiB
C++
/*
|
|
*
|
|
* Copyright (C) 1998-2015, OFFIS e.V.
|
|
* All rights reserved. See COPYRIGHT file for details.
|
|
*
|
|
* This software and supporting documentation were developed by
|
|
*
|
|
* OFFIS e.V.
|
|
* R&D Division Health
|
|
* Escherweg 2
|
|
* D-26121 Oldenburg, Germany
|
|
*
|
|
*
|
|
* Module: dcmtls
|
|
*
|
|
* Author: Marco Eichelberg
|
|
*
|
|
* Purpose:
|
|
* classes: DcmTLSTransportLayer
|
|
*
|
|
*/
|
|
|
|
#ifndef TLSLAYER_H
|
|
#define TLSLAYER_H
|
|
|
|
#include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
|
|
#include "dcmtk/dcmnet/dcmlayer.h" /* for DcmTransportLayer */
|
|
#include "dcmtk/ofstd/ofstream.h" /* for ostream */
|
|
#include "dcmtk/oflog/oflog.h"
|
|
#include "dcmtk/dcmtls/tlsdefin.h"
|
|
|
|
#ifdef WITH_OPENSSL
|
|
BEGIN_EXTERN_C
|
|
#include <openssl/ssl.h>
|
|
END_EXTERN_C
|
|
|
|
extern DCMTK_DCMTLS_EXPORT OFLogger DCM_dcmtlsLogger;
|
|
|
|
#define DCMTLS_TRACE(msg) OFLOG_TRACE(DCM_dcmtlsLogger, msg)
|
|
#define DCMTLS_DEBUG(msg) OFLOG_DEBUG(DCM_dcmtlsLogger, msg)
|
|
#define DCMTLS_INFO(msg) OFLOG_INFO(DCM_dcmtlsLogger, msg)
|
|
#define DCMTLS_WARN(msg) OFLOG_WARN(DCM_dcmtlsLogger, msg)
|
|
#define DCMTLS_ERROR(msg) OFLOG_ERROR(DCM_dcmtlsLogger, msg)
|
|
#define DCMTLS_FATAL(msg) OFLOG_FATAL(DCM_dcmtlsLogger, msg)
|
|
|
|
/** this enum describes how to handle X.509 certificates on a TLS based
|
|
* secure transport connection. They can be ignored, validated if present
|
|
* or validated and demanded.
|
|
*/
|
|
enum DcmCertificateVerification
|
|
{
|
|
/** check peer certificate, fail if no certificate is present
|
|
*/
|
|
DCV_requireCertificate,
|
|
|
|
/** check peer certificate if present, succeed if no certificate is present
|
|
*/
|
|
DCV_checkCertificate,
|
|
|
|
/** do not check peer certificate
|
|
*/
|
|
DCV_ignoreCertificate
|
|
};
|
|
|
|
|
|
/** factory class which creates secure TLS transport layer connections
|
|
* and maintains the parameters common to all TLS transport connections
|
|
* in one application (e.g. the pool of trusted certificates, the key
|
|
* and certificate to be used for authentication and the list of
|
|
* ciphersuite to be used for association negotiation.
|
|
*/
|
|
|
|
class DCMTK_DCMTLS_EXPORT DcmTLSTransportLayer: public DcmTransportLayer
|
|
{
|
|
public:
|
|
|
|
/** a type alias for the type of the underlying OpenSSL context handle to be
|
|
* used in conjunction with the getNativeHandle() member function.
|
|
*/
|
|
typedef SSL_CTX* native_handle_type;
|
|
|
|
/** constructor.
|
|
* @param networkRole network role to be used by the application, influences
|
|
* the choice of the secure transport layer code.
|
|
* @param randFile path to file used to feed the random generator
|
|
* @param initializeOpenSSL Determines if OpenSSL library should be initialized.
|
|
* Some setups (e.g. multi-threaded environments) may be interested in using
|
|
* more than one TLS transport layer at a time and thus must make sure the
|
|
* library is only initialized once.
|
|
*/
|
|
DcmTLSTransportLayer(int networkRole, const char *randFile, OFBool initializeOpenSSL = OFTrue);
|
|
|
|
/// destructor
|
|
virtual ~DcmTLSTransportLayer();
|
|
|
|
/** factory method that returns a new transport connection for the
|
|
* given socket. Depending on the second parameter, either a transparent
|
|
* or a secure connection is established. If the object cannot be created
|
|
* (e. g. because no secure layer is available), returns NULL.
|
|
* @param openSocket TCP/IP socket to be used for the transport connection.
|
|
* the connection must already be establised on socket level. If a non-null
|
|
* pointer is returned, the new connection object takes over control of the socket.
|
|
* @param useSecureLayer if true, a secure layer is used. If false, a
|
|
* transparent layer is used.
|
|
* @return pointer to new connection object if successful, NULL otherwise.
|
|
*/
|
|
virtual DcmTransportConnection *createConnection(int openSocket, OFBool useSecureLayer);
|
|
|
|
/** loads the private key used for authentication of this application from a file.
|
|
* @param fileName path to the private key file
|
|
* @param fileType, must be SSL_FILETYPE_PEM or SSL_FILETYPE_ASN1
|
|
* @return TCS_ok if successful, an error code otherwise
|
|
*/
|
|
DcmTransportLayerStatus setPrivateKeyFile(const char *fileName, int fileType);
|
|
|
|
/** loads the certificate (public key) used for authentication of this application from a file.
|
|
* @param fileName path to the certificate file
|
|
* @param fileType, must be SSL_FILETYPE_PEM or SSL_FILETYPE_ASN1
|
|
* @return TCS_ok if successful, an error code otherwise
|
|
*/
|
|
DcmTransportLayerStatus setCertificateFile(const char *fileName, int fileType);
|
|
|
|
/** checks if the private key and the certificate set using setPrivateKeyFile()
|
|
* and setCertificateFile() match, i.e. if they establish a private/public key pair.
|
|
* @return OFTrue if private key and certificate match, OFFalse otherwise.
|
|
*/
|
|
OFBool checkPrivateKeyMatchesCertificate();
|
|
|
|
/** loads a certificate from a file and adds it to the pool of trusted certificates.
|
|
* @param fileName path to the certificate file
|
|
* @param fileType, must be SSL_FILETYPE_PEM or SSL_FILETYPE_ASN1
|
|
* @return TCS_ok if successful, an error code otherwise
|
|
*/
|
|
DcmTransportLayerStatus addTrustedCertificateFile(const char *fileName, int fileType);
|
|
|
|
/** loads all files as certificates from the specified directory and adds them
|
|
* to the pool of trusted certificates.
|
|
* @param fileName path to the directory containing certificate files
|
|
* @param fileType, must be SSL_FILETYPE_PEM or SSL_FILETYPE_ASN1
|
|
* @return TCS_ok if successful, an error code otherwise
|
|
*/
|
|
DcmTransportLayerStatus addTrustedCertificateDir(const char *pathName, int fileType);
|
|
|
|
/** loads certificates from a file and adds them to the pool of trusted client
|
|
* certificates.
|
|
* @param fileName path to the certificate file
|
|
* @return TCS_ok if successful, an error code otherwise
|
|
*/
|
|
DcmTransportLayerStatus addTrustedClientCertificateFile(const char *fileName);
|
|
|
|
/** appends the given verification flags to the existing ones in this OpenSSL context
|
|
* (using binary or).
|
|
* @warning Documentation for the underlying OpenSSL functions is not available,
|
|
* therefore, these semantics were guessed based on looking at the OpenSSL source
|
|
* code!
|
|
* @param flags the verification flags to append, e. g. X509_V_FLAG_CRL_CHECK.
|
|
* @return TCS_ok if the flags were appended to the existing ones, TCS_unspecifiedError
|
|
* if OpenSSL returns an (unspecified, since the documentation is missing) error.
|
|
*/
|
|
DcmTransportLayerStatus addVerificationFlags(unsigned long flags);
|
|
|
|
/** sets the list of ciphersuites to negotiate.
|
|
* @param suites string containing the list of ciphersuites.
|
|
* The list must be in OpenSSL syntax (use findOpenSSLCipherSuiteName to convert
|
|
* from RFC 2246 ciphersuite names to OpenSSL names), with ciphersuites separated
|
|
* by ':' characters.
|
|
* @return TCS_ok if successful, an error code otherwise
|
|
*/
|
|
DcmTransportLayerStatus setCipherSuites(const char *suites);
|
|
|
|
/** returns the number of known ciphersuites.
|
|
* @return number of known ciphersuites
|
|
*/
|
|
static unsigned long getNumberOfCipherSuites();
|
|
|
|
/** returns a ciphersuite name in RFC 2246 (TLS) form
|
|
* @param idx index, must be < getNumberOfCipherSuites()
|
|
* @return ciphersuite name
|
|
*/
|
|
static const char *getTLSCipherSuiteName(unsigned long idx);
|
|
|
|
/** returns a ciphersuite name in OpenSSL form
|
|
* @param idx index, must be < getNumberOfCipherSuites()
|
|
* @return ciphersuite name
|
|
*/
|
|
static const char *getOpenSSLCipherSuiteName(unsigned long idx);
|
|
|
|
/** finds the OpenSSL ciphersuite name for a given RFC 2246 ciphersuite name.
|
|
* @param tlsCipherSuiteName ciphersuite name in RFC 2246 form
|
|
* @returns ciphersuite name in OpenSSL form, NULL if unknown.
|
|
*/
|
|
static const char *findOpenSSLCipherSuiteName(const char *tlsCipherSuiteName);
|
|
|
|
/** checks if enough entropy data is available to write back a modified
|
|
* random seed file.
|
|
* @return OFTrue if random seed file can be written, OFFalse otherwise.
|
|
*/
|
|
OFBool canWriteRandomSeed() { return canWriteRandseed; }
|
|
|
|
/** writes a modified random seed to file.
|
|
* @param randFile path of file to write
|
|
* @return OFTrue if successful, OFFalse otherwise.
|
|
*/
|
|
OFBool writeRandomSeed(const char *randFile);
|
|
|
|
/** adds the contents of a file to the seed for the cryptographic
|
|
* pseudo-random number generator. The file should contain real
|
|
* random entropy data gathered from keystrokes, system events,
|
|
* /dev/random (on Linux) or something similar.
|
|
* If the TLS layer object is not initialized with sufficient
|
|
* random data, negotiation of TLS connections may fail.
|
|
* @param randFile path of the file containing random data
|
|
*/
|
|
void seedPRNG(const char *randFile);
|
|
|
|
/** modifies the PRNG by adding random data from the given buffer
|
|
* to the PRNG state.
|
|
* @param buf pointer to buffer containing random data
|
|
* @bufSize number of bytes in buffer
|
|
*/
|
|
void addPRNGseed(void *buf, size_t bufSize);
|
|
|
|
/** defines how peer certificates should be treated when
|
|
* negotiating a TLS connection.
|
|
* @param vtype certificate verification mode
|
|
*/
|
|
void setCertificateVerification(DcmCertificateVerification vtype);
|
|
|
|
/** sets the password string to be used when loading an
|
|
* encrypted private key file.
|
|
* Must be called prior to setPrivateKeyFile() in order to be effective.
|
|
* @param thePasswd password string, may be "" or NULL in which case an empty
|
|
* password is assumed.
|
|
*/
|
|
void setPrivateKeyPasswd(const char *thePasswd);
|
|
|
|
/** sets the password string to be used when loading an
|
|
* encrypted private key file to be read from the console stdin.
|
|
*/
|
|
void setPrivateKeyPasswdFromConsole();
|
|
|
|
/** loads a set of Diffie-Hellman parameters from file.
|
|
* These parameters are required for DH, DHE or DSS ciphersuites.
|
|
* @param filename path to the DH parameter file
|
|
* @return OFTrue if successful, OFFalse otherwise.
|
|
*/
|
|
OFBool setTempDHParameters(const char *filename);
|
|
|
|
/** gets the most important attributes of the given X.509 certificate.
|
|
* @param peerCertificate X.509 certificate, may be NULL
|
|
* @return a string describing the certificate
|
|
*/
|
|
static OFString dumpX509Certificate(X509 *peerCertificate);
|
|
|
|
/** provides access to the underlying OpenSSL context handle for implementing
|
|
* custom functionality not accessible by the existing member functions of
|
|
* DcmTLSTransportLayer.
|
|
* @return the underlying OpenSSL context handle.
|
|
* @details
|
|
* <h4>Usage Example</h4>
|
|
* @code{.cpp}
|
|
* DcmTLSTransportLayer tLayer(DICOM_APPLICATION_REQUESTOR, "random.dat");
|
|
* ...
|
|
* DcmTLSTransportLayer::native_handle_type native = tlayer.getNativeHandle();
|
|
* X509_VERIFY_PARAM* param = SSL_CTX_get0_param(native);
|
|
*
|
|
* // Enable automatic hostname checks
|
|
* X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
|
* X509_VERIFY_PARAM_set1_host(param, "www.example.com", 0);
|
|
*
|
|
* // Configure a non-zero callback if desired
|
|
* SSL_CTX_set_verify(native, SSL_VERIFY_PEER, 0);
|
|
* ...
|
|
* @endcode
|
|
*/
|
|
native_handle_type getNativeHandle();
|
|
|
|
private:
|
|
|
|
/// private undefined copy constructor
|
|
DcmTLSTransportLayer(const DcmTLSTransportLayer&);
|
|
|
|
/// private undefined assignment operator
|
|
DcmTLSTransportLayer& operator=(const DcmTLSTransportLayer&);
|
|
|
|
/// OpenSSL context data, needed only once per application
|
|
SSL_CTX *transportLayerContext;
|
|
|
|
/// true if there is enough random data to write a new random seed file
|
|
OFBool canWriteRandseed;
|
|
|
|
/// contains the password for the private key if set on command line
|
|
OFString privateKeyPasswd;
|
|
|
|
};
|
|
|
|
#endif /* WITH_OPENSSL */
|
|
|
|
#endif
|