xref: /haiku/src/kits/network/libnetapi/SecureSocket.cpp (revision 04a0e9c7b68cbe3a43d38e2bca8e860fd80936fb)
1 /*
2  * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3  * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include <SecureSocket.h>
9 
10 #ifdef OPENSSL_ENABLED
11 #	include <openssl/ssl.h>
12 #endif
13 
14 
15 //#define TRACE_SOCKET
16 #ifdef TRACE_SOCKET
17 #	define TRACE(x...) printf(x)
18 #else
19 #	define TRACE(x...) ;
20 #endif
21 
22 
23 #ifdef OPENSSL_ENABLED
24 
25 
26 class BSecureSocket::Private {
27 public:
28 			SSL_CTX*			fCTX;
29 			SSL*				fSSL;
30 			BIO*				fBIO;
31 };
32 
33 
34 BSecureSocket::BSecureSocket()
35 	:
36 	fPrivate(NULL)
37 {
38 }
39 
40 
41 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
42 	:
43 	fPrivate(NULL)
44 {
45 	Connect(peer, timeout);
46 }
47 
48 
49 BSecureSocket::BSecureSocket(const BSecureSocket& other)
50 	:
51 	BSocket(other)
52 {
53 	// TODO: this won't work this way!
54 	fPrivate = (BSecureSocket::Private*)malloc(sizeof(BSecureSocket::Private));
55 	if (fPrivate != NULL)
56 		memcpy(fPrivate, other.fPrivate, sizeof(BSecureSocket::Private));
57 	else
58 		fInitStatus = B_NO_MEMORY;
59 }
60 
61 
62 BSecureSocket::~BSecureSocket()
63 {
64 	free(fPrivate);
65 }
66 
67 
68 status_t
69 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
70 {
71 	if (fPrivate == NULL) {
72 		fPrivate = (BSecureSocket::Private*)calloc(1,
73 			sizeof(BSecureSocket::Private));
74 		if (fPrivate == NULL)
75 			return B_NO_MEMORY;
76 	}
77 
78 	status_t status = BSocket::Connect(peer, timeout);
79 	if (status != B_OK)
80 		return status;
81 
82 	fPrivate->fCTX = SSL_CTX_new(SSLv23_method());
83 	fPrivate->fSSL = SSL_new(fPrivate->fCTX);
84 	fPrivate->fBIO = BIO_new_socket(fSocket, BIO_NOCLOSE);
85 	SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO);
86 
87 	if (SSL_connect(fPrivate->fSSL) <= 0) {
88 		TRACE("SSLConnection can't connect\n");
89 		BSocket::Disconnect();
90 		// TODO: translate ssl to Haiku error
91 		return B_ERROR;
92 	}
93 
94 	return B_OK;
95 }
96 
97 
98 void
99 BSecureSocket::Disconnect()
100 {
101 	if (IsConnected()) {
102 		if (fPrivate->fSSL != NULL) {
103 			SSL_shutdown(fPrivate->fSSL);
104 			fPrivate->fSSL = NULL;
105 		}
106 		if (fPrivate->fCTX != NULL) {
107 			SSL_CTX_free(fPrivate->fCTX);
108 			fPrivate->fCTX = NULL;
109 		}
110 
111 		BSocket::Disconnect();
112 			// Must do this before freeing the BIO, to make sure any pending
113 			// read or write gets unlocked properly.
114 		if (fPrivate->fBIO != NULL) {
115 			BIO_free(fPrivate->fBIO);
116 			fPrivate->fBIO = NULL;
117 		}
118 	}
119 }
120 
121 
122 status_t
123 BSecureSocket::WaitForReadable(bigtime_t timeout) const
124 {
125 	if (fInitStatus != B_OK)
126 		return fInitStatus;
127 	if (!IsConnected())
128 		return B_ERROR;
129 
130 	if (SSL_pending(fPrivate->fSSL) > 0)
131 		return B_OK;
132 
133 	return BSocket::WaitForReadable(timeout);
134 }
135 
136 
137 //	#pragma mark - BDataIO implementation
138 
139 
140 ssize_t
141 BSecureSocket::Read(void* buffer, size_t size)
142 {
143 	if (!IsConnected())
144 		return B_ERROR;
145 
146 	int bytesRead = SSL_read(fPrivate->fSSL, buffer, size);
147 	if (bytesRead >= 0)
148 		return bytesRead;
149 
150 	// TODO: translate SSL error codes!
151 	return B_ERROR;
152 }
153 
154 
155 ssize_t
156 BSecureSocket::Write(const void* buffer, size_t size)
157 {
158 	if (!IsConnected())
159 		return B_ERROR;
160 
161 	int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size);
162 	if (bytesWritten >= 0)
163 		return bytesWritten;
164 
165 	// TODO: translate SSL error codes!
166 	return B_ERROR;
167 }
168 
169 
170 #else	// OPENSSL_ENABLED
171 
172 
173 // #pragma mark - No-SSL stubs
174 
175 
176 BSecureSocket::BSecureSocket()
177 {
178 }
179 
180 
181 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
182 {
183 	fInitStatus = B_UNSUPPORTED;
184 }
185 
186 
187 BSecureSocket::BSecureSocket(const BSecureSocket& other)
188 	:
189 	BSocket(other)
190 {
191 }
192 
193 
194 BSecureSocket::~BSecureSocket()
195 {
196 }
197 
198 
199 status_t
200 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
201 {
202 	return fInitStatus = B_UNSUPPORTED;
203 }
204 
205 
206 void
207 BSecureSocket::Disconnect()
208 {
209 }
210 
211 
212 status_t
213 BSecureSocket::WaitForReadable(bigtime_t timeout) const
214 {
215 	return B_UNSUPPORTED;
216 }
217 
218 
219 //	#pragma mark - BDataIO implementation
220 
221 
222 ssize_t
223 BSecureSocket::Read(void* buffer, size_t size)
224 {
225 	return B_UNSUPPORTED;
226 }
227 
228 
229 ssize_t
230 BSecureSocket::Write(const void* buffer, size_t size)
231 {
232 	return B_UNSUPPORTED;
233 }
234 
235 
236 #endif	// !OPENSSL_ENABLED
237