DCL 4.0
Loading...
Searching...
No Matches
SSLSocket Class Reference

#include <SSLSocket.h>

Inheritance diagram for SSLSocket:
Socket PollAble File Object

Public Member Functions

 SSLSocket () __DCL_THROWS1(SSLException *)
 SSLSocket (const String &_addr, uint16_t _port) __DCL_THROWS2(IOException *
SSLException *virtual ~SSLSocket ()
virtual void close () __DCL_THROWS1(IOException *)
virtual void connect (const sockaddr *_serv_addr, socklen_t _addrlen) __DCL_THROWS1(IOException *)
virtual size_t send (const void *_buf, size_t _n, int _flags=0) __DCL_THROWS1(IOException *)
virtual size_t recv (void *_buf, size_t _n, int _flags=0) __DCL_THROWS1(IOException *)
bool isPeerCertificateVerified () const
String getPeerCertificateCommonName () const
Public Member Functions inherited from File
virtual String toString () const
virtual ~File ()
 File (const String &_path, int _oflags=READONLY, int _mode=0666) __DCL_THROWS1(IOException *)
void open (const String &_path, int _oflags=READONLY, int _mode=0666) __DCL_THROWS1(IOException *)
 File (HandleType _handle, int _ohints, bool _closeOnClose) __DCL_THROWS1(IOException *)
void open (HandleType _handle, int _ohints, bool _closeOnClose) __DCL_THROWS1(IOException *)
virtual void sync () __DCL_THROWS1(IOException *)
off_t seek (off_t _offset, int _whence) __DCL_THROWS1(IOException *)
off_t size () const __DCL_THROWS1(IOException *)
DateTime mtime () const __DCL_THROWS1(IOException *)
bool time (time_t *_atime, time_t *_mtime, time_t *_ctime) const
HandleType handle () const
const String & path () const
Public Member Functions inherited from Object
virtual void destroy ()
String className () const
bool isInstanceOf (const std::type_info &typeinfo) const
virtual const std::type_info & typeInfo () const

Protected Member Functions

void construct () __DCL_THROWS1(SSLException *)
Protected Member Functions inherited from Socket
virtual bool onEvent (short _revents, PollThread *_pPollThread) __DCL_THROWS1(IOException *)
Protected Member Functions inherited from File
 File ()
 File (HandleType _handle, const String &_path)
Protected Member Functions inherited from Object
virtual ~Object ()
 Object ()

Additional Inherited Members

Public Types inherited from File
enum  Whence { BEGIN , CURRENT , END }
Static Public Member Functions inherited from File
static FileopenTempFile (const String &_dirname, const String &_prefix, unsigned int _mode=0666) __DCL_THROWS1(IOException *)
Protected Attributes inherited from File
String __path
HandleType __handle
bool __closeOnClose

Detailed Description

SSL/TLS 소켓에 대한 파일 인터페이스와 Non-Blocking 입출력을 제공한다.

See also
PollThread
SocketPollThread
openssl

Definition at line 49 of file SSLSocket.h.

Constructor & Destructor Documentation

◆ SSLSocket() [1/2]

SSLSocket::SSLSocket ( )

Definition at line 265 of file SSLSocket.cpp.

267{
268 construct();
269}
void construct() __DCL_THROWS1(SSLException *)

◆ SSLSocket() [2/2]

SSLSocket::SSLSocket ( const String & _addr,
uint16_t _port )

◆ ~SSLSocket()

SSLSocket::~SSLSocket ( )
virtual

Definition at line 278 of file SSLSocket.cpp.

279{
280#if __DCL_USE_OPENSSL
281 if (__ssl)
282#elif __DCL_USE_SCHANNEL
283 if (SecIsValidHandle(&__ctxt))
284#endif
285 {
286 try {
287 close();
288 }
289 catch (Exception* cause) {
290 __DCL_TRACE1(__T("Error! SSLSocket::~SSLSocket %ls\n"), cause->toString().data());
291 cause->destroy();
292 }
293 }
294
295#if __DCL_USE_OPENSSL
296 if (__ctx) {
297 SSL_CTX_free(__ctx);
298 #if __DCL_DEBUG
299 __ctx = NULL;
300 #endif
301 }
302
303#elif __DCL_USE_SCHANNEL
304 if (SecIsValidHandle(&__cred)) {
305 SECURITY_STATUS ss = FreeCredentialsHandle(&__cred);
306 #if __DCL_DEBUG
307 if (ss != SEC_E_OK)
308 __DCL_TRACE1(__T("Warning!! [%ls]\n"), __GetStatusMessage(ss).data());
309 SecInvalidateHandle(&__cred);
310 #endif
311 }
312
313#endif
314}
#define NULL
Definition Config.h:340
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:376
#define __T(str)
Definition Object.h:44
virtual String toString() const
Definition Exception.cpp:40
virtual void destroy()
Definition Exception.cpp:74
virtual void close() __DCL_THROWS1(IOException *)

Member Function Documentation

◆ close()

void SSLSocket::close ( )
virtual

파일을 닫는다.

Reimplemented from Socket.

Definition at line 316 of file SSLSocket.cpp.

318{
319#if __DCL_USE_OPENSSL
320 __DCL_ASSERT_HANDLE(__ssl != NULL);
321 SSL_free(__ssl);
322 __ssl = NULL;
323
324#elif __DCL_USE_SCHANNEL
325 __DCL_ASSERT_HANDLE(SecIsValidHandle(&__ctxt));
326 SECURITY_STATUS ss = DeleteSecurityContext(&__ctxt);
327 #if __DCL_DEBUG
328 if (ss != SEC_E_OK)
329 __DCL_TRACE1(__T("Warning!! [%ls]\n"), __GetStatusMessage(ss).data());
330 #endif
331 SecInvalidateHandle(&__ctxt);
332
333#endif
334
336}
#define __DCL_ASSERT_HANDLE(expr)
Definition Object.h:383
virtual void close() __DCL_THROWS1(IOException *)
Definition File.cpp:363

◆ connect()

void SSLSocket::connect ( const sockaddr * _serv_addr,
socklen_t _addrlen )
virtual

Reimplemented from Socket.

Definition at line 350 of file SSLSocket.cpp.

352{
353 Socket::connect(_serv_addr, _addrlen);
354
355 __DCL_TRACE0(__T("SSLSocket::connect()\n"));
356
357#if __DCL_USE_OPENSSL
358 __DCL_ASSERT_HANDLE(__ctx != NULL);
359 __DCL_ASSERT_HANDLE(__ssl == NULL);
360 __ssl = SSL_new(__ctx);
361 BIO* bio = BIO_new_socket(__handle, BIO_NOCLOSE);
362
363 SSL_set_bio(__ssl, bio, bio);
364
365 if (SSL_connect(__ssl) < 0)
366 throw new IOException(toString(), new SSLException());
367
368#elif __DCL_USE_SCHANNEL
369 DWORD fContextReq = ISC_REQ_SEQUENCE_DETECT |
370 ISC_REQ_REPLAY_DETECT |
371 ISC_REQ_CONFIDENTIALITY |
372 ISC_RET_EXTENDED_ERROR |
373 ISC_REQ_ALLOCATE_MEMORY |
374 ISC_REQ_STREAM;
375
376 SecBufferDesc outBufferDesc;
377 SecBuffer outBuffers[1];
378
379 outBuffers[0].BufferType = SECBUFFER_TOKEN;
380 outBuffers[0].cbBuffer = 0;
381 outBuffers[0].pvBuffer = NULL;
382 outBufferDesc.ulVersion = SECBUFFER_VERSION;
383 outBufferDesc.cBuffers = 1;
384 outBufferDesc.pBuffers = outBuffers;
385
386 CtxtHandle ctxt;
387 ULONG ctxtAttr;
388 TimeStamp tsExpiry;
389
390 SECURITY_STATUS ss = InitializeSecurityContextW(
391 &__cred, // __in PCredHandle phCredential,
392 NULL, // __in_out PCtxtHandle phContext,
393 NULL, // __in SEC_CHAR* pszTargetName,
394 fContextReq, // __in ULONG fContextReq,
395 0, // ULONG Reserved1,
396 0, // __in ULONG TargetDataRep,
397 NULL, // __in_out PSecBufferDesc pInput,
398 0, // ULONG Reserved2,
399 &ctxt, // __in_out PCtxtHandle phNewContext,
400 &outBufferDesc, // __out PSecBufferDesc pOutput,
401 &ctxtAttr, // __out PULONG pfContextAttr,
402 &tsExpiry // __out PTimeStamp ptsExpiry
403 );
404
405 if (FAILED(ss))
406 throw new IOException(toString(), new SSLException(ss));
407
408 __DCL_TRACE1(__T("%ls\n"), __GetStatusMessage(ss).data());
409
410 if (outBuffers[0].cbBuffer != 0 && outBuffers[0].pvBuffer != NULL) {
411 __DCL_TRACE3(__T("%d, %d, [%ls]\n"),
412 outBuffers[0].BufferType,
413 outBuffers[0].cbBuffer,
414 String::tryString((const char*) outBuffers[0].pvBuffer,
415 outBuffers[0].cbBuffer, 8).data()
416 );
417 int n = ::send((UINT_PTR) __handle,
418 (const char*) outBuffers[0].pvBuffer, outBuffers[0].cbBuffer, 0);
419 if (n == SOCKET_ERROR || n == 0) {
420 FreeContextBuffer(outBuffers[0].pvBuffer);
421 DeleteSecurityContext(&ctxt);
422 throw new IOException(toString(), WSAGetLastError());
423 }
424
425 __DCL_TRACE1(__T("[%d] bytes of Handshake data sent\n"), n);
426 FreeContextBuffer(outBuffers[0].pvBuffer);
427 outBuffers[0].pvBuffer = NULL;
428 }
429
430 // Handshake
431
432 SecBufferDesc inBufferDesc;
433 SecBuffer inBuffers[2];
434
435 DWORD WSAError = 0;
436#define READ_BUFFER_SIZE 0x10000
437 char* readBuffer = (char*) malloc(READ_BUFFER_SIZE);
438 bool fDoRead = true;
439 unsigned int nRead = 0;
440
441 while (ss == SEC_I_CONTINUE_NEEDED ||
442 ss == SEC_E_INCOMPLETE_MESSAGE ||
443 ss == SEC_I_INCOMPLETE_CREDENTIALS) {
444 if (0 == nRead || ss == SEC_E_INCOMPLETE_MESSAGE) {
445 if (fDoRead) {
446 int n = ::recv(
447 (UINT_PTR) __handle,
448 readBuffer + nRead,
449 READ_BUFFER_SIZE - nRead,
450 0
451 );
452 if (n == SOCKET_ERROR) {
453 WSAError = WSAGetLastError();
454 ss = SEC_E_INTERNAL_ERROR;
455 break;
456 }
457 else if (n == 0) {
458 WSAError = WSAECONNRESET;
459 ss = SEC_E_INTERNAL_ERROR;
460 break;
461 }
462 __DCL_TRACE2(__T("Handshake read [%d] [%ls]\n"), n,
463 String::tryString((const char*) readBuffer + nRead, n, 8).data());
464
465 nRead += n;
466 }
467 else
468 fDoRead = true;
469 }
470
471 inBuffers[0].BufferType = SECBUFFER_TOKEN;
472 inBuffers[0].cbBuffer = nRead;
473 inBuffers[0].pvBuffer = readBuffer;
474
475 inBuffers[1].BufferType = SECBUFFER_EMPTY;
476 inBuffers[1].cbBuffer = 0;
477 inBuffers[1].pvBuffer = NULL;
478
479 inBufferDesc.ulVersion = SECBUFFER_VERSION;
480 inBufferDesc.cBuffers = 2;
481 inBufferDesc.pBuffers = inBuffers;
482
483 outBuffers[0].BufferType = SECBUFFER_TOKEN;
484 outBuffers[0].cbBuffer = 0;
485 outBuffers[0].pvBuffer = NULL;
486
487 outBufferDesc.ulVersion = SECBUFFER_VERSION;
488 outBufferDesc.cBuffers = 1;
489 outBufferDesc.pBuffers = outBuffers;
490
491 ss = InitializeSecurityContextW(
492 &__cred,
493 &ctxt,
494 NULL,
495 fContextReq,
496 0,
497 SECURITY_NATIVE_DREP,
498 &inBufferDesc,
499 0,
500 NULL,
501 &outBufferDesc,
502 &ctxtAttr,
503 &tsExpiry
504 );
505
506 if (ss == SEC_E_OK ||
507 ss == SEC_I_CONTINUE_NEEDED ||
508 FAILED(ss) && (ctxtAttr & ISC_RET_EXTENDED_ERROR)) {
509 if (outBuffers[0].cbBuffer != 0 && outBuffers[0].pvBuffer != NULL) {
510 int n = ::send(
511 (UINT_PTR) __handle,
512 (const char*) outBuffers[0].pvBuffer,
513 outBuffers[0].cbBuffer,
514 0
515 );
516 if (n == SOCKET_ERROR || n == 0) {
517 WSAError = WSAGetLastError();
518 FreeContextBuffer(outBuffers[0].pvBuffer);
519 DeleteSecurityContext(&ctxt);
520 ss = SEC_E_INTERNAL_ERROR;
521 break;
522 }
523
524 __DCL_TRACE1(__T("[%d] bytes of Handshake data sent\n"), n);
525 FreeContextBuffer(outBuffers[0].pvBuffer);
526 outBuffers[0].pvBuffer = NULL;
527 }
528 }
529
530 if (ss == SEC_E_INCOMPLETE_MESSAGE) {
531 __DCL_TRACE0(__T("====================== SEC_E_INCOMPLETE_MESSAGE =====================\n"));
532 continue;
533 }
534
535 __DCL_TRACE1(__T("Before OK[%u]\n"), ss);
536 if (ss == SEC_E_OK) {
537 __DCL_TRACE0(__T("Handshake was successful\n"));
538
539 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
540 __DCL_TRACE1(__T("Extad data [%d] bytes\n"), inBuffers[1].cbBuffer);
541 }
542
543 break;
544 }
545
546 __DCL_TRACE2(__T("[%u][%ls]\n"), ss, __GetStatusMessage(ss).data());
547
548 if(ss == SEC_I_INCOMPLETE_CREDENTIALS) {
549 __DCL_TRACE0(__T("SEC_I_INCOMPLETE_CREDENTIALS\n"));
550
551 // Get New client Credentials
552
553 break;
554
555 fDoRead = false;
556 ss = SEC_I_CONTINUE_NEEDED;
557 continue;
558 }
559
560 if (inBuffers[1].BufferType == SECBUFFER_EXTRA) {
561 __DCL_TRACE1(__T("Extad data [%d] bytes\n"), inBuffers[1].cbBuffer);
562 memcpy(readBuffer,
563 readBuffer + (nRead - inBuffers[1].cbBuffer),
564 inBuffers[1].cbBuffer
565 );
566 nRead = inBuffers[1].cbBuffer;
567 }
568 else
569 nRead = 0;
570 }
571
572 free(readBuffer);
573
574 if (FAILED(ss)) {
575 DeleteSecurityContext(&ctxt);
576 }
577 else
578 __ctxt = ctxt;
579
580#endif
581}
#define __DCL_TRACE0(psz)
Definition Object.h:375
#define __DCL_TRACE3(fmt, arg1, arg2, arg3)
Definition Object.h:378
#define __DCL_TRACE2(fmt, arg1, arg2)
Definition Object.h:377
void CharsetConvertException *size_t n
Definition SQLField.cpp:253
HandleType __handle
Definition File.h:251
virtual String toString() const
virtual size_t send(const void *_buf, size_t _n, int _flags=0) __DCL_THROWS1(IOException *)
virtual size_t recv(void *_buf, size_t _n, int _flags=0) __DCL_THROWS1(IOException *)

◆ construct()

void SSLSocket::construct ( )
protected

Definition at line 219 of file SSLSocket.cpp.

221{
222#if __DCL_USE_OPENSSL
223 Thread::once(__opensslOnceControl, __opensslLibraryInit);
224 __ctx = NULL;
225 __ssl = NULL;
226 SSL_CTX* ctx = SSL_CTX_new(SSLv23_method());
227 if (ctx == NULL)
228 throw new SSLException();
229 __ctx = ctx;
230
231#elif __DCL_USE_SCHANNEL
232 SecInvalidateHandle(&__cred);
233 SecInvalidateHandle(&__ctxt);
234
235 CredHandle cred;
236 SCHANNEL_CRED credData;
237 TimeStamp tsExpiry;
238
239 ZeroMemory(&credData, sizeof(credData));
240 credData.dwVersion = SCHANNEL_CRED_VERSION;
241 // Specify the TLS V1.0 (client-side) security protocol.
242 // credData.grbitEnabledProtocols = SP_PROT_TLS1_CLIENT;
243
244 credData.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
245 credData.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
246
247 SECURITY_STATUS ss = AcquireCredentialsHandleW(
248 NULL, // __in SEC_CHAR* pszPrincipal, default principal
249 UNISP_NAME_W, // __in SEC_CHAR* pszPackage, for Schannel
250 SECPKG_CRED_OUTBOUND, // __in ULONG fCredentialUse,
251 NULL, // __in PLUID pvLogonID, use the current LOGON id
252 &credData, // __in PVOID pAuthData, protocol-specific data
253 NULL, // __in SEC_GET_KEY_FN pGetKeyFn, default
254 NULL, // __in PVOID pvGetKeyArgument, default
255 &cred, // __out PCredHandle phCredential,
256 &tsExpiry // __out PTimeStamp ptsExpiry
257 );
258 if (ss != SEC_E_OK)
259 throw new SSLException(ss);
260
261 __cred = cred;
262#endif
263}

◆ getPeerCertificateCommonName()

String SSLSocket::getPeerCertificateCommonName ( ) const

Definition at line 661 of file SSLSocket.cpp.

662{
663 String s;
664
665#if __DCL_USE_OPENSSL
666 __DCL_ASSERT_HANDLE(__ctx != NULL);
667 __DCL_ASSERT_HANDLE(__ssl != NULL);
668
669 char peer_CN[512];
670
671 X509* peer = SSL_get_peer_certificate(__ssl);
672 if (peer) {
673 int r = X509_NAME_get_text_by_NID(
674 X509_get_subject_name(peer),
675 NID_commonName,
676 peer_CN,
677 sizeof(peer_CN)
678 );
679
680 if (r > 0) {
681 LocaleDecoder decoder;
682 s = decoder.decode(peer_CN);
683 }
684 }
685
686#endif
687 return s;
688}
ByteString r

◆ isPeerCertificateVerified()

bool SSLSocket::isPeerCertificateVerified ( ) const

Definition at line 650 of file SSLSocket.cpp.

651{
652#if __DCL_USE_OPENSSL
653 __DCL_ASSERT_HANDLE(__ctx != NULL);
654 __DCL_ASSERT_HANDLE(__ssl != NULL);
655
656 return SSL_get_verify_result(__ssl) !=X509_V_OK;
657#endif
658 return false;
659}

◆ recv()

size_t SSLSocket::recv ( void * _buf,
size_t _n,
int _flags = 0 )
virtual
Returns
Non-Blocking 상태에서 0을 반환할 수 있다. 이 경우 다시 시도해야 한다.

Reimplemented from Socket.

Definition at line 613 of file SSLSocket.cpp.

615{
616#if __DCL_USE_OPENSSL
617 __DCL_ASSERT_HANDLE(__ctx != NULL);
618 __DCL_ASSERT_HANDLE(__ssl != NULL);
619
620 __DCL_TRACE2(__T("SSLSocket::recv(%p, %zd)\n"), _buf, _n);
621
622 __DCL_TRACE2(__T("before avail[%zd], pending[%d]\n"),
623 Socket::available(), SSL_pending(__ssl));
624 int n = (int) _n;
625 int r = SSL_read(__ssl, _buf, n);
626 __DCL_TRACE1(__T("SSLSocket::SSL_read(%d)\n"), r);
627 __DCL_TRACE2(__T("after avail[%zd], pending[%d]\n"),
628 Socket::available(), SSL_pending(__ssl));
629 if (r > 0)
630 return (size_t) r;
631
632 switch (SSL_get_error(__ssl, r)) {
633 case SSL_ERROR_ZERO_RETURN:
634 __DCL_TRACE0(__T("SSL error zero return\n"));
635 // ssl close notify, and send close notify
636 SSL_shutdown(__ssl);
637 break;
638 case SSL_ERROR_SYSCALL:
639 __DCL_TRACE0(__T("SSL Error: Premature close\n"));
640 break;
641 default:
642 throw new IOException(toString(), new SSLException());
643 }
644#endif
645 // DWORD dw = SCHANNEL_SHUTDOWN;
646
647 return 0;
648}
virtual size_t available() const __DCL_THROWS1(IOException *)
Definition File.cpp:401

◆ send()

size_t SSLSocket::send ( const void * _buf,
size_t _n,
int _flags = 0 )
virtual
Returns
Non-Blocking 상태에서 0을 반환할 수 있다. 이 경우 다시 시도해야 한다.

Reimplemented from Socket.

Definition at line 583 of file SSLSocket.cpp.

585{
586#if __DCL_USE_OPENSSL
587 __DCL_ASSERT_HANDLE(__ctx != NULL);
588 __DCL_ASSERT_HANDLE(__ssl != NULL);
589
590 __DCL_TRACE2(__T("SSLSocket::send(%p, %zd)\n"), _buf, _n);
591
592 int n = (int) _n;
593 int r = SSL_write(__ssl, _buf, (int) _n);
594
595 __DCL_TRACE1(__T("SSLSocket::SSL_write(%d)\n"),r);
596
597 if (r > 0)
598 return (size_t) r;
599
600 switch(SSL_get_error(__ssl, r)) {
601 case SSL_ERROR_NONE:
602 if(n != r)
603 __DCL_TRACE0(__T("Incomplete write!\n"));
604 break;
605 default:
606 throw new IOException(toString(), new SSLException());
607 }
608#endif
609
610 return 0;
611}

The documentation for this class was generated from the following files: