| 1 | // Copyright (C) 2021 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
| 3 | |
| 4 | #ifndef QTLSBACKEND_P_H |
| 5 | #define QTLSBACKEND_P_H |
| 6 | |
| 7 | // |
| 8 | // W A R N I N G |
| 9 | // ------------- |
| 10 | // |
| 11 | // This file is not part of the Qt API. It exists purely as an |
| 12 | // implementation detail. This header file may change from version to |
| 13 | // version without notice, or even be removed. |
| 14 | // |
| 15 | // We mean it. |
| 16 | // |
| 17 | |
| 18 | #include <QtNetwork/private/qtnetworkglobal_p.h> |
| 19 | |
| 20 | #include "qsslconfiguration.h" |
| 21 | #include "qsslerror.h" |
| 22 | #include "qssl_p.h" |
| 23 | |
| 24 | #if QT_CONFIG(dtls) |
| 25 | #include "qdtls.h" |
| 26 | #endif |
| 27 | |
| 28 | #include <QtNetwork/qsslcertificate.h> |
| 29 | #include <QtNetwork/qsslcipher.h> |
| 30 | #include <QtNetwork/qsslkey.h> |
| 31 | #include <QtNetwork/qssl.h> |
| 32 | |
| 33 | #include <QtCore/qloggingcategory.h> |
| 34 | #include <QtCore/qnamespace.h> |
| 35 | #include <QtCore/qobject.h> |
| 36 | #include <QtCore/qglobal.h> |
| 37 | #include <QtCore/qstring.h> |
| 38 | #include <QtCore/qlist.h> |
| 39 | #include <QtCore/qmap.h> |
| 40 | |
| 41 | #include <memory> |
| 42 | |
| 43 | QT_BEGIN_NAMESPACE |
| 44 | |
| 45 | class QSslPreSharedKeyAuthenticator; |
| 46 | class QSslSocketPrivate; |
| 47 | class QHostAddress; |
| 48 | class QSslContext; |
| 49 | |
| 50 | class QSslSocket; |
| 51 | class QByteArray; |
| 52 | class QSslCipher; |
| 53 | class QUdpSocket; |
| 54 | class QIODevice; |
| 55 | class QSslError; |
| 56 | class QSslKey; |
| 57 | |
| 58 | namespace QTlsPrivate { |
| 59 | |
| 60 | class Q_NETWORK_EXPORT TlsKey { |
| 61 | public: |
| 62 | TlsKey() = default; |
| 63 | Q_DISABLE_COPY_MOVE(TlsKey) |
| 64 | |
| 65 | virtual ~TlsKey(); |
| 66 | |
| 67 | using KeyType = QSsl::KeyType; |
| 68 | using KeyAlgorithm = QSsl::KeyAlgorithm; |
| 69 | |
| 70 | virtual void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der, |
| 71 | const QByteArray &passPhrase, bool deepClear) = 0; |
| 72 | virtual void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem, |
| 73 | const QByteArray &passPhrase, bool deepClear) = 0; |
| 74 | |
| 75 | virtual QByteArray toPem(const QByteArray &passPhrase) const = 0; |
| 76 | virtual QByteArray derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *) const = 0; |
| 77 | virtual QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &) const = 0; |
| 78 | |
| 79 | virtual void fromHandle(Qt::HANDLE handle, KeyType type) = 0; |
| 80 | virtual Qt::HANDLE handle() const = 0; |
| 81 | |
| 82 | virtual bool isNull() const = 0; |
| 83 | virtual KeyType type() const = 0; |
| 84 | virtual KeyAlgorithm algorithm() const = 0; |
| 85 | virtual int length() const = 0; |
| 86 | |
| 87 | virtual void clear(bool deepClear) = 0; |
| 88 | |
| 89 | virtual bool isPkcs8() const = 0; |
| 90 | |
| 91 | virtual QByteArray decrypt(Cipher cipher, const QByteArray &data, |
| 92 | const QByteArray &passPhrase, const QByteArray &iv) const = 0; |
| 93 | virtual QByteArray encrypt(Cipher cipher, const QByteArray &data, |
| 94 | const QByteArray &key, const QByteArray &iv) const = 0; |
| 95 | |
| 96 | QByteArray () const; |
| 97 | QByteArray () const; |
| 98 | }; |
| 99 | |
| 100 | class Q_NETWORK_EXPORT X509Certificate |
| 101 | { |
| 102 | public: |
| 103 | virtual ~X509Certificate(); |
| 104 | |
| 105 | virtual bool isEqual(const X509Certificate &other) const = 0; |
| 106 | virtual bool isNull() const = 0; |
| 107 | virtual bool isSelfSigned() const = 0; |
| 108 | virtual QByteArray version() const = 0; |
| 109 | virtual QByteArray serialNumber() const = 0; |
| 110 | virtual QStringList issuerInfo(QSslCertificate::SubjectInfo subject) const = 0; |
| 111 | virtual QStringList issuerInfo(const QByteArray &attribute) const = 0; |
| 112 | virtual QStringList subjectInfo(QSslCertificate::SubjectInfo subject) const = 0; |
| 113 | virtual QStringList subjectInfo(const QByteArray &attribute) const = 0; |
| 114 | |
| 115 | virtual QList<QByteArray> subjectInfoAttributes() const = 0; |
| 116 | virtual QList<QByteArray> issuerInfoAttributes() const = 0; |
| 117 | virtual QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames() const = 0; |
| 118 | virtual QDateTime effectiveDate() const = 0; |
| 119 | virtual QDateTime expiryDate() const = 0; |
| 120 | |
| 121 | virtual TlsKey *publicKey() const; |
| 122 | |
| 123 | // Extensions. Plugins do not expose internal representation |
| 124 | // and cannot rely on QSslCertificate's internals. Thus, |
| 125 | // we provide this information 'in pieces': |
| 126 | virtual qsizetype numberOfExtensions() const = 0; |
| 127 | virtual QString oidForExtension(qsizetype i) const = 0; |
| 128 | virtual QString nameForExtension(qsizetype i) const = 0; |
| 129 | virtual QVariant valueForExtension(qsizetype i) const = 0; |
| 130 | virtual bool isExtensionCritical(qsizetype i) const = 0; |
| 131 | virtual bool isExtensionSupported(qsizetype i) const = 0; |
| 132 | |
| 133 | virtual QByteArray toPem() const = 0; |
| 134 | virtual QByteArray toDer() const = 0; |
| 135 | virtual QString toText() const = 0; |
| 136 | |
| 137 | virtual Qt::HANDLE handle() const = 0; |
| 138 | |
| 139 | virtual size_t hash(size_t seed) const noexcept = 0; |
| 140 | }; |
| 141 | |
| 142 | // TLSTODO: consider making those into virtuals in QTlsBackend. After all, we ask the backend |
| 143 | // to return those pointers if the functionality is supported, but it's a bit odd to have |
| 144 | // this level of indirection. They are not parts of the classes above because ... |
| 145 | // you'd then have to ask backend to create a certificate to ... call those |
| 146 | // functions on a certificate. |
| 147 | using X509ChainVerifyPtr = QList<QSslError> (*)(const QList<QSslCertificate> &chain, |
| 148 | const QString &hostName); |
| 149 | using X509PemReaderPtr = QList<QSslCertificate> (*)(const QByteArray &pem, int count); |
| 150 | using X509DerReaderPtr = X509PemReaderPtr; |
| 151 | using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertificate *cert, |
| 152 | QList<QSslCertificate> *caCertificates, |
| 153 | const QByteArray &passPhrase); |
| 154 | |
| 155 | #if QT_CONFIG(ssl) |
| 156 | // TLS over TCP. Handshake, encryption/decryption. |
| 157 | class Q_NETWORK_EXPORT TlsCryptograph : public QObject |
| 158 | { |
| 159 | public: |
| 160 | virtual ~TlsCryptograph(); |
| 161 | |
| 162 | virtual void init(QSslSocket *q, QSslSocketPrivate *d) = 0; |
| 163 | virtual void checkSettingSslContext(std::shared_ptr<QSslContext> tlsContext); |
| 164 | virtual std::shared_ptr<QSslContext> sslContext() const; |
| 165 | |
| 166 | virtual QList<QSslError> tlsErrors() const = 0; |
| 167 | |
| 168 | virtual void startClientEncryption() = 0; |
| 169 | virtual void startServerEncryption() = 0; |
| 170 | virtual void continueHandshake() = 0; |
| 171 | virtual void enableHandshakeContinuation(); |
| 172 | virtual void disconnectFromHost() = 0; |
| 173 | virtual void disconnected() = 0; |
| 174 | virtual void cancelCAFetch(); |
| 175 | virtual QSslCipher sessionCipher() const = 0; |
| 176 | virtual QSsl::SslProtocol sessionProtocol() const = 0; |
| 177 | |
| 178 | virtual void transmit() = 0; |
| 179 | virtual bool hasUndecryptedData() const; |
| 180 | virtual QList<QOcspResponse> ocsps() const; |
| 181 | |
| 182 | static bool isMatchingHostname(const QSslCertificate &cert, const QString &peerName); |
| 183 | |
| 184 | void setErrorAndEmit(QSslSocketPrivate *d, QAbstractSocket::SocketError errorCode, |
| 185 | const QString &errorDescription) const; |
| 186 | }; |
| 187 | #else |
| 188 | class TlsCryptograph; |
| 189 | #endif // QT_CONFIG(ssl) |
| 190 | |
| 191 | #if QT_CONFIG(dtls) |
| 192 | |
| 193 | class Q_NETWORK_EXPORT DtlsBase |
| 194 | { |
| 195 | public: |
| 196 | virtual ~DtlsBase(); |
| 197 | |
| 198 | virtual void setDtlsError(QDtlsError code, const QString &description) = 0; |
| 199 | |
| 200 | virtual QDtlsError error() const = 0; |
| 201 | virtual QString errorString() const = 0; |
| 202 | |
| 203 | virtual void clearDtlsError() = 0; |
| 204 | |
| 205 | virtual void setConfiguration(const QSslConfiguration &configuration) = 0; |
| 206 | virtual QSslConfiguration configuration() const = 0; |
| 207 | |
| 208 | using GenParams = QDtlsClientVerifier::GeneratorParameters; |
| 209 | virtual bool setCookieGeneratorParameters(const GenParams ¶ms) = 0; |
| 210 | virtual GenParams cookieGeneratorParameters() const = 0; |
| 211 | }; |
| 212 | |
| 213 | // DTLS cookie: generation and verification. |
| 214 | class Q_NETWORK_EXPORT DtlsCookieVerifier : virtual public DtlsBase |
| 215 | { |
| 216 | public: |
| 217 | virtual bool verifyClient(QUdpSocket *socket, const QByteArray &dgram, |
| 218 | const QHostAddress &address, quint16 port) = 0; |
| 219 | virtual QByteArray verifiedHello() const = 0; |
| 220 | }; |
| 221 | |
| 222 | // TLS over UDP. Handshake, encryption/decryption. |
| 223 | class Q_NETWORK_EXPORT DtlsCryptograph : virtual public DtlsBase |
| 224 | { |
| 225 | public: |
| 226 | |
| 227 | virtual QSslSocket::SslMode cryptographMode() const = 0; |
| 228 | virtual void setPeer(const QHostAddress &addr, quint16 port, const QString &name) = 0; |
| 229 | virtual QHostAddress peerAddress() const = 0; |
| 230 | virtual quint16 peerPort() const = 0; |
| 231 | virtual void setPeerVerificationName(const QString &name) = 0; |
| 232 | virtual QString peerVerificationName() const = 0; |
| 233 | |
| 234 | virtual void setDtlsMtuHint(quint16 mtu) = 0; |
| 235 | virtual quint16 dtlsMtuHint() const = 0; |
| 236 | |
| 237 | virtual QDtls::HandshakeState state() const = 0; |
| 238 | virtual bool isConnectionEncrypted() const = 0; |
| 239 | |
| 240 | virtual bool startHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0; |
| 241 | virtual bool handleTimeout(QUdpSocket *socket) = 0; |
| 242 | virtual bool continueHandshake(QUdpSocket *socket, const QByteArray &dgram) = 0; |
| 243 | virtual bool resumeHandshake(QUdpSocket *socket) = 0; |
| 244 | virtual void abortHandshake(QUdpSocket *socket) = 0; |
| 245 | virtual void sendShutdownAlert(QUdpSocket *socket) = 0; |
| 246 | |
| 247 | virtual QList<QSslError> peerVerificationErrors() const = 0; |
| 248 | virtual void ignoreVerificationErrors(const QList<QSslError> &errorsToIgnore) = 0; |
| 249 | |
| 250 | virtual QSslCipher dtlsSessionCipher() const = 0; |
| 251 | virtual QSsl::SslProtocol dtlsSessionProtocol() const = 0; |
| 252 | |
| 253 | virtual qint64 writeDatagramEncrypted(QUdpSocket *socket, const QByteArray &dgram) = 0; |
| 254 | virtual QByteArray decryptDatagram(QUdpSocket *socket, const QByteArray &dgram) = 0; |
| 255 | }; |
| 256 | |
| 257 | #else |
| 258 | |
| 259 | class DtlsCookieVerifier; |
| 260 | class DtlsCryptograph; |
| 261 | |
| 262 | #endif // QT_CONFIG(dtls) |
| 263 | |
| 264 | } // namespace QTlsPrivate |
| 265 | |
| 266 | // Factory, creating back-end specific implementations of |
| 267 | // different entities QSslSocket is using. |
| 268 | class Q_NETWORK_EXPORT QTlsBackend : public QObject |
| 269 | { |
| 270 | Q_OBJECT |
| 271 | public: |
| 272 | QTlsBackend(); |
| 273 | ~QTlsBackend() override; |
| 274 | |
| 275 | virtual bool isValid() const; |
| 276 | virtual long tlsLibraryVersionNumber() const; |
| 277 | virtual QString tlsLibraryVersionString() const; |
| 278 | virtual long tlsLibraryBuildVersionNumber() const; |
| 279 | virtual QString tlsLibraryBuildVersionString() const; |
| 280 | virtual void ensureInitialized() const; |
| 281 | |
| 282 | virtual QString backendName() const = 0; |
| 283 | virtual QList<QSsl::SslProtocol> supportedProtocols() const = 0; |
| 284 | virtual QList<QSsl::SupportedFeature> supportedFeatures() const = 0; |
| 285 | virtual QList<QSsl::ImplementedClass> implementedClasses() const = 0; |
| 286 | |
| 287 | // X509 and keys: |
| 288 | virtual QTlsPrivate::TlsKey *createKey() const; |
| 289 | virtual QTlsPrivate::X509Certificate *createCertificate() const; |
| 290 | |
| 291 | virtual QList<QSslCertificate> systemCaCertificates() const; |
| 292 | |
| 293 | // TLS and DTLS: |
| 294 | virtual QTlsPrivate::TlsCryptograph *createTlsCryptograph() const; |
| 295 | virtual QTlsPrivate::DtlsCryptograph *createDtlsCryptograph(class QDtls *qObject, int mode) const; |
| 296 | virtual QTlsPrivate::DtlsCookieVerifier *createDtlsCookieVerifier() const; |
| 297 | |
| 298 | // TLSTODO - get rid of these function pointers, make them virtuals in |
| 299 | // the backend itself. X509 machinery: |
| 300 | virtual QTlsPrivate::X509ChainVerifyPtr X509Verifier() const; |
| 301 | virtual QTlsPrivate::X509PemReaderPtr X509PemReader() const; |
| 302 | virtual QTlsPrivate::X509DerReaderPtr X509DerReader() const; |
| 303 | virtual QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const; |
| 304 | |
| 305 | // Elliptic curves: |
| 306 | virtual QList<int> ellipticCurvesIds() const; |
| 307 | virtual int curveIdFromShortName(const QString &name) const; |
| 308 | virtual int curveIdFromLongName(const QString &name) const; |
| 309 | virtual QString shortNameForId(int cid) const; |
| 310 | virtual QString longNameForId(int cid) const; |
| 311 | virtual bool isTlsNamedCurve(int cid) const; |
| 312 | |
| 313 | // Note: int and not QSslDiffieHellmanParameter::Error - because this class and |
| 314 | // its enum are QT_CONFIG(ssl)-conditioned. But not QTlsBackend and |
| 315 | // its virtual functions. DH decoding: |
| 316 | virtual int dhParametersFromDer(const QByteArray &derData, QByteArray *data) const; |
| 317 | virtual int dhParametersFromPem(const QByteArray &pemData, QByteArray *data) const; |
| 318 | |
| 319 | static QList<QString> availableBackendNames(); |
| 320 | static QString defaultBackendName(); |
| 321 | static QTlsBackend *findBackend(const QString &backendName); |
| 322 | static QTlsBackend *activeOrAnyBackend(); |
| 323 | |
| 324 | static QList<QSsl::SslProtocol> supportedProtocols(const QString &backendName); |
| 325 | static QList<QSsl::SupportedFeature> supportedFeatures(const QString &backendName); |
| 326 | static QList<QSsl::ImplementedClass> implementedClasses(const QString &backendName); |
| 327 | |
| 328 | // Built-in, this is what Qt provides out of the box (depending on OS): |
| 329 | static constexpr const int nameIndexSchannel = 0; |
| 330 | static constexpr const int nameIndexSecureTransport = 1; |
| 331 | static constexpr const int nameIndexOpenSSL = 2; |
| 332 | static constexpr const int nameIndexCertOnly = 3; |
| 333 | |
| 334 | static const QString builtinBackendNames[]; |
| 335 | |
| 336 | template<class DynamicType, class TLSObject> |
| 337 | static DynamicType *backend(const TLSObject &o) |
| 338 | { |
| 339 | return static_cast<DynamicType *>(o.d->backend.get()); |
| 340 | } |
| 341 | |
| 342 | static void resetBackend(QSslKey &key, QTlsPrivate::TlsKey *keyBackend); |
| 343 | |
| 344 | static void setupClientPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *hint, |
| 345 | int hintLength, unsigned maxIdentityLen, unsigned maxPskLen); |
| 346 | static void setupServerPskAuth(QSslPreSharedKeyAuthenticator *auth, const char *identity, |
| 347 | const QByteArray &identityHint, unsigned maxPskLen); |
| 348 | #if QT_CONFIG(ssl) |
| 349 | static QSslCipher createCiphersuite(const QString &description, int bits, int supportedBits); |
| 350 | static QSslCipher createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol, |
| 351 | const QString &protocolString); |
| 352 | static QSslCipher createCiphersuite(const QString &name, const QString &keyExchangeMethod, |
| 353 | const QString &encryptionMethod, |
| 354 | const QString &authenticationMethod, |
| 355 | int bits, QSsl::SslProtocol protocol, |
| 356 | const QString &protocolString); |
| 357 | |
| 358 | // Those statics are implemented using QSslSocketPrivate (which is not exported, |
| 359 | // unlike QTlsBackend). |
| 360 | static QList<QSslCipher> defaultCiphers(); |
| 361 | static QList<QSslCipher> defaultDtlsCiphers(); |
| 362 | |
| 363 | static void setDefaultCiphers(const QList<QSslCipher> &ciphers); |
| 364 | static void setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers); |
| 365 | static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers); |
| 366 | |
| 367 | static void resetDefaultEllipticCurves(); |
| 368 | |
| 369 | static void setDefaultCaCertificates(const QList<QSslCertificate> &certs); |
| 370 | |
| 371 | // Many thanks to people who designed QSslConfiguration with hidden |
| 372 | // data-members, that sneakily set by some 'friend' classes, having |
| 373 | // some twisted logic. |
| 374 | static bool rootLoadingOnDemandAllowed(const QSslConfiguration &configuration); |
| 375 | static void storePeerCertificate(QSslConfiguration &configuration, const QSslCertificate &peerCert); |
| 376 | static void storePeerCertificateChain(QSslConfiguration &configuration, |
| 377 | const QList<QSslCertificate> &peerCertificateChain); |
| 378 | static void clearPeerCertificates(QSslConfiguration &configuration); |
| 379 | // And those are even worse, this is where we don't have the original configuration, |
| 380 | // and can have only a copy. So instead we go to d->privateConfiguration.someMember: |
| 381 | static void clearPeerCertificates(QSslSocketPrivate *d); |
| 382 | static void setPeerSessionShared(QSslSocketPrivate *d, bool shared); |
| 383 | static void setSessionAsn1(QSslSocketPrivate *d, const QByteArray &asn1); |
| 384 | static void setSessionLifetimeHint(QSslSocketPrivate *d, int hint); |
| 385 | using AlpnNegotiationStatus = QSslConfiguration::NextProtocolNegotiationStatus; |
| 386 | static void setAlpnStatus(QSslSocketPrivate *d, AlpnNegotiationStatus st); |
| 387 | static void setNegotiatedProtocol(QSslSocketPrivate *d, const QByteArray &protocol); |
| 388 | static void storePeerCertificate(QSslSocketPrivate *d, const QSslCertificate &peerCert); |
| 389 | static void storePeerCertificateChain(QSslSocketPrivate *d, const QList<QSslCertificate> &peerChain); |
| 390 | static void addTustedRoot(QSslSocketPrivate *d, const QSslCertificate &rootCert);// TODO: "addTrusted..." |
| 391 | // The next one - is a "very important" feature! Kidding ... |
| 392 | static void setEphemeralKey(QSslSocketPrivate *d, const QSslKey &key); |
| 393 | |
| 394 | virtual void forceAutotestSecurityLevel(); |
| 395 | #endif // QT_CONFIG(ssl) |
| 396 | |
| 397 | Q_DISABLE_COPY_MOVE(QTlsBackend) |
| 398 | }; |
| 399 | |
| 400 | #define QTlsBackend_iid "org.qt-project.Qt.QTlsBackend" |
| 401 | Q_DECLARE_INTERFACE(QTlsBackend, QTlsBackend_iid); |
| 402 | |
| 403 | QT_END_NAMESPACE |
| 404 | |
| 405 | #endif // QTLSBACKEND_P_H |
| 406 | |