/* * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3.0 only, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3.0 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3.0 along with this program. If not, see * <https://www.gnu.org/licenses/>. */ #import "OFStream.h" #import "OFRunLoop.h" #import "OFX509Certificate.h" #import "OFX509CertificatePrivateKey.h" OF_ASSUME_NONNULL_BEGIN /** @file */ @class OFArray OF_GENERIC(ObjectType); @class OFTLSStream; /** * @brief An enum representing an error of an OFTLSStream. */ typedef enum { /** @brief An unknown error. */ OFTLSStreamErrorCodeUnknown, /** @brief Initialization of the TLS context failed. */ OFTLSStreamErrorCodeInitializationFailed, /** @brief Failed to verify certificate. */ OFTLSStreamErrorCodeCertificateVerificationFailed, /** @brief The certificate has an untrusted or unknown issuer. */ OFTLSStreamErrorCodeCertificateIssuerUntrusted, /** @brief The certificate is for a different name. */ OFTLSStreamErrorCodeCertificateNameMismatch, /** @brief The certificate has expired or is not yet valid. */ OFTLSStreamErrorCodeCertificatedExpired, /** @brief The certificate has been revoked. */ OFTLSStreamErrorCodeCertificateRevoked } OFTLSStreamErrorCode; /** * @protocol OFTLSStreamDelegate OFTLSStream.h ObjFW/ObjFW.h * * A delegate for OFTLSStream. */ @protocol OFTLSStreamDelegate <OFStreamDelegate> @optional /** * @brief A method which is called when a TLS stream performed the client * handshake. * * @param stream The TLS stream which performed the handshake * @param host The host for which the handshake was performed * @param exception An exception that occurred during the handshake, or nil on * success */ - (void)stream: (OFTLSStream *)stream didPerformClientHandshakeWithHost: (OFString *)host exception: (nullable id)exception; /** * @brief A method which is called when a TLS stream performed the server * handshake. * * @param stream The TLS stream which performed the handshake * @param exception An exception that occurred during the handshake, or nil on * success */ - (void)streamDidPerformServerHandshake: (OFTLSStream *)stream exception: (nullable id)exception; @end /** * @class OFTLSStream OFTLSStream.h ObjFW/ObjFW.h * * @brief A class that provides Transport Layer Security on top of a stream. * * This class is a class cluster and returns a suitable OFTLSStream subclass, * if available. * * Subclasses need to override @ref lowlevelReadIntoBuffer:length:, * @ref lowlevelWriteBuffer:length:, * @ref lowlevelHasDataInReadBuffer and * @ref asyncPerformClientHandshakeWithHost:runLoopMode:. * * In order to get access to the underlying stream, @ref underlyingStream can * be used. */ @interface OFTLSStream: OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving> { OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving> *_underlyingStream; bool _verifiesCertificates; OFArray OF_GENERIC(OFX509Certificate *) *_Nullable _certificateChain; OFX509CertificatePrivateKey *_Nullable _privateKey; OF_RESERVE_IVARS(OFTLSStream, 2) } /** * @brief The underlying stream. */ @property (readonly, nonatomic) OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving> *underlyingStream; /** * @brief The delegate for asynchronous operations on the stream. * * @note The delegate is retained for as long as asynchronous operations are * still ongoing. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id <OFTLSStreamDelegate> delegate; /** * @brief Whether certificates are verified. Default is true. */ @property (nonatomic) bool verifiesCertificates; /** * @brief The certificate chain to use. */ @property OF_NULLABLE_PROPERTY (copy, nonatomic) OFArray OF_GENERIC(OFX509Certificate *) *certificateChain; /** * @brief The private key to use. */ @property OF_NULLABLE_PROPERTY (retain, nonatomic) OFX509CertificatePrivateKey *privateKey; - (instancetype)init OF_UNAVAILABLE; /** * @brief Creates a new TLS stream with the specified stream as its underlying * stream. * * @param stream The stream to use as underlying stream. Must not be closed * before the TLS stream is closed. * @return A new, autoreleased TLS stream */ + (instancetype)streamWithStream: (OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving> *)stream; /** * @brief Initializes the TLS stream with the specified stream as its * underlying stream. * * @note The delegate of the specified stream will be changed to the TLS * stream. You must not change this before the TLS session is completed. * * @param stream The stream to use as underlying stream. Must not be closed * before the TLS stream is closed. * @return An initialized TLS stream */ - (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving> *)stream OF_DESIGNATED_INITIALIZER; /** * @brief Asynchronously performs the TLS client handshake for the specified * host and calls the delegate afterwards. * * @param host The host to perform the handshake with * @throw OFTLSHandshakeFailedException The TLS handshake failed * @throw OFAlreadyOpenException The handshake was already performed */ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host; /** * @brief Asynchronously performs the TLS client handshake for the specified * host and calls the delegate afterwards. * * @param host The host to perform the handshake with * @param runLoopMode The run loop mode in which to perform the async handshake * @throw OFTLSHandshakeFailedException The TLS handshake failed * @throw OFAlreadyOpenException The handshake was already performed */ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host runLoopMode: (OFRunLoopMode)runLoopMode; /** * @brief Performs the TLS client handshake for the specified host. * * @param host The host to perform the handshake with * @throw OFTLSHandshakeFailedException The TLS handshake failed * @throw OFAlreadyOpenException The handshake was already performed */ - (void)performClientHandshakeWithHost: (OFString *)host; /** * @brief Asynchronously performs the TLS server handshake and calls the * delegate afterwards. * * @throw OFTLSHandshakeFailedException The TLS handshake failed * @throw OFAlreadyOpenException The handshake was already performed */ - (void)asyncPerformServerHandshake; /** * @brief Asynchronously performs the TLS server handshake and calls the * delegate afterwards. * * @param runLoopMode The run loop mode in which to perform the async handshake * * @throw OFTLSHandshakeFailedException The TLS handshake failed * @throw OFAlreadyOpenException The handshake was already performed */ - (void)asyncPerformServerHandshakeWithRunLoopMode: (OFRunLoopMode)runLoopMode; /** * @brief Performs the TLS server handshake. * * @throw OFTLSHandshakeFailedException The TLS handshake failed * @throw OFAlreadyOpenException The handshake was already performed */ - (void)performServerHandshake; @end #ifdef __cplusplus extern "C" { #endif /** * @brief The implementation for OFTLSStream to use. * * This can be set to a class that is always used for OFTLSStream. This is * useful to either force a specific implementation or to use one that ObjFW * does not know about. */ extern Class OFTLSStreamImplementation; /** * @brief Returns a string description for the TLS stream error code. * * @param errorCode The error code to return the description for * @return A string description for the TLS stream error code */ extern OFString *OFTLSStreamErrorCodeDescription( OFTLSStreamErrorCode errorCode); #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END