1818
1919#ifdef WITH_THREAD
2020#include "pythread.h"
21+ #define PySSL_BEGIN_ALLOW_THREADS_S (save ) \
22+ do { if (_ssl_locks_count>0) { (save) = PyEval_SaveThread(); } } while (0)
23+ #define PySSL_END_ALLOW_THREADS_S (save ) \
24+ do { if (_ssl_locks_count>0) { PyEval_RestoreThread(save); } } while (0)
2125#define PySSL_BEGIN_ALLOW_THREADS { \
2226 PyThreadState *_save = NULL; \
23- if (_ssl_locks_count>0) {_save = PyEval_SaveThread();}
24- #define PySSL_BLOCK_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save)};
25- #define PySSL_UNBLOCK_THREADS if (_ssl_locks_count>0){_save = PyEval_SaveThread()};
26- #define PySSL_END_ALLOW_THREADS if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \
27- }
27+ PySSL_BEGIN_ALLOW_THREADS_S(_save);
28+ #define PySSL_BLOCK_THREADS PySSL_END_ALLOW_THREADS_S(_save);
29+ #define PySSL_UNBLOCK_THREADS PySSL_BEGIN_ALLOW_THREADS_S(_save);
30+ #define PySSL_END_ALLOW_THREADS PySSL_END_ALLOW_THREADS_S(_save); }
2831
2932#else /* no WITH_THREAD */
3033
34+ #define PySSL_BEGIN_ALLOW_THREADS_S (save )
35+ #define PySSL_END_ALLOW_THREADS_S (save )
3136#define PySSL_BEGIN_ALLOW_THREADS
3237#define PySSL_BLOCK_THREADS
3338#define PySSL_UNBLOCK_THREADS
@@ -1635,19 +1640,118 @@ set_options(PySSLContext *self, PyObject *arg, void *c)
16351640 return 0 ;
16361641}
16371642
1643+ typedef struct {
1644+ PyThreadState * thread_state ;
1645+ PyObject * callable ;
1646+ char * password ;
1647+ Py_ssize_t size ;
1648+ int error ;
1649+ } _PySSLPasswordInfo ;
1650+
1651+ static int
1652+ _pwinfo_set (_PySSLPasswordInfo * pw_info , PyObject * password ,
1653+ const char * bad_type_error )
1654+ {
1655+ /* Set the password and size fields of a _PySSLPasswordInfo struct
1656+ from a unicode, bytes, or byte array object.
1657+ The password field will be dynamically allocated and must be freed
1658+ by the caller */
1659+ PyObject * password_bytes = NULL ;
1660+ const char * data = NULL ;
1661+ Py_ssize_t size ;
1662+
1663+ if (PyUnicode_Check (password )) {
1664+ password_bytes = PyUnicode_AsEncodedString (password , NULL , NULL );
1665+ if (!password_bytes ) {
1666+ goto error ;
1667+ }
1668+ data = PyBytes_AS_STRING (password_bytes );
1669+ size = PyBytes_GET_SIZE (password_bytes );
1670+ } else if (PyBytes_Check (password )) {
1671+ data = PyBytes_AS_STRING (password );
1672+ size = PyBytes_GET_SIZE (password );
1673+ } else if (PyByteArray_Check (password )) {
1674+ data = PyByteArray_AS_STRING (password );
1675+ size = PyByteArray_GET_SIZE (password );
1676+ } else {
1677+ PyErr_SetString (PyExc_TypeError , bad_type_error );
1678+ goto error ;
1679+ }
1680+
1681+ free (pw_info -> password );
1682+ pw_info -> password = malloc (size );
1683+ if (!pw_info -> password ) {
1684+ PyErr_SetString (PyExc_MemoryError ,
1685+ "unable to allocate password buffer" );
1686+ goto error ;
1687+ }
1688+ memcpy (pw_info -> password , data , size );
1689+ pw_info -> size = size ;
1690+
1691+ Py_XDECREF (password_bytes );
1692+ return 1 ;
1693+
1694+ error :
1695+ Py_XDECREF (password_bytes );
1696+ return 0 ;
1697+ }
1698+
1699+ static int
1700+ _password_callback (char * buf , int size , int rwflag , void * userdata )
1701+ {
1702+ _PySSLPasswordInfo * pw_info = (_PySSLPasswordInfo * ) userdata ;
1703+ PyObject * fn_ret = NULL ;
1704+
1705+ PySSL_END_ALLOW_THREADS_S (pw_info -> thread_state );
1706+
1707+ if (pw_info -> callable ) {
1708+ fn_ret = PyObject_CallFunctionObjArgs (pw_info -> callable , NULL );
1709+ if (!fn_ret ) {
1710+ /* TODO: It would be nice to move _ctypes_add_traceback() into the
1711+ core python API, so we could use it to add a frame here */
1712+ goto error ;
1713+ }
1714+
1715+ if (!_pwinfo_set (pw_info , fn_ret ,
1716+ "password callback must return a string" )) {
1717+ goto error ;
1718+ }
1719+ Py_CLEAR (fn_ret );
1720+ }
1721+
1722+ if (pw_info -> size > size ) {
1723+ PyErr_Format (PyExc_ValueError ,
1724+ "password cannot be longer than %d bytes" , size );
1725+ goto error ;
1726+ }
1727+
1728+ PySSL_BEGIN_ALLOW_THREADS_S (pw_info -> thread_state );
1729+ memcpy (buf , pw_info -> password , pw_info -> size );
1730+ return pw_info -> size ;
1731+
1732+ error :
1733+ Py_XDECREF (fn_ret );
1734+ PySSL_BEGIN_ALLOW_THREADS_S (pw_info -> thread_state );
1735+ pw_info -> error = 1 ;
1736+ return -1 ;
1737+ }
1738+
16381739static PyObject *
16391740load_cert_chain (PySSLContext * self , PyObject * args , PyObject * kwds )
16401741{
1641- char * kwlist [] = {"certfile" , "keyfile" , NULL };
1642- PyObject * certfile , * keyfile = NULL ;
1742+ char * kwlist [] = {"certfile" , "keyfile" , "password" , NULL };
1743+ PyObject * certfile , * keyfile = NULL , * password = NULL ;
16431744 PyObject * certfile_bytes = NULL , * keyfile_bytes = NULL ;
1745+ pem_password_cb * orig_passwd_cb = self -> ctx -> default_passwd_callback ;
1746+ void * orig_passwd_userdata = self -> ctx -> default_passwd_callback_userdata ;
1747+ _PySSLPasswordInfo pw_info = { NULL , NULL , NULL , 0 , 0 };
16441748 int r ;
16451749
16461750 errno = 0 ;
16471751 ERR_clear_error ();
16481752 if (!PyArg_ParseTupleAndKeywords (args , kwds ,
1649- "O|O :load_cert_chain" , kwlist ,
1650- & certfile , & keyfile ))
1753+ "O|OO :load_cert_chain" , kwlist ,
1754+ & certfile , & keyfile , & password ))
16511755 return NULL ;
16521756 if (keyfile == Py_None )
16531757 keyfile = NULL ;
@@ -1661,12 +1765,26 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
16611765 "keyfile should be a valid filesystem path" );
16621766 goto error ;
16631767 }
1664- PySSL_BEGIN_ALLOW_THREADS
1768+ if (password && password != Py_None ) {
1769+ if (PyCallable_Check (password )) {
1770+ pw_info .callable = password ;
1771+ } else if (!_pwinfo_set (& pw_info , password ,
1772+ "password should be a string or callable" )) {
1773+ goto error ;
1774+ }
1775+ SSL_CTX_set_default_passwd_cb (self -> ctx , _password_callback );
1776+ SSL_CTX_set_default_passwd_cb_userdata (self -> ctx , & pw_info );
1777+ }
1778+ PySSL_BEGIN_ALLOW_THREADS_S (pw_info .thread_state );
16651779 r = SSL_CTX_use_certificate_chain_file (self -> ctx ,
16661780 PyBytes_AS_STRING (certfile_bytes ));
1667- PySSL_END_ALLOW_THREADS
1781+ PySSL_END_ALLOW_THREADS_S ( pw_info . thread_state );
16681782 if (r != 1 ) {
1669- if (errno != 0 ) {
1783+ if (pw_info .error ) {
1784+ ERR_clear_error ();
1785+ /* the password callback has already set the error information */
1786+ }
1787+ else if (errno != 0 ) {
16701788 ERR_clear_error ();
16711789 PyErr_SetFromErrno (PyExc_IOError );
16721790 }
@@ -1675,33 +1793,43 @@ load_cert_chain(PySSLContext *self, PyObject *args, PyObject *kwds)
16751793 }
16761794 goto error ;
16771795 }
1678- PySSL_BEGIN_ALLOW_THREADS
1796+ PySSL_BEGIN_ALLOW_THREADS_S ( pw_info . thread_state );
16791797 r = SSL_CTX_use_PrivateKey_file (self -> ctx ,
16801798 PyBytes_AS_STRING (keyfile ? keyfile_bytes : certfile_bytes ),
16811799 SSL_FILETYPE_PEM );
1682- PySSL_END_ALLOW_THREADS
1683- Py_XDECREF (keyfile_bytes );
1684- Py_XDECREF (certfile_bytes );
1800+ PySSL_END_ALLOW_THREADS_S ( pw_info . thread_state );
1801+ Py_CLEAR (keyfile_bytes );
1802+ Py_CLEAR (certfile_bytes );
16851803 if (r != 1 ) {
1686- if (errno != 0 ) {
1804+ if (pw_info .error ) {
1805+ ERR_clear_error ();
1806+ /* the password callback has already set the error information */
1807+ }
1808+ else if (errno != 0 ) {
16871809 ERR_clear_error ();
16881810 PyErr_SetFromErrno (PyExc_IOError );
16891811 }
16901812 else {
16911813 _setSSLError (NULL , 0 , __FILE__ , __LINE__ );
16921814 }
1693- return NULL ;
1815+ goto error ;
16941816 }
1695- PySSL_BEGIN_ALLOW_THREADS
1817+ PySSL_BEGIN_ALLOW_THREADS_S ( pw_info . thread_state );
16961818 r = SSL_CTX_check_private_key (self -> ctx );
1697- PySSL_END_ALLOW_THREADS
1819+ PySSL_END_ALLOW_THREADS_S ( pw_info . thread_state );
16981820 if (r != 1 ) {
16991821 _setSSLError (NULL , 0 , __FILE__ , __LINE__ );
1700- return NULL ;
1822+ goto error ;
17011823 }
1824+ SSL_CTX_set_default_passwd_cb (self -> ctx , orig_passwd_cb );
1825+ SSL_CTX_set_default_passwd_cb_userdata (self -> ctx , orig_passwd_userdata );
1826+ free (pw_info .password );
17021827 Py_RETURN_NONE ;
17031828
17041829error :
1830+ SSL_CTX_set_default_passwd_cb (self -> ctx , orig_passwd_cb );
1831+ SSL_CTX_set_default_passwd_cb_userdata (self -> ctx , orig_passwd_userdata );
1832+ free (pw_info .password );
17051833 Py_XDECREF (keyfile_bytes );
17061834 Py_XDECREF (certfile_bytes );
17071835 return NULL ;
0 commit comments