/[resiprocate]/branches/b-identity-0505/DtlsTransport.cxx
ViewVC logotype

Contents of /branches/b-identity-0505/DtlsTransport.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4598 - (show annotations) (download)
Wed May 11 22:53:07 2005 UTC (14 years, 6 months ago) by derek
File size: 14800 byte(s)
set svn:eol-style to LF
1
2 #ifdef USE_DTLS
3
4 #if defined(HAVE_CONFIG_H)
5 #include "resiprocate/config.hxx"
6 #endif
7
8 #include <memory>
9
10 #ifndef RESIP_COMPAT_HXX
11 #include "resiprocate/os/compat.hxx"
12 #endif
13
14 #ifndef RESIP_DATA_HXX
15 #include "resiprocate/os/Data.hxx"
16 #endif
17
18 #ifndef RESIP_DNSUTIL_HXX
19 #include "resiprocate/os/DnsUtil.hxx"
20 #endif
21
22 #ifndef RESIP_SOCKET_HXX
23 #include "resiprocate/os/Socket.hxx"
24 #endif
25
26 #ifndef RESIP_LOGGER_HXX
27 #include "resiprocate/os/Logger.hxx"
28 #endif
29
30 #ifndef RESIP_SIPMESSAGE_HXX
31 #include "resiprocate/SipMessage.hxx"
32 #endif
33
34 #ifndef RESIP_HELPER_HXX
35 #include "resiprocate/Helper.hxx"
36 #endif
37
38 #ifndef RESIP_SECURITY_HXX
39 #include "resiprocate/Security.hxx"
40 #endif
41
42 #ifndef RESIP_DTLSMESSAGE_HXX
43 #include "resiprocate/DtlsMessage.hxx"
44 #endif
45
46 #ifndef RESIP_DTLSTRANSPORT_HXX
47 #include "resiprocate/DtlsTransport.hxx"
48 #endif
49
50 #include "resiprocate/os/WinLeakCheck.hxx"
51
52 #include <openssl/e_os2.h>
53 #include <openssl/evp.h>
54 #include <openssl/crypto.h>
55 #include <openssl/err.h>
56 #include <openssl/pem.h>
57 #include <openssl/pkcs7.h>
58 #include <openssl/x509v3.h>
59 #include <openssl/ssl.h>
60
61 #define RESIPROCATE_SUBSYSTEM Subsystem::TRANSPORT
62
63 using namespace std;
64 using namespace resip;
65
66 DtlsTransport::DtlsTransport(Fifo<TransactionMessage>& fifo,
67 int portNum,
68 IpVersion version,
69 const Data& interfaceObj,
70 Security& security,
71 const Data& sipDomain)
72 : UdpTransport( fifo, portNum, version, interfaceObj ),
73 mTimer( mHandshakePending ),
74 mSecurity( &security )
75 {
76 setTlsDomain(sipDomain);
77 InfoLog ( << "Creating DTLS transport host=" << interfaceObj
78 << " port=" << portNum
79 << " ipv4=" << version ) ;
80
81 mTuple.setType( transport() );
82
83 mClientCtx = SSL_CTX_new( DTLSv1_client_method() ) ;
84 mServerCtx = SSL_CTX_new( DTLSv1_server_method() ) ;
85 assert( mClientCtx ) ;
86 assert( mServerCtx ) ;
87
88 mDummyBio = BIO_new( BIO_s_mem() ) ;
89 assert( mDummyBio ) ;
90
91 /* trying to read from this BIO always returns retry */
92 BIO_set_mem_eof_return( mDummyBio, -1 ) ;
93 }
94
95 DtlsTransport::~DtlsTransport()
96 {
97 DebugLog (<< "Shutting down " << mTuple);
98 BIO_free( mDummyBio) ;
99 ThreadIf::shutdown();
100 join();
101 }
102
103 void
104 DtlsTransport::_read( FdSet& fdset )
105 {
106 //should this buffer be allocated on the stack and then copied out, as it
107 //needs to be deleted every time EWOULDBLOCK is encountered
108 // .dlb. can we determine the size of the buffer before we allocate?
109 // something about MSG_PEEK|MSG_TRUNC in Stevens..
110 // .dlb. RFC3261 18.1.1 MUST accept 65K datagrams. would have to attempt to
111 // adjust the UDP buffer as well...
112 unsigned int bufferLen = UdpTransport::MaxBufferSize + 5 ;
113 char* buffer = new char[ bufferLen ] ;
114 unsigned char *pt = new unsigned char[ bufferLen ] ;
115
116 SSL *ssl ;
117 BIO *rbio ;
118 BIO *wbio ;
119
120 // !jf! how do we tell if it discarded bytes
121 // !ah! we use the len-1 trick :-(
122 Tuple tuple(mTuple) ;
123 socklen_t slen = tuple.length() ;
124 int len = recvfrom( mFd,
125 buffer,
126 UdpTransport::MaxBufferSize,
127 0 /*flags */,
128 &tuple.getMutableSockaddr(),
129 &slen ) ;
130 if ( len == SOCKET_ERROR )
131 {
132 int err = getErrno() ;
133 if ( err != EWOULDBLOCK )
134 {
135 error( err ) ;
136 }
137 }
138
139 if (len == 0 || len == SOCKET_ERROR)
140 {
141 delete [] buffer ;
142 buffer = 0 ;
143 return ;
144 }
145
146 if ( len + 1 >= UdpTransport::MaxBufferSize )
147 {
148 InfoLog (<<"Datagram exceeded max length "<<UdpTransport::MaxBufferSize ) ;
149 delete [] buffer ; buffer = 0 ;
150 return ;
151 }
152
153 //DebugLog ( << "UDP Rcv : " << len << " b" );
154 //DebugLog ( << Data(buffer, len).escaped().c_str());
155
156 /* begin SSL stuff */
157 struct sockaddr peer = tuple.getMutableSockaddr() ;
158
159 ssl = mDtlsConnections[ *((struct sockaddr_in *)&peer) ] ;
160
161 /*
162 * If we don't have a binding for this peer,
163 * then we're a server.
164 */
165 if ( ssl == NULL )
166 {
167 ssl = SSL_new( mServerCtx ) ;
168 assert( ssl ) ;
169
170 SSL_set_accept_state( ssl ) ;
171
172 X509 *cert = mSecurity->getDomainCert( mDomain ) ;
173 assert( cert ) ;
174
175 EVP_PKEY *pkey = mSecurity->getDomainKey( mDomain ) ;
176 assert( pkey ) ;
177
178 if( ! SSL_use_certificate( ssl, cert ) )
179 {
180 throw Security::Exception( "SSL_use_certificate failed",
181 __FILE__, __LINE__ ) ;
182 }
183
184 if ( ! SSL_use_PrivateKey( ssl, pkey ) )
185 throw Security::Exception( "SSL_use_PrivateKey failed.",
186 __FILE__, __LINE__ ) ;
187
188 wbio = BIO_new_dgram( mFd, BIO_NOCLOSE ) ;
189 assert( wbio ) ;
190
191 BIO_dgram_set_peer( wbio, &peer ) ;
192
193 SSL_set_bio( ssl, NULL, wbio ) ;
194
195 /* remember this connection */
196 mDtlsConnections[ *((struct sockaddr_in *)&peer) ] = ssl ;
197 }
198
199 rbio = BIO_new_mem_buf( buffer, len ) ;
200 BIO_set_mem_eof_return( rbio, -1 ) ;
201
202 ssl->rbio = rbio ;
203
204 len = SSL_read( ssl, pt, UdpTransport::MaxBufferSize ) ;
205 int err = SSL_get_error( ssl, len ) ;
206
207 /* done with the rbio */
208 BIO_free( ssl->rbio ) ;
209 ssl->rbio = mDummyBio ;
210 delete [] buffer ;
211 buffer = 0 ;
212
213 if ( len <= 0 )
214 {
215 switch( err )
216 {
217 case SSL_ERROR_NONE:
218 break ;
219 case SSL_ERROR_SSL:
220 break ;
221 case SSL_ERROR_WANT_READ:
222 break ;
223 case SSL_ERROR_WANT_WRITE:
224 break ;
225 case SSL_ERROR_SYSCALL:
226 break ;
227 /* connection closed */
228 case SSL_ERROR_ZERO_RETURN:
229 _cleanupConnectionState( ssl, *((struct sockaddr_in *)&peer) ) ;
230 break ;
231 case SSL_ERROR_WANT_CONNECT:
232 break ;
233 case SSL_ERROR_WANT_ACCEPT:
234 break ;
235 default:
236 break ;
237 }
238 }
239
240 if ( len <= 0 )
241 return ;
242
243 if ( SSL_in_init( ssl ) )
244 mTimer.add( ssl, DtlsReceiveTimeout ) ;
245
246 SipMessage* message = new SipMessage(this);
247
248 // set the received from information into the received= parameter in the
249 // via
250
251 // It is presumed that UDP Datagrams are arriving atomically and that
252 // each one is a unique SIP message
253
254
255 // Save all the info where this message came from
256 tuple.transport = this ;
257 message->setSource( tuple ) ;
258 //DebugLog (<< "Received from: " << tuple);
259
260 // Tell the SipMessage about this datagram buffer.
261 message->addBuffer( (char *)pt ) ;
262
263 mMsgHeaderScanner.prepareForMessage( message ) ;
264
265 char *unprocessedCharPtr ;
266 if (mMsgHeaderScanner.scanChunk( (char *)pt,
267 len,
268 &unprocessedCharPtr ) !=
269 MsgHeaderScanner::scrEnd)
270 {
271 DebugLog( << "Scanner rejecting datagram as unparsable / fragmented from "
272 << tuple ) ;
273 DebugLog( << Data( pt, len ) ) ;
274 delete message ;
275 message = 0 ;
276 return ;
277 }
278
279 // no pp error
280 int used = unprocessedCharPtr - (char *)pt ;
281
282 if ( used < len )
283 {
284 // body is present .. add it up.
285 // NB. The Sip Message uses an overlay (again)
286 // for the body. It ALSO expects that the body
287 // will be contiguous (of course).
288 // it doesn't need a new buffer in UDP b/c there
289 // will only be one datagram per buffer. (1:1 strict)
290
291 message->setBody( (char *)pt + used, len - used ) ;
292 //DebugLog(<<"added " << len-used << " byte body");
293 }
294
295 if ( ! basicCheck( *message ) )
296 {
297 delete message ; // cannot use it, so, punt on it...
298 // basicCheck queued any response required
299 message = 0 ;
300 return ;
301 }
302
303 stampReceived( message) ;
304
305 mStateMachineFifo.add( message ) ;
306 }
307
308 void DtlsTransport::_write( FdSet& fdset )
309 {
310 SSL *ssl ;
311 BIO *wBio ;
312 int retry = 0 ;
313
314 std::auto_ptr<SendData> sendData = std::auto_ptr<SendData>(mTxFifo.getNext());
315 //DebugLog (<< "Sent: " << sendData->data);
316 //DebugLog (<< "Sending message on udp.");
317
318 assert( &(*sendData) );
319 assert( sendData->destination.getPort() != 0 );
320
321 sockaddr peer = sendData->destination.getSockaddr();
322
323 ssl = mDtlsConnections[ *((struct sockaddr_in *)&peer) ] ;
324
325 /* If we don't have a binding, then we're a client */
326 if ( ssl == NULL )
327 {
328 ssl = SSL_new( mClientCtx ) ;
329 assert( ssl ) ;
330
331 SSL_set_connect_state( ssl ) ;
332
333 wBio = BIO_new_dgram( mFd, BIO_NOCLOSE ) ;
334 assert( wBio ) ;
335
336 BIO_dgram_set_peer( wBio, &peer) ;
337
338 /* the real rbio will be set by _read */
339 SSL_set_bio( ssl, mDummyBio, wBio ) ;
340
341 /* we should be ready to take this out if the
342 * connection fails later */
343 mDtlsConnections [ *((struct sockaddr_in *)&peer) ] = ssl ;
344 }
345
346 int count = SSL_write(ssl, sendData->data.data(),
347 sendData->data.size());
348
349 /*
350 * all reads go through _read, so the most likely result during a handshake
351 * will be SSL_ERROR_WANT_READ
352 */
353
354 if ( count <= 0 )
355 {
356 int err = SSL_get_error( ssl, count ) ;
357 switch( err )
358 {
359 case SSL_ERROR_NONE:
360 break;
361 case SSL_ERROR_SSL:
362 break;
363 case SSL_ERROR_WANT_READ:
364 retry = 1 ;
365 break;
366 case SSL_ERROR_WANT_WRITE:
367 retry = 1 ;
368 fdset.setWrite(mFd);
369 break;
370 case SSL_ERROR_SYSCALL:
371 {
372 int e = getErrno();
373 error(e);
374 InfoLog (<< "Failed (" << e << ") sending to "
375 << sendData->destination);
376 fail(sendData->transactionId);
377 break;
378 }
379 case SSL_ERROR_ZERO_RETURN:
380 _cleanupConnectionState( ssl, *((struct sockaddr_in *)&peer) ) ;
381 break ;
382 case SSL_ERROR_WANT_CONNECT:
383 break;
384 case SSL_ERROR_WANT_ACCEPT:
385 break;
386 default:
387 break ;
388 }
389 }
390
391 if ( ! retry && count != int(sendData->data.size()) )
392 {
393 ErrLog (<< "UDPTransport - send buffer full" );
394 fail(sendData->transactionId);
395 }
396 }
397
398 void
399 DtlsTransport::_doHandshake( void )
400 {
401 DtlsMessage *msg = mHandshakePending.getNext() ;
402 SSL *ssl = msg->getSsl() ;
403
404 delete msg ;
405
406 int ret = SSL_do_handshake( ssl ) ;
407
408 switch( ret )
409 {
410 case SSL_ERROR_NONE:
411 break;
412 case SSL_ERROR_SSL:
413 break;
414 case SSL_ERROR_WANT_READ:
415 break;
416 case SSL_ERROR_WANT_WRITE:
417 break;
418 case SSL_ERROR_SYSCALL:
419 break;
420 case SSL_ERROR_ZERO_RETURN:
421 break;
422 case SSL_ERROR_WANT_CONNECT:
423 break;
424 case SSL_ERROR_WANT_ACCEPT:
425 break;
426 default:
427 break ;
428 }
429 }
430
431 void
432 DtlsTransport::process(FdSet& fdset)
433 {
434 // pull buffers to send out of TxFifo
435 // receive datagrams from fd
436 // preparse and stuff into RxFifo
437
438 mTimer.process() ;
439
440 while ( mHandshakePending.messageAvailable() )
441 _doHandshake() ;
442
443 if ( mTxFifo.messageAvailable() && fdset.readyToWrite( mFd ) )
444 _write( fdset ) ;
445
446 // !jf! this may have to change - when we read a message that is too big
447 if ( fdset.readyToRead(mFd) )
448 _read( fdset) ;
449 }
450
451
452 void
453 DtlsTransport::buildFdSet( FdSet& fdset )
454 {
455 fdset.setRead(mFd);
456
457 if (mTxFifo.messageAvailable())
458 {
459 fdset.setWrite(mFd);
460 }
461 }
462
463 void
464 DtlsTransport::_cleanupConnectionState( SSL *ssl, struct sockaddr_in peer )
465 {
466 /*
467 * SSL_free decrements the ref-count for mDummyBio by 1, so
468 * add 1 to the ref-count to make sure it does not get free'd
469 */
470 CRYPTO_add( &mDummyBio->references, 1, CRYPTO_LOCK_BIO ) ;
471 SSL_free( ssl ) ;
472 mDtlsConnections.erase( peer ) ;
473 }
474
475 void
476 DtlsTransport::_mapDebug( const char *where, const char *action, SSL *ssl )
477 {
478 fprintf( stderr, "%s: %s\t%p\n", where, action, ssl ) ;
479 fprintf( stderr, "map sizet = %d\n", mDtlsConnections.size() ) ;
480 }
481
482 void
483 DtlsTransport::_printSock( const struct sockaddr_in *sock )
484 {
485 fprintf( stderr, "addr = %s\t port = %d\n", inet_ntoa( sock->sin_addr ),
486 ntohs( sock->sin_port ) ) ;
487 }
488
489 #endif /* USE_DTLS */
490
491 /* ====================================================================
492 * The Vovida Software License, Version 1.0
493 *
494 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
495 *
496 * Redistribution and use in source and binary forms, with or without
497 * modification, are permitted provided that the following conditions
498 * are met:
499 *
500 * 1. Redistributions of source code must retain the above copyright
501 * notice, this list of conditions and the following disclaimer.
502 *
503 * 2. Redistributions in binary form must reproduce the above copyright
504 * notice, this list of conditions and the following disclaimer in
505 * the documentation and/or other materials provided with the
506 * distribution.
507 *
508 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
509 * and "Vovida Open Communication Application Library (VOCAL)" must
510 * not be used to endorse or promote products derived from this
511 * software without prior written permission. For written
512 * permission, please contact vocal@vovida.org.
513 *
514 * 4. Products derived from this software may not be called "VOCAL", nor
515 * may "VOCAL" appear in their name, without prior written
516 * permission of Vovida Networks, Inc.
517 *
518 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
519 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
520 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
521 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
522 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
523 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
524 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
525 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
526 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
527 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
528 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
529 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
530 * DAMAGE.
531 *
532 * ====================================================================
533 *
534 * This software consists of voluntary contributions made by Vovida
535 * Networks, Inc. and many individuals on behalf of Vovida Networks,
536 * Inc. For more information on Vovida Networks, Inc., please see
537 * <http://www.vovida.org/>.
538 *
539 */

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27