ObjFW  Check-in [112eb62f7b]

Overview
Comment:Add OFSecureTransportTLSStream

This implements OFTLSStream using Apple's Secure Transport. While Secure
Transport is declared deprecated by Apple, Apple so far has failed to
provide a suitable replacement. They recommend Network.framework as a
replacement, however it can neither work on arbitrary sockets, nor can
it do STARTTLS.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 112eb62f7bf4b6192f9a2cd274c058e2017f3f487dfc34e9eb4ce7a54c66533f
User & Date: js on 2021-11-13 20:28:25
Other Links: manifest | tags
Context
2021-11-13
21:09
-[OFSecureTransportTLSStream hasDataInReadBuffer] check-in: a3eee50a18 user: js tags: trunk
20:28
Add OFSecureTransportTLSStream check-in: 112eb62f7b user: js tags: trunk
13:04
Completely rework the TLS/SSL API check-in: d30efa8bbf user: js tags: trunk
Changes

Modified configure.ac from [6fe2736e44] to [fc419f2924].

1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
			[Whether we have netinet/tcp.h])
	])
	AC_CHECK_HEADERS([arpa/inet.h netdb.h])
	AC_CHECK_HEADER(netipx/ipx.h, [
		AC_DEFINE(OF_HAVE_NETIPX_IPX_H, 1,
			[Whether we have netipx/ipx.h])
	])
	AC_CHECK_HEADERS(sys/un.h, [
		AC_DEFINE(OF_HAVE_SYS_UN_H, 1, [Whether we have sys/un.h])
	])

	AC_CHECK_MEMBER([struct sockaddr_in6.sin6_addr], [
		AC_EGREP_CPP(egrep_cpp_yes, [
			#ifdef _WIN32
			typedef int BOOL;







|







1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
			[Whether we have netinet/tcp.h])
	])
	AC_CHECK_HEADERS([arpa/inet.h netdb.h])
	AC_CHECK_HEADER(netipx/ipx.h, [
		AC_DEFINE(OF_HAVE_NETIPX_IPX_H, 1,
			[Whether we have netipx/ipx.h])
	])
	AC_CHECK_HEADER(sys/un.h, [
		AC_DEFINE(OF_HAVE_SYS_UN_H, 1, [Whether we have sys/un.h])
	])

	AC_CHECK_MEMBER([struct sockaddr_in6.sin6_addr], [
		AC_EGREP_CPP(egrep_cpp_yes, [
			#ifdef _WIN32
			typedef int BOOL;
1531
1532
1533
1534
1535
1536
1537














1538
1539
1540
1541
1542
1543
1544
			AC_DEFINE(HAVE_SELECT, 1,
				[Whether we have select() or similar])
			AC_SUBST(OF_SELECT_KERNEL_EVENT_OBSERVER_M,
				"OFSelectKernelEventObserver.m")
		])
		;;
	esac















	AS_IF([test x"$enable_threads" != x"no"], [
		AC_SUBST(OF_HTTP_CLIENT_TESTS_M, "OFHTTPClientTests.m")
	])

	AC_SUBST(OFDNS, "ofdns")
	AS_IF([test x"$enable_files" != x"no"], [







>
>
>
>
>
>
>
>
>
>
>
>
>
>







1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
			AC_DEFINE(HAVE_SELECT, 1,
				[Whether we have select() or similar])
			AC_SUBST(OF_SELECT_KERNEL_EVENT_OBSERVER_M,
				"OFSelectKernelEventObserver.m")
		])
		;;
	esac

	AC_CHECK_HEADERS(Security/SecureTransport.h, [
		old_LIBS="$LIBS"
		LIBS="-framework Security -framework Foundation $LIBS"

		AC_CHECK_FUNC(SSLHandshake, [
			AC_DEFINE(HAVE_SECURE_TRANSPORT, 1,
				[Whether we have Secure Transport])
			AC_SUBST(OF_SECURE_TRANSPORT_TLS_STREAM_M,
				"OFSecureTransportTLSStream.m")
		], [
			LIBS="$old_LIBS"
		])
	])

	AS_IF([test x"$enable_threads" != x"no"], [
		AC_SUBST(OF_HTTP_CLIENT_TESTS_M, "OFHTTPClientTests.m")
	])

	AC_SUBST(OFDNS, "ofdns")
	AS_IF([test x"$enable_files" != x"no"], [

Modified extra.mk.in from [07cebcd27b] to [7c71ab8e5d].

44
45
46
47
48
49
50

51
52
53
54
55
56
57
OFHASH = @OFHASH@
OFHTTP = @OFHTTP@
OF_BLOCK_TESTS_M = @OF_BLOCK_TESTS_M@
OF_EPOLL_KERNEL_EVENT_OBSERVER_M = @OF_EPOLL_KERNEL_EVENT_OBSERVER_M@
OF_HTTP_CLIENT_TESTS_M = @OF_HTTP_CLIENT_TESTS_M@
OF_KQUEUE_KERNEL_EVENT_OBSERVER_M = @OF_KQUEUE_KERNEL_EVENT_OBSERVER_M@
OF_POLL_KERNEL_EVENT_OBSERVER_M = @OF_POLL_KERNEL_EVENT_OBSERVER_M@

OF_SELECT_KERNEL_EVENT_OBSERVER_M = @OF_SELECT_KERNEL_EVENT_OBSERVER_M@
OF_SUBPROCESS_M = @OF_SUBPROCESS_M@
REEXPORT_RUNTIME = @REEXPORT_RUNTIME@
REEXPORT_RUNTIME_FRAMEWORK = @REEXPORT_RUNTIME_FRAMEWORK@
RUNTIME = @RUNTIME@
RUNTIME_ARC_TESTS_M = @RUNTIME_ARC_TESTS_M@
RUNTIME_AUTORELEASE_M = @RUNTIME_AUTORELEASE_M@







>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
OFHASH = @OFHASH@
OFHTTP = @OFHTTP@
OF_BLOCK_TESTS_M = @OF_BLOCK_TESTS_M@
OF_EPOLL_KERNEL_EVENT_OBSERVER_M = @OF_EPOLL_KERNEL_EVENT_OBSERVER_M@
OF_HTTP_CLIENT_TESTS_M = @OF_HTTP_CLIENT_TESTS_M@
OF_KQUEUE_KERNEL_EVENT_OBSERVER_M = @OF_KQUEUE_KERNEL_EVENT_OBSERVER_M@
OF_POLL_KERNEL_EVENT_OBSERVER_M = @OF_POLL_KERNEL_EVENT_OBSERVER_M@
OF_SECURE_TRANSPORT_TLS_STREAM_M = @OF_SECURE_TRANSPORT_TLS_STREAM_M@
OF_SELECT_KERNEL_EVENT_OBSERVER_M = @OF_SELECT_KERNEL_EVENT_OBSERVER_M@
OF_SUBPROCESS_M = @OF_SUBPROCESS_M@
REEXPORT_RUNTIME = @REEXPORT_RUNTIME@
REEXPORT_RUNTIME_FRAMEWORK = @REEXPORT_RUNTIME_FRAMEWORK@
RUNTIME = @RUNTIME@
RUNTIME_ARC_TESTS_M = @RUNTIME_ARC_TESTS_M@
RUNTIME_AUTORELEASE_M = @RUNTIME_AUTORELEASE_M@

Modified src/Makefile from [dc8f45eb96] to [d600f2be16].

212
213
214
215
216
217
218

219
220
221
222
223
224
225
		${OF_EPOLL_KERNEL_EVENT_OBSERVER_M}	\
		OFHTTPURLHandler.m			\
		OFHostAddressResolver.m			\
		OFIPSocketAsyncConnector.m		\
		OFKernelEventObserver.m			\
		${OF_KQUEUE_KERNEL_EVENT_OBSERVER_M}	\
		${OF_POLL_KERNEL_EVENT_OBSERVER_M}	\

		${OF_SELECT_KERNEL_EVENT_OBSERVER_M}	\
		OFTCPSocketSOCKS5Connector.m

OBJS_EXTRA = exceptions/exceptions.a	\
	     encodings/encodings.a	\
	     forwarding/forwarding.a
LIB_OBJS_EXTRA = exceptions/exceptions.lib.a	\







>







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
		${OF_EPOLL_KERNEL_EVENT_OBSERVER_M}	\
		OFHTTPURLHandler.m			\
		OFHostAddressResolver.m			\
		OFIPSocketAsyncConnector.m		\
		OFKernelEventObserver.m			\
		${OF_KQUEUE_KERNEL_EVENT_OBSERVER_M}	\
		${OF_POLL_KERNEL_EVENT_OBSERVER_M}	\
		${OF_SECURE_TRANSPORT_TLS_STREAM_M}	\
		${OF_SELECT_KERNEL_EVENT_OBSERVER_M}	\
		OFTCPSocketSOCKS5Connector.m

OBJS_EXTRA = exceptions/exceptions.a	\
	     encodings/encodings.a	\
	     forwarding/forwarding.a
LIB_OBJS_EXTRA = exceptions/exceptions.lib.a	\

Modified src/OFIPSocketAsyncConnector.m from [f532e1ec24] to [da3019744a].

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
			((OFTCPSocketAsyncConnectBlock)_block)(_exception);
		else
			OFEnsure(0);
	} else {
#endif
		if ([_delegate respondsToSelector:
		    @selector(socket:didConnectToHost:port:exception:)])
			[_delegate socket: _socket
			    didConnectToHost: _host
					port: _port
				   exception: _exception];
#ifdef OF_HAVE_BLOCKS
	}
#endif
}







|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
			((OFTCPSocketAsyncConnectBlock)_block)(_exception);
		else
			OFEnsure(0);
	} else {
#endif
		if ([_delegate respondsToSelector:
		    @selector(socket:didConnectToHost:port:exception:)])
			[_delegate    socket: _socket
			    didConnectToHost: _host
					port: _port
				   exception: _exception];
#ifdef OF_HAVE_BLOCKS
	}
#endif
}

Added src/OFSecureTransportTLSStream.h version [af37f6a50a].























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * 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 "OFTLSStream.h"

OF_ASSUME_NONNULL_BEGIN

@interface OFSecureTransportTLSStream: OFTLSStream <OFStreamDelegate>
{
	struct SSLContext *_context;
	OFString *_host;
}
@end

OF_ASSUME_NONNULL_END

Added src/OFSecureTransportTLSStream.m version [56d8fa21c4].

































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * 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.
 */

#include "config.h"

#import "OFSecureTransportTLSStream.h"

#include <Security/SecureTransport.h>

#import "OFAlreadyConnectedException.h"
#import "OFNotOpenException.h"
#import "OFReadFailedException.h"
#import "OFTLSHandshakeFailedException.h"
#import "OFWriteFailedException.h"

static OSStatus
readFunc(SSLConnectionRef connection, void *data, size_t *dataLength)
{
	bool incomplete;
	size_t length = [((OFTLSStream *)connection).wrappedStream
	    readIntoBuffer: data
		    length: *dataLength];

	incomplete = (length < *dataLength);
	*dataLength = length;

	return (incomplete ? errSSLWouldBlock : noErr);
}

static OSStatus
writeFunc(SSLConnectionRef connection, const void *data, size_t *dataLength)
{
	@try {
		[((OFTLSStream *)connection).wrappedStream
		    writeBuffer: data
			 length: *dataLength];
	} @catch (OFWriteFailedException *e) {
		*dataLength = e.bytesWritten;

		if (e.errNo == EWOULDBLOCK)
			return errSSLWouldBlock;

		@throw e;
	}

	return noErr;
}

/*
 * Apple deprecated Secure Transport without providing a replacement that can
 * work with any socket. On top of that, their replacement, Network.framework,
 * doesn't support STARTTLS at all.
 */
#pragma GCC diagnostic ignored "-Wdeprecated"

@implementation OFSecureTransportTLSStream
- (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving,
				     OFReadyForWritingObserving> *)stream
{
	self = [super initWithStream: stream];

	@try {
		_wrappedStream.delegate = self;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	if (_context != NULL)
		[self close];

	[_host release];

	[super dealloc];
}

- (void)close
{
	if (_context == NULL)
		@throw [OFNotOpenException exceptionWithObject: self];

	SSLClose(_context);
	CFRelease(_context);
	_context = NULL;

	[super close];
}

- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)length
{
	OSStatus status;
	size_t ret;

	if (_context == NULL)
		@throw [OFNotOpenException exceptionWithObject: self];

	status = SSLRead(_context, buffer, length, &ret);
	if (status != noErr && status != errSSLWouldBlock)
		/* FIXME: Translate status to errNo */
		@throw [OFReadFailedException exceptionWithObject: self
						  requestedLength: length
							    errNo: 0];

	return ret;
}

- (size_t)lowlevelWriteBuffer: (const void *)buffer length: (size_t)length
{
	OSStatus status;
	size_t ret = 0;

	if (_context == NULL)
		@throw [OFNotOpenException exceptionWithObject: self];

	status = SSLWrite(_context, buffer, length, &ret);
	if (status != noErr && status != errSSLWouldBlock)
		/* FIXME: Translate status to errNo */
		@throw [OFWriteFailedException exceptionWithObject: self
						   requestedLength: length
						      bytesWritten: ret
							     errNo: 0];

	return ret;
}

- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode
{
	static const OFTLSStreamErrorCode initFailedErrorCode =
	    OFTLSStreamErrorCodeInitializationFailed;
	id exception = nil;
	OSStatus status;

	if (_context != NULL)
		@throw [OFAlreadyConnectedException exceptionWithSocket: self];

	if ((_context = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide,
	    kSSLStreamType)) == NULL)
		@throw [OFTLSHandshakeFailedException
		    exceptionWithStream: self
				   host: host
			      errorCode: initFailedErrorCode];

	if (SSLSetIOFuncs(_context, readFunc, writeFunc) != noErr ||
	    SSLSetConnection(_context, self) != noErr)
		@throw [OFTLSHandshakeFailedException
		    exceptionWithStream: self
				   host: host
			      errorCode: initFailedErrorCode];

	if (_verifiesCertificates)
		if (SSLSetPeerDomainName(_context,
		    host.UTF8String, host.UTF8StringLength) != noErr)
			@throw [OFTLSHandshakeFailedException
			    exceptionWithStream: self
					   host: host
				      errorCode: initFailedErrorCode];

	status = SSLHandshake(_context);

	if (status == errSSLWouldBlock) {
		/*
		 * Theoretically it is possible we block because Secure
		 * Transport cannot write without blocking. But unfortunately,
		 * Secure Transport does not tell us whether it's blocked on
		 * reading or writing. Waiting for the stream to be either
		 * readable or writable doesn't work either, as the stream is
		 * almost always at least ready for one of the two.
		 */
		[_wrappedStream asyncReadIntoBuffer: (void *)"" 
					     length: 0
					runLoopMode: runLoopMode];
		[_delegate retain];
		_host = [host copy];
		return;
	}

	if (status != noErr)
		/* FIXME: Map to better errors */
		exception = [OFTLSHandshakeFailedException
		    exceptionWithStream: self
				   host: host
			      errorCode: OFTLSStreamErrorCodeUnknown];

	if ([_delegate respondsToSelector:
	    @selector(stream:didPerformClientHandshakeWithHost:exception:)])
		[_delegate		       stream: self
		    didPerformClientHandshakeWithHost: host
					    exception: exception];
}

-      (bool)stream: (OFStream *)stream
  didReadIntoBuffer: (void *)buffer
	     length: (size_t)length
	  exception: (nullable id)exception
{
	if (exception == nil) {
		OSStatus status = SSLHandshake(_context);

		if (status == errSSLWouldBlock)
			return true;

		if (status != noErr)
			exception = [OFTLSHandshakeFailedException
			    exceptionWithStream: self
					   host: _host
				      errorCode: OFTLSStreamErrorCodeUnknown];
	}

	if ([_delegate respondsToSelector:
	    @selector(stream:didPerformClientHandshakeWithHost:exception:)])
		[_delegate		       stream: self
		    didPerformClientHandshakeWithHost: _host
					    exception: exception];

	[_host release];
	_host = nil;

	[_delegate release];

	return false;
}
@end

Modified src/OFTLSStream.h from [c91283e053] to [b3a209020a].

18
19
20
21
22
23
24










25
26
27
28
29
30
31

OF_ASSUME_NONNULL_BEGIN

/** @file */

@class OFTLSStream;











/**
 * @protocol OFTLSStreamDelegate OFTLSStream.h ObjFW/OFTLSStream.h
 *
 * A delegate for OFTLSStream.
 */
@protocol OFTLSStreamDelegate <OFStreamDelegate>
/**







>
>
>
>
>
>
>
>
>
>







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

OF_ASSUME_NONNULL_BEGIN

/** @file */

@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
} OFTLSStreamErrorCode;

/**
 * @protocol OFTLSStreamDelegate OFTLSStream.h ObjFW/OFTLSStream.h
 *
 * A delegate for OFTLSStream.
 */
@protocol OFTLSStreamDelegate <OFStreamDelegate>
/**
106
107
108
109
110
111
112
113

114
115
116
117
118
119
120
 *	  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
 */







|
>







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
 *	  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
    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
 */
145
146
147
148
149
150
151









152
153
154
155
156
 * @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







>
>
>
>
>
>
>
>
>





156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
 * @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;

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

Modified src/OFTLSStream.m from [53f8754aca] to [6023c3c0c6].

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
 * file.
 */

#include "config.h"

#import "OFTLSStream.h"
#import "OFDate.h"




#import "OFNotImplementedException.h"

Class OFTLSStreamImplementation = Nil;
static const OFRunLoopMode handshakeRunLoopMode =
    @"OFTLSStreamHandshakeRunLoopMode";

@interface OFTLSStreamHandshakeDelegate: OFObject <OFTLSStreamDelegate>
{
@public
	bool _done;
	id _exception;
}
@end
















@implementation OFTLSStreamHandshakeDelegate
- (void)dealloc
{
	[_exception release];

	[super dealloc];







>
>
>



<
<
<
<







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
 * file.
 */

#include "config.h"

#import "OFTLSStream.h"
#import "OFDate.h"
#ifdef HAVE_SECURE_TRANSPORT
# import "OFSecureTransportTLSStream.h"
#endif

#import "OFNotImplementedException.h"





@interface OFTLSStreamHandshakeDelegate: OFObject <OFTLSStreamDelegate>
{
@public
	bool _done;
	id _exception;
}
@end

Class OFTLSStreamImplementation = Nil;
static const OFRunLoopMode handshakeRunLoopMode =
    @"OFTLSStreamHandshakeRunLoopMode";

OFString *
OFTLSStreamErrorCodeDescription(OFTLSStreamErrorCode errorCode)
{
	switch (errorCode) {
	case OFTLSStreamErrorCodeInitializationFailed:
		return @"Initialization of TLS context failed";
	default:
		return @"Unknown error";
	}
}

@implementation OFTLSStreamHandshakeDelegate
- (void)dealloc
{
	[_exception release];

	[super dealloc];
56
57
58
59
60
61
62



63
64

65
66
67
68
69
70
71

+ (instancetype)alloc
{
	if (self == [OFTLSStream class]) {
		if (OFTLSStreamImplementation != Nil)
			return [OFTLSStreamImplementation alloc];




		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];

	}

	return [super alloc];
}

+ (instancetype)streamWithStream: (OFStream <OFReadyForReadingObserving,
				       OFReadyForWritingObserving> *)stream







>
>
>


>







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89

+ (instancetype)alloc
{
	if (self == [OFTLSStream class]) {
		if (OFTLSStreamImplementation != Nil)
			return [OFTLSStreamImplementation alloc];

#ifdef HAVE_SECURE_TRANSPORT
		return [OFSecureTransportTLSStream alloc];
#else
		@throw [OFNotImplementedException exceptionWithSelector: _cmd
								 object: self];
#endif
	}

	return [super alloc];
}

+ (instancetype)streamWithStream: (OFStream <OFReadyForReadingObserving,
				       OFReadyForWritingObserving> *)stream

Modified src/ObjFW.h from [b540b51725] to [4b80c7d121].

227
228
229
230
231
232
233



234
235
236
237
238
239
240
#endif
#import "OFStillLockedException.h"
#ifdef OF_HAVE_THREADS
# import "OFThreadJoinFailedException.h"
# import "OFThreadStartFailedException.h"
# import "OFThreadStillRunningException.h"
#endif



#import "OFTruncatedDataException.h"
#import "OFUnboundNamespaceException.h"
#import "OFUnboundPrefixException.h"
#import "OFUndefinedKeyException.h"
#import "OFUnknownXMLEntityException.h"
#import "OFUnlockFailedException.h"
#import "OFUnsupportedProtocolException.h"







>
>
>







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#endif
#import "OFStillLockedException.h"
#ifdef OF_HAVE_THREADS
# import "OFThreadJoinFailedException.h"
# import "OFThreadStartFailedException.h"
# import "OFThreadStillRunningException.h"
#endif
#ifdef OF_HAVE_SOCKETS
# import "OFTLSHandshakeFailedException.h"
#endif
#import "OFTruncatedDataException.h"
#import "OFUnboundNamespaceException.h"
#import "OFUnboundPrefixException.h"
#import "OFUndefinedKeyException.h"
#import "OFUnknownXMLEntityException.h"
#import "OFUnlockFailedException.h"
#import "OFUnsupportedProtocolException.h"

Modified src/exceptions/Makefile from [351e362627] to [d98a82648f].

57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
	       OFAlreadyConnectedException.m		\
	       OFBindFailedException.m			\
	       OFConnectionFailedException.m		\
	       OFDNSQueryFailedException.m		\
	       OFHTTPRequestFailedException.m		\
	       OFListenFailedException.m		\
	       OFObserveFailedException.m		\
	       OFResolveHostFailedException.m

SRCS_THREADS = OFConditionBroadcastFailedException.m	\
	       OFConditionSignalFailedException.m	\
	       OFConditionStillWaitingException.m	\
	       OFConditionWaitFailedException.m		\
	       OFThreadJoinFailedException.m		\
	       OFThreadStartFailedException.m		\
	       OFThreadStillRunningException.m







|
>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
	       OFAlreadyConnectedException.m		\
	       OFBindFailedException.m			\
	       OFConnectionFailedException.m		\
	       OFDNSQueryFailedException.m		\
	       OFHTTPRequestFailedException.m		\
	       OFListenFailedException.m		\
	       OFObserveFailedException.m		\
	       OFResolveHostFailedException.m		\
	       OFTLSHandshakeFailedException.m
SRCS_THREADS = OFConditionBroadcastFailedException.m	\
	       OFConditionSignalFailedException.m	\
	       OFConditionStillWaitingException.m	\
	       OFConditionWaitFailedException.m		\
	       OFThreadJoinFailedException.m		\
	       OFThreadStartFailedException.m		\
	       OFThreadStillRunningException.m

Modified src/exceptions/OFListenFailedException.h from [08a4f6833f] to [d3d380a413].

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
+ (instancetype)exceptionWithSocket: (id)socket
			    backlog: (int)backlog
			      errNo: (int)errNo;

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated listen failed exception
 *
 * @param socket The socket which failed to listen
 * @param backlog The requested size of the back log
 * @param errNo The errno of the error that occurred
 * @return An initialized listen failed exception
 */
- (instancetype)initWithSocket: (id)socket
		       backlog: (int)backlog
			 errNo: (int)errNo OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END







|












61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
+ (instancetype)exceptionWithSocket: (id)socket
			    backlog: (int)backlog
			      errNo: (int)errNo;

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated listen failed exception.
 *
 * @param socket The socket which failed to listen
 * @param backlog The requested size of the back log
 * @param errNo The errno of the error that occurred
 * @return An initialized listen failed exception
 */
- (instancetype)initWithSocket: (id)socket
		       backlog: (int)backlog
			 errNo: (int)errNo OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Modified src/exceptions/OFReadFailedException.m from [acb3de62d5] to [2c0f1f9618].

17
18
19
20
21
22
23

24
25
26




27
28

#import "OFReadFailedException.h"
#import "OFString.h"

@implementation OFReadFailedException
- (OFString *)description
{

	return [OFString stringWithFormat:
	    @"Failed to read %zu bytes from an object of type %@: %@",
	    _requestedLength, [_object class], OFStrError(_errNo)];




}
@end







>
|
|
|
>
>
>
>


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

#import "OFReadFailedException.h"
#import "OFString.h"

@implementation OFReadFailedException
- (OFString *)description
{
	if (_errNo != 0)
		return [OFString stringWithFormat:
		    @"Failed to read %zu bytes from an object of type %@: %@",
		    _requestedLength, [_object class], OFStrError(_errNo)];
	else
		return [OFString stringWithFormat:
		    @"Failed to read %zu bytes from an object of type %@",
		    _requestedLength, [_object class]];
}
@end

Modified src/exceptions/OFReadOrWriteFailedException.m from [dadaef8eb0] to [451a9c002f].

59
60
61
62
63
64
65

66
67
68
69





70
71
	[_object release];

	[super dealloc];
}

- (OFString *)description
{

	return [OFString stringWithFormat:
	    @"Failed to read or write %zu bytes from / to an object of type "
	    @"%@: %@",
	    _requestedLength, [_object class], OFStrError(_errNo)];





}
@end







>
|
|
|
|
>
>
>
>
>


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
	[_object release];

	[super dealloc];
}

- (OFString *)description
{
	if (_errNo != 0)
		return [OFString stringWithFormat:
		    @"Failed to read or write %zu bytes from / to an object of "
		    @"type %@: %@",
		    _requestedLength, [_object class], OFStrError(_errNo)];
	else
		return [OFString stringWithFormat:
		    @"Failed to read or write %zu bytes from / to an object of "
		    @"type %@",
		    _requestedLength, [_object class]];
}
@end

Added src/exceptions/OFTLSHandshakeFailedException.h version [b1f02c3e16].









































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
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
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * 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 "OFException.h"

#ifndef OF_HAVE_SOCKETS
# error No sockets available!
#endif

#import "OFTLSStream.h"

OF_ASSUME_NONNULL_BEGIN

/**
 * @class OFTLSHandshakeFailedException \
 *	  OFTLSHandshakeFailedException.h ObjFW/OFTLSHandshakeFailedException.h
 *
 * @brief An exception indicating that a TLS handshake.
 */
@interface OFTLSHandshakeFailedException: OFException
{
	OFTLSStream *_stream;
	OFString *_Nullable _host;
	OFTLSStreamErrorCode _errorCode;
}

/**
 * @brief The TLS stream which failed the handshake.
 */
@property (readonly, nonatomic) OFTLSStream *stream;

/**
 * @brief The host for the handshake.
 */
@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *host;

/**
 * @brief The error code from the TLS stream.
 */
@property (readonly, nonatomic) OFTLSStreamErrorCode errorCode;

+ (instancetype)exception OF_UNAVAILABLE;

/**
 * @brief Creates a new, autoreleased TLS handshake failed exception.
 *
 * @param stream The TLS stream which failed the handshake
 * @param host The host for the handshake
 * @param errorCode The error code from the TLS stream
 * @return A new, autoreleased TLS handshake failed exception
 */
+ (instancetype)exceptionWithStream: (OFTLSStream *)stream
			       host: (nullable OFString *)host
			  errorCode: (OFTLSStreamErrorCode)errorCode;

- (instancetype)init OF_UNAVAILABLE;

/**
 * @brief Initializes an already allocated TLS handshake failed exception.
 *
 * @param stream The TLS stream which failed the handshake
 * @param host The host for the handshake
 * @param errorCode The error code from the TLS stream
 * @return An initialized TLS handshake failed exception
 */
- (instancetype)initWithStream: (OFTLSStream *)stream
			  host: (nullable OFString *)host
		     errorCode: (OFTLSStreamErrorCode)errorCode
    OF_DESIGNATED_INITIALIZER;
@end

OF_ASSUME_NONNULL_END

Added src/exceptions/OFTLSHandshakeFailedException.m version [2e553f0270].



































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
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
/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 *
 * All rights reserved.
 *
 * This file is part of ObjFW. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
 * the packaging of this file.
 *
 * 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.
 */

#include "config.h"

#import "OFTLSHandshakeFailedException.h"
#import "OFString.h"

@implementation OFTLSHandshakeFailedException
@synthesize stream = _stream, host = _host, errorCode = _errorCode;

+ (instancetype)exception
{
	OF_UNRECOGNIZED_SELECTOR
}

+ (instancetype)exceptionWithStream: (OFTLSStream *)stream
			       host: (OFString *)host
			  errorCode: (OFTLSStreamErrorCode)errorCode
{
	return [[[self alloc] initWithStream: stream
					host: host
				   errorCode: errorCode] autorelease];
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (instancetype)initWithStream: (OFTLSStream *)stream
			  host: (OFString *)host
		     errorCode: (OFTLSStreamErrorCode)errorCode
{
	self = [super init];

	@try {
		_stream = [stream retain];
		_host = [host copy];
		_errorCode = errorCode;
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_stream release];
	[_host release];

	[super dealloc];
}

- (OFString *)description
{
	if (_host != nil)
		return [OFString stringWithFormat:
		    @"TLS handshake in class %@ with host %@ failed: %@",
		    _stream.class, _host,
		    OFTLSStreamErrorCodeDescription(_errorCode)];
	else
		return [OFString stringWithFormat:
		    @"TLS handshake in class %@ failed: %@",
		    _stream.class, OFTLSStreamErrorCodeDescription(_errorCode)];
}
@end

Modified src/exceptions/OFWriteFailedException.m from [6f0f1c63f5] to [47ca157f6b].

60
61
62
63
64
65
66

67
68
69
70
71





72
73
	_bytesWritten = bytesWritten;

	return self;
}

- (OFString *)description
{

	return [OFString stringWithFormat:
	    @"Failed to write %zu bytes (after %zu bytes written) to an "
	    @"object of type %@: %@",
	    _requestedLength, _bytesWritten, [_object class],
	    OFStrError(_errNo)];





}
@end







>
|
|
|
|
|
>
>
>
>
>


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
	_bytesWritten = bytesWritten;

	return self;
}

- (OFString *)description
{
	if (_errNo != 0)
		return [OFString stringWithFormat:
		    @"Failed to write %zu bytes (after %zu bytes written) to "
		    @"an object of type %@: %@",
		    _requestedLength, _bytesWritten, [_object class],
		    OFStrError(_errNo)];
	else
		return [OFString stringWithFormat:
		    @"Failed to write %zu bytes (after %zu bytes written) to "
		    @"an object of type %@",
		    _requestedLength, _bytesWritten, [_object class]];
}
@end