BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file PeerChat.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29  
30 #include <string.h>
31  
32 #include <nss/ssl.h>
33 #include <nss/sslerr.h>
34  
35 #include <misc/byteorder.h>
36 #include <security/BRandom.h>
37  
38 #include "PeerChat.h"
39  
40 #include <generated/blog_channel_PeerChat.h>
41  
42 #define PeerLog(_o, ...) BLog_LogViaFunc((_o)->logfunc, (_o)->user, BLOG_CURRENT_CHANNEL, __VA_ARGS__)
43  
44 static void report_error (PeerChat *o)
45 {
46 DebugError_AssertNoError(&o->d_err);
47  
48 DEBUGERROR(&o->d_err, o->handler_error(o->user))
49 return;
50 }
51  
52 static void recv_job_handler (PeerChat *o)
53 {
54 DebugObject_Access(&o->d_obj);
55 DebugError_AssertNoError(&o->d_err);
56 ASSERT(o->recv_data_len >= 0)
57 ASSERT(o->recv_data_len <= SC_MAX_MSGLEN)
58  
59 int data_len = o->recv_data_len;
60  
61 // set no received data
62 o->recv_data_len = -1;
63  
64 #ifdef PEERCHAT_SIMULATE_ERROR
65 uint8_t x;
66 BRandom_randomize(&x, sizeof(x));
67 if (x < PEERCHAT_SIMULATE_ERROR) {
68 PeerLog(o, BLOG_ERROR, "simulate error");
69 report_error(o);
70 return;
71 }
72 #endif
73  
74 if (o->ssl_mode != PEERCHAT_SSL_NONE) {
75 // buffer data
76 if (!SimpleStreamBuffer_Write(&o->ssl_recv_buf, o->recv_data, data_len)) {
77 PeerLog(o, BLOG_ERROR, "out of recv buffer");
78 report_error(o);
79 return;
80 }
81 } else {
82 // call message handler
83 o->handler_message(o->user, o->recv_data, data_len);
84 return;
85 }
86 }
87  
88 static void ssl_con_handler (PeerChat *o, int event)
89 {
90 DebugObject_Access(&o->d_obj);
91 DebugError_AssertNoError(&o->d_err);
92 ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
93 ASSERT(event == BSSLCONNECTION_EVENT_ERROR)
94  
95 PeerLog(o, BLOG_ERROR, "SSL error");
96  
97 report_error(o);
98 return;
99 }
100  
101 static SECStatus client_auth_data_callback (PeerChat *o, PRFileDesc *fd, CERTDistNames *caNames, CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey)
102 {
103 DebugObject_Access(&o->d_obj);
104 ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT)
105  
106 CERTCertificate *cert = CERT_DupCertificate(o->ssl_cert);
107 if (!cert) {
108 PeerLog(o, BLOG_ERROR, "CERT_DupCertificate failed");
109 goto fail0;
110 }
111  
112 SECKEYPrivateKey *key = SECKEY_CopyPrivateKey(o->ssl_key);
113 if (!key) {
114 PeerLog(o, BLOG_ERROR, "SECKEY_CopyPrivateKey failed");
115 goto fail1;
116 }
117  
118 *pRetCert = cert;
119 *pRetKey = key;
120 return SECSuccess;
121  
122 fail1:
123 CERT_DestroyCertificate(cert);
124 fail0:
125 return SECFailure;
126 }
127  
128 static SECStatus auth_certificate_callback (PeerChat *o, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
129 {
130 DebugObject_Access(&o->d_obj);
131 ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
132  
133 // This callback is used to bypass checking the server's domain name, as peers
134 // don't have domain names. We byte-compare the certificate to the one reported
135 // by the server anyway.
136  
137 SECStatus ret = SECFailure;
138  
139 CERTCertificate *cert = SSL_PeerCertificate(o->ssl_prfd);
140 if (!cert) {
141 PeerLog(o, BLOG_ERROR, "SSL_PeerCertificate failed");
142 PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
143 goto fail1;
144 }
145  
146 SECCertUsage cert_usage = (o->ssl_mode == PEERCHAT_SSL_CLIENT ? certUsageSSLServer : certUsageSSLClient);
147  
148 if (CERT_VerifyCertNow(CERT_GetDefaultCertDB(), cert, PR_TRUE, cert_usage, SSL_RevealPinArg(o->ssl_prfd)) != SECSuccess) {
149 goto fail2;
150 }
151  
152 // compare to certificate provided by the server
153 SECItem der = cert->derCert;
154 if (der.len != o->ssl_peer_cert_len || memcmp(der.data, o->ssl_peer_cert, der.len)) {
155 PeerLog(o, BLOG_ERROR, "peer certificate doesn't match");
156 PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
157 goto fail2;
158 }
159  
160 ret = SECSuccess;
161  
162 fail2:
163 CERT_DestroyCertificate(cert);
164 fail1:
165 return ret;
166 }
167  
168 static void ssl_recv_if_handler_send (PeerChat *o, uint8_t *data, int data_len)
169 {
170 DebugObject_Access(&o->d_obj);
171 DebugError_AssertNoError(&o->d_err);
172 ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
173 ASSERT(data_len >= 0)
174 ASSERT(data_len <= SC_MAX_MSGLEN)
175  
176 // accept packet
177 PacketPassInterface_Done(&o->ssl_recv_if);
178  
179 // call message handler
180 o->handler_message(o->user, data, data_len);
181 return;
182 }
183  
184 static void ssl_recv_decoder_handler_error (PeerChat *o)
185 {
186 DebugObject_Access(&o->d_obj);
187 DebugError_AssertNoError(&o->d_err);
188 ASSERT(o->ssl_mode == PEERCHAT_SSL_CLIENT || o->ssl_mode == PEERCHAT_SSL_SERVER)
189  
190 PeerLog(o, BLOG_ERROR, "decoder error");
191  
192 report_error(o);
193 return;
194 }
195  
196 int PeerChat_Init (PeerChat *o, peerid_t peer_id, int ssl_mode, int ssl_flags, CERTCertificate *ssl_cert, SECKEYPrivateKey *ssl_key,
197 uint8_t *ssl_peer_cert, int ssl_peer_cert_len, BPendingGroup *pg, BThreadWorkDispatcher *twd, void *user,
198 BLog_logfunc logfunc,
199 PeerChat_handler_error handler_error,
200 PeerChat_handler_message handler_message)
201 {
202 ASSERT(ssl_mode == PEERCHAT_SSL_NONE || ssl_mode == PEERCHAT_SSL_CLIENT || ssl_mode == PEERCHAT_SSL_SERVER)
203 ASSERT(ssl_mode == PEERCHAT_SSL_NONE || ssl_peer_cert_len >= 0)
204 ASSERT(logfunc)
205 ASSERT(handler_error)
206 ASSERT(handler_message)
207  
208 // init arguments
209 o->ssl_mode = ssl_mode;
210 o->ssl_cert = ssl_cert;
211 o->ssl_key = ssl_key;
212 o->ssl_peer_cert = ssl_peer_cert;
213 o->ssl_peer_cert_len = ssl_peer_cert_len;
214 o->user = user;
215 o->logfunc = logfunc;
216 o->handler_error = handler_error;
217 o->handler_message = handler_message;
218  
219 // init copier
220 PacketCopier_Init(&o->copier, SC_MAX_MSGLEN, pg);
221  
222 // init SC encoder
223 SCOutmsgEncoder_Init(&o->sc_encoder, peer_id, PacketCopier_GetOutput(&o->copier), pg);
224  
225 // init PacketProto encoder
226 PacketProtoEncoder_Init(&o->pp_encoder, SCOutmsgEncoder_GetOutput(&o->sc_encoder), pg);
227  
228 // init recv job
229 BPending_Init(&o->recv_job, pg, (BPending_handler)recv_job_handler, o);
230  
231 // set no received data
232 o->recv_data_len = -1;
233  
234 PacketPassInterface *send_buf_output = PacketCopier_GetInput(&o->copier);
235  
236 if (o->ssl_mode != PEERCHAT_SSL_NONE) {
237 // init receive buffer
238 if (!SimpleStreamBuffer_Init(&o->ssl_recv_buf, PEERCHAT_SSL_RECV_BUF_SIZE, pg)) {
239 PeerLog(o, BLOG_ERROR, "SimpleStreamBuffer_Init failed");
240 goto fail1;
241 }
242  
243 // init SSL StreamPacketSender
244 StreamPacketSender_Init(&o->ssl_sp_sender, send_buf_output, pg);
245  
246 // init SSL bottom prfd
247 if (!BSSLConnection_MakeBackend(&o->ssl_bottom_prfd, StreamPacketSender_GetInput(&o->ssl_sp_sender), SimpleStreamBuffer_GetOutput(&o->ssl_recv_buf), twd, ssl_flags)) {
248 PeerLog(o, BLOG_ERROR, "BSSLConnection_MakeBackend failed");
249 goto fail2;
250 }
251  
252 // init SSL prfd
253 if (!(o->ssl_prfd = SSL_ImportFD(NULL, &o->ssl_bottom_prfd))) {
254 ASSERT_FORCE(PR_Close(&o->ssl_bottom_prfd) == PR_SUCCESS)
255 PeerLog(o, BLOG_ERROR, "SSL_ImportFD failed");
256 goto fail2;
257 }
258  
259 // set client or server mode
260 if (SSL_ResetHandshake(o->ssl_prfd, (o->ssl_mode == PEERCHAT_SSL_SERVER ? PR_TRUE : PR_FALSE)) != SECSuccess) {
261 PeerLog(o, BLOG_ERROR, "SSL_ResetHandshake failed");
262 goto fail3;
263 }
264  
265 if (o->ssl_mode == PEERCHAT_SSL_SERVER) {
266 // set server certificate
267 if (SSL_ConfigSecureServer(o->ssl_prfd, o->ssl_cert, o->ssl_key, NSS_FindCertKEAType(o->ssl_cert)) != SECSuccess) {
268 PeerLog(o, BLOG_ERROR, "SSL_ConfigSecureServer failed");
269 goto fail3;
270 }
271  
272 // set require client certificate
273 if (SSL_OptionSet(o->ssl_prfd, SSL_REQUEST_CERTIFICATE, PR_TRUE) != SECSuccess) {
274 PeerLog(o, BLOG_ERROR, "SSL_OptionSet(SSL_REQUEST_CERTIFICATE) failed");
275 goto fail3;
276 }
277 if (SSL_OptionSet(o->ssl_prfd, SSL_REQUIRE_CERTIFICATE, PR_TRUE) != SECSuccess) {
278 PeerLog(o, BLOG_ERROR, "SSL_OptionSet(SSL_REQUIRE_CERTIFICATE) failed");
279 goto fail3;
280 }
281 } else {
282 // set client certificate callback
283 if (SSL_GetClientAuthDataHook(o->ssl_prfd, (SSLGetClientAuthData)client_auth_data_callback, o) != SECSuccess) {
284 PeerLog(o, BLOG_ERROR, "SSL_GetClientAuthDataHook failed");
285 goto fail3;
286 }
287 }
288  
289 // set verify peer certificate hook
290 if (SSL_AuthCertificateHook(o->ssl_prfd, (SSLAuthCertificate)auth_certificate_callback, o) != SECSuccess) {
291 PeerLog(o, BLOG_ERROR, "SSL_AuthCertificateHook failed");
292 goto fail3;
293 }
294  
295 // init SSL connection
296 BSSLConnection_Init(&o->ssl_con, o->ssl_prfd, 0, pg, o, (BSSLConnection_handler)ssl_con_handler);
297  
298 // init SSL PacketStreamSender
299 PacketStreamSender_Init(&o->ssl_ps_sender, BSSLConnection_GetSendIf(&o->ssl_con), sizeof(struct packetproto_header) + SC_MAX_MSGLEN, pg);
300  
301 // init SSL copier
302 PacketCopier_Init(&o->ssl_copier, SC_MAX_MSGLEN, pg);
303  
304 // init SSL encoder
305 PacketProtoEncoder_Init(&o->ssl_encoder, PacketCopier_GetOutput(&o->ssl_copier), pg);
306  
307 // init SSL buffer
308 if (!SinglePacketBuffer_Init(&o->ssl_buffer, PacketProtoEncoder_GetOutput(&o->ssl_encoder), PacketStreamSender_GetInput(&o->ssl_ps_sender), pg)) {
309 PeerLog(o, BLOG_ERROR, "SinglePacketBuffer_Init failed");
310 goto fail4;
311 }
312  
313 // init receive interface
314 PacketPassInterface_Init(&o->ssl_recv_if, SC_MAX_MSGLEN, (PacketPassInterface_handler_send)ssl_recv_if_handler_send, o, pg);
315  
316 // init receive decoder
317 if (!PacketProtoDecoder_Init(&o->ssl_recv_decoder, BSSLConnection_GetRecvIf(&o->ssl_con), &o->ssl_recv_if, pg, o, (PacketProtoDecoder_handler_error)ssl_recv_decoder_handler_error)) {
318 PeerLog(o, BLOG_ERROR, "PacketProtoDecoder_Init failed");
319 goto fail5;
320 }
321  
322 send_buf_output = PacketCopier_GetInput(&o->ssl_copier);
323 }
324  
325 // init send writer
326 BufferWriter_Init(&o->send_writer, SC_MAX_MSGLEN, pg);
327  
328 // init send buffer
329 if (!PacketBuffer_Init(&o->send_buf, BufferWriter_GetOutput(&o->send_writer), send_buf_output, PEERCHAT_SEND_BUF_SIZE, pg)) {
330 PeerLog(o, BLOG_ERROR, "PacketBuffer_Init failed");
331 goto fail6;
332 }
333  
334 DebugError_Init(&o->d_err, pg);
335 DebugObject_Init(&o->d_obj);
336 return 1;
337  
338 fail6:
339 BufferWriter_Free(&o->send_writer);
340 if (o->ssl_mode != PEERCHAT_SSL_NONE) {
341 PacketProtoDecoder_Free(&o->ssl_recv_decoder);
342 fail5:
343 PacketPassInterface_Free(&o->ssl_recv_if);
344 SinglePacketBuffer_Free(&o->ssl_buffer);
345 fail4:
346 PacketProtoEncoder_Free(&o->ssl_encoder);
347 PacketCopier_Free(&o->ssl_copier);
348 PacketStreamSender_Free(&o->ssl_ps_sender);
349 BSSLConnection_Free(&o->ssl_con);
350 fail3:
351 ASSERT_FORCE(PR_Close(o->ssl_prfd) == PR_SUCCESS)
352 fail2:
353 StreamPacketSender_Free(&o->ssl_sp_sender);
354 SimpleStreamBuffer_Free(&o->ssl_recv_buf);
355 }
356 fail1:
357 BPending_Free(&o->recv_job);
358 PacketProtoEncoder_Free(&o->pp_encoder);
359 SCOutmsgEncoder_Free(&o->sc_encoder);
360 PacketCopier_Free(&o->copier);
361 return 0;
362 }
363  
364 void PeerChat_Free (PeerChat *o)
365 {
366 DebugObject_Free(&o->d_obj);
367 DebugError_Free(&o->d_err);
368  
369 // stop using any buffers before they get freed
370 if (o->ssl_mode != PEERCHAT_SSL_NONE) {
371 BSSLConnection_ReleaseBuffers(&o->ssl_con);
372 }
373  
374 PacketBuffer_Free(&o->send_buf);
375 BufferWriter_Free(&o->send_writer);
376 if (o->ssl_mode != PEERCHAT_SSL_NONE) {
377 PacketProtoDecoder_Free(&o->ssl_recv_decoder);
378 PacketPassInterface_Free(&o->ssl_recv_if);
379 SinglePacketBuffer_Free(&o->ssl_buffer);
380 PacketProtoEncoder_Free(&o->ssl_encoder);
381 PacketCopier_Free(&o->ssl_copier);
382 PacketStreamSender_Free(&o->ssl_ps_sender);
383 BSSLConnection_Free(&o->ssl_con);
384 ASSERT_FORCE(PR_Close(o->ssl_prfd) == PR_SUCCESS)
385 StreamPacketSender_Free(&o->ssl_sp_sender);
386 SimpleStreamBuffer_Free(&o->ssl_recv_buf);
387 }
388 BPending_Free(&o->recv_job);
389 PacketProtoEncoder_Free(&o->pp_encoder);
390 SCOutmsgEncoder_Free(&o->sc_encoder);
391 PacketCopier_Free(&o->copier);
392 }
393  
394 PacketRecvInterface * PeerChat_GetSendOutput (PeerChat *o)
395 {
396 DebugObject_Access(&o->d_obj);
397  
398 return PacketProtoEncoder_GetOutput(&o->pp_encoder);
399 }
400  
401 void PeerChat_InputReceived (PeerChat *o, uint8_t *data, int data_len)
402 {
403 DebugObject_Access(&o->d_obj);
404 DebugError_AssertNoError(&o->d_err);
405 ASSERT(o->recv_data_len == -1)
406 ASSERT(data_len >= 0)
407 ASSERT(data_len <= SC_MAX_MSGLEN)
408  
409 // remember data
410 o->recv_data = data;
411 o->recv_data_len = data_len;
412  
413 // set received job
414 BPending_Set(&o->recv_job);
415 }
416  
417 int PeerChat_StartMessage (PeerChat *o, uint8_t **data)
418 {
419 DebugObject_Access(&o->d_obj);
420 DebugError_AssertNoError(&o->d_err);
421  
422 return BufferWriter_StartPacket(&o->send_writer, data);
423 }
424  
425 void PeerChat_EndMessage (PeerChat *o, int data_len)
426 {
427 DebugObject_Access(&o->d_obj);
428 DebugError_AssertNoError(&o->d_err);
429 ASSERT(data_len >= 0)
430 ASSERT(data_len <= SC_MAX_MSGLEN)
431  
432 BufferWriter_EndPacket(&o->send_writer, data_len);
433 }