ObjFW  Diff

Differences From Artifact [9df190e90e]:

To Artifact [0ae2a154e2]:


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

-
+













-
+
+



-
+
-
-

-
-
-
+
+
-
-
-
-

-
+
-
-
+
-
-
-
-
+
-
+
+
+
+
+
-
-
-
-
-
-
-
-


-
+

-
-
+

-
+

-
+
+
+
+
+
+
+

+
+
+
-
+
-


-
-
-
-
+
+
-
-
+
-
-
-
-
+
+
+
-

+
+
+
+
+
+
-
-
+
+

-
-
-
+
+
+
-
-
-
+
+
-
-
-
-
+
+
+
+

-
-
-
-
+
+
+
+
+
+
+
+
+
+

-
+
+


-
-
+
+
-
-
-
-
+
+
+
-
-
-


-
-
+
+

-
-
+
+
-
-
+

-
-
-
+
+
-
-
-
-
-
-
+
+
+
+

-
-
+
+
+

-
+
+
+


-
-
+
+

-
+
-
-

-
-
+


-
-
+
+

-
-
+
+
-
-
-

-
+
+


-
-
+

-
-
-
-
+
-
-
-

-
-
-
+
+
+
+
+
+

-
+
-

+
+
-
-
-
+
+
+
+
-
+
+

+
-
+
-

-
-
+
+
+
+
+


/*
 * Copyright (c) 2008-2021 Jonathan Schleifer <js@nil.im>
 * Copyright (c) 2008-2022 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 "OFObject.h"
#import "OFStream.h"
#import "OFRunLoop.h"

OF_ASSUME_NONNULL_BEGIN

@class OFString;
/** @file */
@class OFDictionary OF_GENERIC(KeyType, ObjectType);
@protocol OFTLSSocket;

/**
 * @protocol OFTLSSocketDelegate OFTLSSocket.h ObjFW/OFTLSSocket.h
 *
@class OFTLSStream;

 * @brief A delegate for classes implementing the OFTLSSocket protocol.
 */
@protocol OFTLSSocketDelegate <OFTCPSocketDelegate>
@optional
/**
 * @brief This callback is called when the TLS socket wants to know if it
 * @brief An enum representing an error of an OFTLSStream.
 *	  should accept the received certificate.
 *
 */
 * @note This is only used to verify certain fields of a certificate to allow
 *	 for protocol specific verification. The certificate chain is verified
 *	 using the specified CAs, or the system's CAs if no CAs have been
 *	 specified.
typedef enum {
 *
	/** @brief An unknown error. */
	OFTLSStreamErrorCodeUnknown,
	/** @brief Initialization of the TLS context failed. */
	OFTLSStreamErrorCodeInitializationFailed
} OFTLSStreamErrorCode;
 * @param socket The socket which wants to know if it should accept the received
 *		 certificate
 * @param certificate A dictionary with the fields of the received certificate
 * @return Whether the TLS socket should accept the received certificate chain
 */
-	     (bool)socket: (id <OFTLSSocket>)socket
  shouldAcceptCertificate: (OFDictionary *)certificate;
@end

/**
 * @protocol OFTLSSocket OFTLSSocket.h ObjFW/OFTLSSocket.h
 * @protocol OFTLSStreamDelegate OFTLSStream.h ObjFW/OFTLSStream.h
 *
 * @brief A protocol that should be implemented by 3rd-party libraries
 *	  implementing TLS.
 * A delegate for OFTLSStream.
 */
@protocol OFTLSSocket
@protocol OFTLSStreamDelegate <OFStreamDelegate>
/**
 * @brief The delegate for the TLS socket.
 * @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;
@property OF_NULLABLE_PROPERTY (assign, nonatomic)
@end
    id <OFTLSSocketDelegate> delegate;

/**
 * @brief The path to the X.509 certificate file to use.
 */
@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *certificateFile;

 * @class OFTLSStream OFTLSStream.h ObjFW/OFTLSStream.h
 *
/**
 * @brief The path to the PKCS#8 private key file to use.
 * @brief A class that provides Transport Layer Security on top of a stream.
 */
@property OF_NULLABLE_PROPERTY (copy, nonatomic) OFString *privateKeyFile;

/**
 *
 * This class is a class cluster and returns a suitable OFTLSStream subclass,
 * if available.
 * @brief The passphrase to decrypt the PKCS#8 private key file.
 *
 * 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.underlyingStream.hasDataInReadBuffer` if it does not have any
 * @warning You have to ensure that this is in secure memory protected from
 *	    swapping! This is also the reason why this is not an OFString.
 * unprocessed data. In order to get access to the underlying stream,
 * @ref underlyingStream can be used.
 */
@property OF_NULLABLE_PROPERTY (assign, nonatomic)
    const char *privateKeyPassphrase;

@interface OFTLSStream: OFStream <OFReadyForReadingObserving,
    OFReadyForWritingObserving>
{
/**
 * @brief Whether certificates are verified.
 *
	OFStream <OFReadyForReadingObserving, OFReadyForWritingObserving>
	    *_underlyingStream;
 * The default is enabled.
 */
@property (nonatomic) bool verifiesCertificates;

	bool _verifiesCertificates;
	OF_RESERVE_IVARS(OFTLSStream, 4)
}

/**
 * @brief Initializes the TLS socket with the specified TCP socket as its
 *	  underlying socket.
 *
 * @param socket The TCP socket to use as underlying socket
 * @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.
 */
- (instancetype)initWithSocket: (OFTCPSocket *)socket;
@property OF_NULLABLE_PROPERTY (assign, nonatomic)
    id <OFTLSStreamDelegate> delegate;

/**
 * @brief Initiates the TLS handshake.
 *
 * @brief Whether certificates are verified. Default is true.
 */
 * @note This is only useful if you used @ref initWithSocket: to start TLS on
 *	 a TCP socket which is already connected!
 *
 * @param host The host to expect for certificate verification.
@property (nonatomic) bool verifiesCertificates;

- (instancetype)init OF_UNAVAILABLE;
 *	       May be `nil` if certificate verification is disabled.
 */
- (void)startTLSWithExpectedHost: (nullable OFString *)host;

/**
 * @brief Sets the path to the X.509 certificate file to use for the specified
 *	  SNI host.
 * @brief Creates a new TLS stream with the specified stream as its underlying
 *	  stream.
 *
 * @param SNIHost The SNI host for which the path of the X.509 certificate file
 *		  should be set
 * @param stream The stream to use as underlying stream. Must not be closed
 *		 before the TLS stream is closed.
 *
 * @param certificateFile The path to the X.509 certificate file
 * @return A new, autoreleased TLS stream
 */
- (void)setCertificateFile: (OFString *)certificateFile
		forSNIHost: (OFString *)SNIHost;

+ (instancetype)streamWithStream: (OFStream <OFReadyForReadingObserving,
				       OFReadyForWritingObserving> *)stream;
/**
 * @brief Returns the path of the X.509 certificate file used by the TLS socket
 *	  for the specified SNI host.
 *
 * @param SNIHost The SNI host for which the path of the X.509 certificate file
 *		  should be returned

/**
 * @brief Initializes the TLS stream with the specified stream as its
 *	  underlying stream.
 *
 * @return The path of the X.509 certificate file used by the TLS socket for
 *	   the specified SNI host
 * @param stream The stream to use as underlying stream. Must not be closed
 *		 before the TLS stream is closed.
 * @return An initialized TLS stream
 */
- (nullable OFString *)certificateFileForSNIHost: (OFString *)SNIHost;
- (instancetype)initWithStream: (OFStream <OFReadyForReadingObserving,
				     OFReadyForWritingObserving> *)stream
    OF_DESIGNATED_INITIALIZER;

/**
 * @brief Sets the path to the PKCS#8 private key file to use for the specified
 *	  SNI host.
 * @brief Asynchronously performs the TLS client handshake for the specified
 *	  host and calls the delegate afterwards.
 *
 * @param privateKeyFile The path to the PKCS#8 private key file
 * @param host The host to perform the handshake with
 * @param SNIHost The SNI host for which the path to the PKCS#8 private key
 *		  file should be set
 */
- (void)setPrivateKeyFile: (OFString *)privateKeyFile
	       forSNIHost: (OFString *)SNIHost;
- (void)asyncPerformClientHandshakeWithHost: (OFString *)host;

/**
 * @brief Returns the path of the PKCS#8 private key file used by the TLS
 *	  socket for the specified SNI host.
 * @brief Asynchronously performs the TLS client handshake for the specified
 *	  host and calls the delegate afterwards.
 *
 * @param SNIHost The SNI host for which the path of the PKCS#8 private key
 *		  file should be returned
 * @param host The host to perform the handshake with
 * @param runLoopMode The run loop mode in which to perform the async handshake
 *
 * @return The path of the PKCS#8 private key file used by the TLS socket for
 *	   the specified SNI host
 */
- (nullable OFString *)privateKeyFileForSNIHost: (OFString *)SNIHost;
- (void)asyncPerformClientHandshakeWithHost: (OFString *)host
				runLoopMode: (OFRunLoopMode)runLoopMode;

/**
 * @brief Sets the passphrase to decrypt the PKCS#8 private key file for the
 *	  specified SNI host.
 * @brief Performs the TLS client handshake for the specified host.
 *
 * @warning You have to ensure that this is in secure memory protected from
 *	    swapping! This is also the reason why this is not an OFString.
 *
 * @param privateKeyPassphrase The passphrase to decrypt the PKCS#8 private
 * @param host The host to perform the handshake with
 *			       key file for the specified SNI host
 * @param SNIHost The SNI host for which the passphrase to decrypt the PKCS#8
 *		  private key file should be set
 */
- (void)setPrivateKeyPassphrase: (const char *)privateKeyPassphrase
		     forSNIHost: (OFString *)SNIHost;

- (void)performClientHandshakeWithHost: (OFString *)host;
@end

#ifdef __cplusplus
extern "C" {
#endif
/**
 * @brief Returns the passphrase to decrypt the PKCS#8 private key file for the
 * @brief The implementation for OFTLSStream to use.
 *	  specified SNI host.
 *
 * 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
 * @warning You should not copy this to insecure memory which is swappable!
 *
 * @param SNIHost The SNI host for which the passphrase to decrypt the PKCS#8
 * not know about.
 */
extern Class OFTLSStreamImplementation;

 *		  private key file should be returned
/**
 * @brief Returns a string description for the TLS stream error code.
 *
 * @param errorCode The error code to return the description for
 * @return The passphrase to decrypt the PKCS#8 private key file for the
 * @return A string description for the TLS stream error code
 *	   specified SNI host
 */
- (nullable const char *)privateKeyPassphraseForSNIHost: (OFString *)SNIHost;
@end
extern OFString *OFTLSStreamErrorCodeDescription(
    OFTLSStreamErrorCode errorCode);
#ifdef __cplusplus
}
#endif

OF_ASSUME_NONNULL_END