ObjFW  Diff

Differences From Artifact [5dd4f959ef]:

To Artifact [c91283e053]:

  • File src/OFTLSStream.h — part of check-in [d30efa8bbf] at 2021-11-13 13:04:13 on branch trunk — Completely rework the TLS/SSL API

    The previous API could never work cleanly and would always require
    hacks, as it needed intercepting all interactions of OFTCPSocket with
    the raw socket and did not work at all if the OFTCPSocket had anything
    in its read buffer before starting the TLS handshake. This also could
    not be fixed easily, as it would have required the object to contain two
    read buffers, one for the unencrypted connection and one for the
    encrypted connection. There was also no clean way to perform the
    handshake in a non-blocking way.

    The new API is a lot cleaner and requires none of the hacks, but using
    it requires slightly more work. But this is more than made up for by
    making a fully asynchronous handshake possible. It uses the concept of a
    stream wrapping another stream, meaning the entire connecting part is
    being handled by OFTCPSocket and then the connected socket is passed off
    to OFTLSStream to wrap it. This also makes for a lot cleaner separation
    of concerns. (user: js, size: 4764) [annotate] [blame] [check-ins using]


9
10
11
12
13
14
15
16

17
18
19




20
21
22
23
24
25












26
27
28
29
30
31
32
33
34
35
36
37

38
39
40
41
42
43
44
45
46

47


48
49
50
51
52






53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


68
69
70
71
72
73
74
75


76
77

78
79

80
81
82
83
84
85

86
87

88
89
90
91


92
93

94
95
96
97




98
99


100
101
102
103


104
105

106
107
108
109
110
111
112




113
114
115
116
117
118
119
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFTCPSocket.h"


OF_ASSUME_NONNULL_BEGIN





/**
 * @protocol OFTLSSocketDelegate OFTLSSocket.h ObjFW/OFTLSSocket.h
 *
 * A delegate for OFTLSSocket.
 */
@protocol OFTLSSocketDelegate <OFTCPSocketDelegate>












@end

/**
 * @class OFTLSSocket OFTLSSocket.h ObjFW/OFTLSSocket.h
 *
 * @brief A class that provides Transport Layer Security on top of a TCP socket.
 *
 * This class is a class cluster and returns a suitable OFTLSSocket subclass,
 * if available.
 *
 * Subclasses need to override @ref accept, @ref lowlevelReadIntoBuffer:length:,
 * @ref lowlevelWriteBuffer:length: and @ref startTLSForHost:port:. The method

 * @ref hasDataInReadBuffer should be overridden to return `true` if the TLS
 * socket has cached unprocessed data internally, while returning
 * `[super hasDataInReadBuffer]` if it does not have any unprocessed data. In
 * order to get access to the lowlevel TCP methods (you cannot call `super`, as
 * the class is abstract), the private methods @ref TCPAccept,
 * @ref lowlevelTCPReadIntoBuffer:length: and
 * @ref lowlevelTCPWriteBuffer:length: are provided.
 */
@interface OFTLSSocket: OFTCPSocket

{


	bool _verifiesCertificates;
	OF_RESERVE_IVARS(OFTLSSocket, 4)
}

/**






 * @brief The delegate for asynchronous operations on the socket.
 *
 * @note The delegate is retained for as long as asynchronous operations are
 *	 still ongoing.
 */
@property OF_NULLABLE_PROPERTY (assign, nonatomic)
    id <OFTLSSocketDelegate> delegate;

/**
 * @brief Whether certificates are verified.
 *
 * The default is enabled.
 */
@property (nonatomic) bool verifiesCertificates;



/**
 * @brief Initializes the TLS socket with the specified TCP socket as its
 *	  underlying socket.
 *
 * The passed socket will become invalid, as the internal socket handle gets
 * moved from the specified socket to the OFTLSSocket.
 *
 * @param socket The TCP socket to use as underlying socket


 */
- (instancetype)initWithSocket: (OFTCPSocket *)socket;


/**

 * @brief Start TLS on the underlying socket with the assumption that it is
 *	  connected to the specified host and port.
 *
 * @param host The host the socket is connected to, which is also used for
 *	       verification
 * @param port The port the socket is connected to

 */
- (void)startTLSForHost: (OFString *)host port: (uint16_t)port;


/**
 * @brief This method should never be called directly. Only subclasses of
 *	  @ref OFTLSSocket are allowed to call it.


 */
- (instancetype)TCPAccept;


/**
 * @brief This method should never be called directly. Only subclasses of
 *	  @ref OFTLSSocket are allowed to call it.




 */
- (size_t)lowlevelTCPReadIntoBuffer: (void *)buffer length: (size_t)length;



/**
 * @brief This method should never be called directly. Only subclasses of
 *	  @ref OFTLSSocket are allowed to call it.


 */
- (size_t)lowlevelTCPWriteBuffer: (const void *)buffer length: (size_t)length;

@end

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief The concrete subclass of OFTLSSocket that should be used.




 */
extern Class _Nullable OFTLSSocketImplementation;
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END







|
>



>
>
>
>

|

|

|
>
>
>
>
>
>
>
>
>
>
>
>



|

|

|


|
|
>

|
|
|
<
|
<

|
>

>
>

|



>
>
>
>
>
>
|





|


|
<
<



>
>

|
|

<
<
<
|
>
>

|
>


>
|
<

|
<
|
>

|
>


|
|
>
>

<
>


|
<
>
>
>
>

<
>
>


|
<
>
>

<
>






|
>
>
>
>

|





9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

60

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87


88
89
90
91
92
93
94
95
96



97
98
99
100
101
102
103
104
105
106

107
108

109
110
111
112
113
114
115
116
117
118
119
120

121
122
123
124

125
126
127
128
129

130
131
132
133
134

135
136
137

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
 *
 * Alternatively, it may be distributed under the terms of the GNU General
 * Public License, either version 2 or 3, which can be found in the file
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#import "OFStream.h"
#import "OFRunLoop.h"

OF_ASSUME_NONNULL_BEGIN

/** @file */

@class OFTLSStream;

/**
 * @protocol OFTLSStreamDelegate OFTLSStream.h ObjFW/OFTLSStream.h
 *
 * A delegate for OFTLSStream.
 */
@protocol OFTLSStreamDelegate <OFStreamDelegate>
/**
 * @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;
@end

/**
 * @class OFTLSStream OFTLSStream.h ObjFW/OFTLSStream.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: and
 * @ref asyncPerformClientHandshakeWithHost:runLoopMode:. The method
 * @ref hasDataInReadBuffer should be overridden to return `true` if the TLS
 * stream has cached unprocessed data internally, while returning
 * `self.wrappedStream.hasDataInReadBuffer` if it does not have any unprocessed
 * data. In order to get access to the wrapped stream, @ref wrappedStream can

 * be used.

 */
@interface OFTLSStream: OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
	OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving>
	    *_wrappedStream;
	bool _verifiesCertificates;
	OF_RESERVE_IVARS(OFTLSStream, 4)
}

/**
 * @brief The wrapped stream.
 */
@property (readonly, nonatomic) OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving> *wrappedStream;

/**
 * @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;

- (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.

 *
 * @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;

/**
 * @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
 */

- (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
 */

- (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
 */

- (void)performClientHandshakeWithHost: (OFString *)host;
@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 use one that ObjFW does
 * not know about.
 */
extern Class OFTLSStreamImplementation;
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END