@@ -81,7 +81,9 @@ class WolfSSL(object):
8181
8282 @classmethod
8383 def enable_debug (self ):
84- _lib .wolfSSL_Debugging_ON ()
84+ if _lib .wolfSSL_Debugging_ON () != _SSL_SUCCESS :
85+ raise RuntimeError (
86+ "wolfSSL debugging not available" )
8587
8688 @classmethod
8789 def disable_debug (self ):
@@ -143,9 +145,7 @@ def get_der(self):
143145 if derPtr == _ffi .NULL :
144146 return None
145147
146- derBytes = _ffi .buffer (derPtr , outSz [0 ])
147-
148- return derBytes
148+ return _ffi .buffer (derPtr , outSz [0 ])[:]
149149
150150class SSLContext (object ):
151151 """
@@ -154,7 +154,9 @@ class SSLContext(object):
154154 """
155155
156156 def __init__ (self , protocol , server_side = None ):
157- _lib .wolfSSL_Init ()
157+ if _lib .wolfSSL_Init () != _SSL_SUCCESS :
158+ raise RuntimeError (
159+ "wolfSSL library initialization failed" )
158160 method = _WolfSSLMethod (protocol , server_side )
159161
160162 self .protocol = protocol
@@ -356,9 +358,10 @@ def load_verify_locations(self, cafile=None, capath=None, cadata=None):
356358 raise SSLError ("Unable to load verify locations. E(%d)" % ret )
357359
358360 if cadata is not None :
361+ cadata_bytes = t2b (cadata )
359362 ret = _lib .wolfSSL_CTX_load_verify_buffer (
360- self .native_object , t2b ( cadata ) ,
361- len (cadata ), _SSL_FILETYPE_PEM )
363+ self .native_object , cadata_bytes ,
364+ len (cadata_bytes ), _SSL_FILETYPE_PEM )
362365
363366 if ret != _SSL_SUCCESS :
364367 raise SSLError ("Unable to load verify locations. E(%d)" % ret )
@@ -476,8 +479,11 @@ def __init__(self, sock=None, keyfile=None, certfile=None,
476479 ret = _lib .wolfSSL_check_domain_name (self .native_object ,
477480 sni )
478481 if ret != _SSL_SUCCESS :
479- raise SSLError ("Unable to set domain name check for "
480- "hostname verification" )
482+ self ._release_native_object ()
483+ raise SSLError (
484+ "Unable to set domain name "
485+ "check for hostname "
486+ "verification" )
481487
482488 if connected :
483489 try :
@@ -497,6 +503,7 @@ def _release_native_object(self):
497503 self .native_object = _ffi .NULL
498504
499505 def pending (self ):
506+ self ._check_closed ("pending" )
500507 return _lib .wolfSSL_pending (self .native_object )
501508
502509 @property
@@ -605,14 +612,6 @@ def sendall(self, data, flags=0):
605612
606613 while sent < length :
607614 ret = self .write (data [sent :])
608- if (ret <= 0 ):
609- #expect to receive 0 when peer is reset or closed
610- err = _lib .wolfSSL_get_error (self .native_object , 0 )
611- if err == _SSL_ERROR_WANT_WRITE :
612- raise SSLWantWriteError ()
613- else :
614- raise SSLError ("wolfSSL_write error (%d)" % err )
615-
616615 sent += ret
617616
618617 return None
@@ -676,11 +675,13 @@ def recv_into(self, buffer, nbytes=None, flags=0):
676675 self ._check_closed ("read" )
677676 if self ._context .protocol < PROTOCOL_DTLSv1 :
678677 self ._check_connected ()
678+ else :
679+ self .do_handshake ()
679680
680681 if buffer is None :
681682 raise ValueError ("buffer cannot be None" )
682683
683- if nbytes is None :
684+ if nbytes is None or nbytes == 0 :
684685 nbytes = len (buffer )
685686 else :
686687 nbytes = min (len (buffer ), nbytes )
@@ -721,7 +722,9 @@ def recvmsg_into(self, *args, **kwargs):
721722
722723 def shutdown (self , how ):
723724 if self .native_object != _ffi .NULL :
724- _lib .wolfSSL_shutdown (self .native_object )
725+ ret = _lib .wolfSSL_shutdown (self .native_object )
726+ if ret == 0 :
727+ _lib .wolfSSL_shutdown (self .native_object )
725728 self ._release_native_object ()
726729 if self ._context .protocol < PROTOCOL_DTLSv1 :
727730 self ._sock .shutdown (how )
@@ -732,10 +735,15 @@ def unwrap(self):
732735 Returns the wrapped OS socket.
733736 """
734737 if self .native_object != _ffi .NULL :
735- _lib .wolfSSL_set_fd (self .native_object , - 1 )
738+ if self ._connected :
739+ # Single-step shutdown is intentional; any
740+ # bidirectional close_notify exchange is the
741+ # caller's responsibility on the raw socket.
742+ _lib .wolfSSL_shutdown (self .native_object )
743+ self ._release_native_object ()
736744
737745 sock = socket (family = self ._sock .family ,
738- sock_type = self ._sock .type ,
746+ type = self ._sock .type ,
739747 proto = self ._sock .proto ,
740748 fileno = self ._sock .fileno ())
741749
@@ -745,14 +753,19 @@ def unwrap(self):
745753 return sock
746754
747755 def add_peer (self , addr ):
748- peerAddr = _lib .wolfSSL_dtls_create_peer (addr [1 ],t2b (addr [0 ]))
749- if peerAddr == _ffi .NULL :
750- raise SSLError ("Failed to create peer" )
751- ret = _lib .wolfSSL_dtls_set_peer (self .native_object , peerAddr ,
752- _SOCKADDR_SZ )
756+ peerAddr = _lib .wolfSSL_dtls_create_peer (addr [1 ], t2b (addr [0 ]))
757+ if peerAddr == _ffi .NULL :
758+ raise SSLError ("Failed to create peer" )
759+ try :
760+ ret = _lib .wolfSSL_dtls_set_peer (
761+ self .native_object , peerAddr ,
762+ _SOCKADDR_SZ )
753763 if ret != _SSL_SUCCESS :
754- raise SSLError ("Unable to set dtls peer. E(%d)" % ret )
755- _lib .wolfSSL_dtls_free_peer (peerAddr )
764+ raise SSLError (
765+ "Unable to set dtls peer."
766+ " E(%d)" % ret )
767+ finally :
768+ _lib .wolfSSL_dtls_free_peer (peerAddr )
756769
757770 def do_handshake (self , block = False ): # pylint: disable=unused-argument
758771 """
@@ -814,18 +827,16 @@ def _real_connect(self, addr, connect_ex):
814827 raise ValueError ("attempt to connect already-connected SSLSocket!" )
815828
816829 err = 0
817- ret = _SSL_SUCCESS
818-
830+
819831 if self ._context .protocol >= PROTOCOL_DTLSv1 :
820- self .add_peer (addr )
832+ self .add_peer (addr )
821833 else :
822834 if connect_ex :
823835 err = self ._sock .connect_ex (addr )
824836 else :
825- err = 0
826837 self ._sock .connect (addr )
827838
828- if err == 0 and ret == _SSL_SUCCESS :
839+ if err == 0 :
829840 self ._connected = True
830841 if self .do_handshake_on_connect :
831842 self .do_handshake ()
@@ -894,12 +905,22 @@ def version(self):
894905 """
895906 Returns the version of the protocol used in the connection.
896907 """
897- return _ffi .string (_lib .wolfSSL_get_version (self .native_object )).decode ("ascii" )
908+ self ._check_closed ("version" )
909+ return _ffi .string (
910+ _lib .wolfSSL_get_version (
911+ self .native_object )).decode ("ascii" )
898912
899913 # The following functions expose functionality of the underlying
900914 # Socket object. These are also exposed through Python's ssl module
901915 # API and are provided here for compatibility.
902916 def close (self ):
917+ if self .native_object != _ffi .NULL :
918+ if self ._connected :
919+ # Single-step shutdown is intentional here; the
920+ # socket is about to be closed so a bidirectional
921+ # close_notify exchange is not required.
922+ _lib .wolfSSL_shutdown (self .native_object )
923+ self ._release_native_object ()
903924 self ._sock .close ()
904925
905926 def fileno (self ):
@@ -1029,12 +1050,16 @@ def callback(self):
10291050 def _get_passwd (self , passwd , sz , rw , userdata ):
10301051 try :
10311052 result = self ._passwd_wrapper (sz , rw , userdata )
1032- if not isinstance (result , bytes ):
1033- raise ValueError ("Problem, expected String, not bytes" )
1034- if len (result ) > sz :
1035- raise ValueError ("Problem with password returned being long" )
1036- for i in range (len (result )):
1037- passwd [i ] = result [i :i + 1 ]
1038- return len (result )
1039- except Exception as e :
1040- raise ValueError ("Problem getting password from callback" )
1053+ except Exception :
1054+ raise ValueError (
1055+ "Problem getting password from callback" )
1056+ if not isinstance (result , bytes ):
1057+ raise ValueError (
1058+ "Password callback must return bytes" )
1059+ if len (result ) > sz :
1060+ raise ValueError (
1061+ "Problem with password returned"
1062+ " being long" )
1063+ for i in range (len (result )):
1064+ passwd [i ] = result [i :i + 1 ]
1065+ return len (result )
0 commit comments