• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Debug helpers */
2 
3 #ifndef SSL3_MT_CHANGE_CIPHER_SPEC
4 /* Dummy message type for handling CCS like a normal handshake message
5  * not defined in OpenSSL 1.0.2
6  */
7 #define SSL3_MT_CHANGE_CIPHER_SPEC              0x0101
8 #endif
9 
10 static void
_PySSL_msg_callback(int write_p,int version,int content_type,const void * buf,size_t len,SSL * ssl,void * arg)11 _PySSL_msg_callback(int write_p, int version, int content_type,
12                     const void *buf, size_t len, SSL *ssl, void *arg)
13 {
14     const char *cbuf = (const char *)buf;
15     PyGILState_STATE threadstate;
16     PyObject *res = NULL;
17     PySSLSocket *ssl_obj = NULL;  /* ssl._SSLSocket, borrowed ref */
18     PyObject *ssl_socket = NULL;  /* ssl.SSLSocket or ssl.SSLObject */
19     int msg_type;
20 
21     threadstate = PyGILState_Ensure();
22 
23     ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl);
24     assert(Py_IS_TYPE(ssl_obj, get_state_sock(ssl_obj)->PySSLSocket_Type));
25     if (ssl_obj->ctx->msg_cb == NULL) {
26         PyGILState_Release(threadstate);
27         return;
28     }
29 
30     if (ssl_obj->owner)
31         ssl_socket = PyWeakref_GetObject(ssl_obj->owner);
32     else if (ssl_obj->Socket)
33         ssl_socket = PyWeakref_GetObject(ssl_obj->Socket);
34     else
35         ssl_socket = (PyObject *)ssl_obj;
36     Py_INCREF(ssl_socket);
37 
38     /* assume that OpenSSL verifies all payload and buf len is of sufficient
39        length */
40     switch(content_type) {
41       case SSL3_RT_CHANGE_CIPHER_SPEC:
42         msg_type = SSL3_MT_CHANGE_CIPHER_SPEC;
43         break;
44       case SSL3_RT_ALERT:
45         /* byte 0: level */
46         /* byte 1: alert type */
47         msg_type = (int)cbuf[1];
48         break;
49       case SSL3_RT_HANDSHAKE:
50         msg_type = (int)cbuf[0];
51         break;
52 #ifdef SSL3_RT_HEADER
53       case SSL3_RT_HEADER:
54         /* frame header encodes version in bytes 1..2 */
55         version = cbuf[1] << 8 | cbuf[2];
56         msg_type = (int)cbuf[0];
57         break;
58 #endif
59 #ifdef SSL3_RT_INNER_CONTENT_TYPE
60       case SSL3_RT_INNER_CONTENT_TYPE:
61         msg_type = (int)cbuf[0];
62         break;
63 #endif
64       default:
65         /* never SSL3_RT_APPLICATION_DATA */
66         msg_type = -1;
67         break;
68     }
69 
70     res = PyObject_CallFunction(
71         ssl_obj->ctx->msg_cb, "Osiiiy#",
72         ssl_socket, write_p ? "write" : "read",
73         version, content_type, msg_type,
74         buf, len
75     );
76     if (res == NULL) {
77         PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb);
78     } else {
79         Py_DECREF(res);
80     }
81     Py_XDECREF(ssl_socket);
82 
83     PyGILState_Release(threadstate);
84 }
85 
86 
87 static PyObject *
_PySSLContext_get_msg_callback(PySSLContext * self,void * c)88 _PySSLContext_get_msg_callback(PySSLContext *self, void *c) {
89     if (self->msg_cb != NULL) {
90         Py_INCREF(self->msg_cb);
91         return self->msg_cb;
92     } else {
93         Py_RETURN_NONE;
94     }
95 }
96 
97 static int
_PySSLContext_set_msg_callback(PySSLContext * self,PyObject * arg,void * c)98 _PySSLContext_set_msg_callback(PySSLContext *self, PyObject *arg, void *c) {
99     Py_CLEAR(self->msg_cb);
100     if (arg == Py_None) {
101         SSL_CTX_set_msg_callback(self->ctx, NULL);
102     }
103     else {
104         if (!PyCallable_Check(arg)) {
105             SSL_CTX_set_msg_callback(self->ctx, NULL);
106             PyErr_SetString(PyExc_TypeError,
107                             "not a callable object");
108             return -1;
109         }
110         Py_INCREF(arg);
111         self->msg_cb = arg;
112         SSL_CTX_set_msg_callback(self->ctx, _PySSL_msg_callback);
113     }
114     return 0;
115 }
116 
117 static void
_PySSL_keylog_callback(const SSL * ssl,const char * line)118 _PySSL_keylog_callback(const SSL *ssl, const char *line)
119 {
120     PyGILState_STATE threadstate;
121     PySSLSocket *ssl_obj = NULL;  /* ssl._SSLSocket, borrowed ref */
122     int res, e;
123     static PyThread_type_lock *lock = NULL;
124 
125     threadstate = PyGILState_Ensure();
126 
127     ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl);
128     assert(Py_IS_TYPE(ssl_obj, get_state_sock(ssl_obj)->PySSLSocket_Type));
129     if (ssl_obj->ctx->keylog_bio == NULL) {
130         return;
131     }
132 
133     /* Allocate a static lock to synchronize writes to keylog file.
134      * The lock is neither released on exit nor on fork(). The lock is
135      * also shared between all SSLContexts although contexts may write to
136      * their own files. IMHO that's good enough for a non-performance
137      * critical debug helper.
138      */
139     if (lock == NULL) {
140         lock = PyThread_allocate_lock();
141         if (lock == NULL) {
142             PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
143             PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value,
144                         &ssl_obj->exc_tb);
145             return;
146         }
147     }
148 
149     PySSL_BEGIN_ALLOW_THREADS
150     PyThread_acquire_lock(lock, 1);
151     res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line);
152     e = errno;
153     (void)BIO_flush(ssl_obj->ctx->keylog_bio);
154     PyThread_release_lock(lock);
155     PySSL_END_ALLOW_THREADS
156 
157     if (res == -1) {
158         errno = e;
159         PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError,
160                                              ssl_obj->ctx->keylog_filename);
161         PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb);
162     }
163     PyGILState_Release(threadstate);
164 }
165 
166 static PyObject *
_PySSLContext_get_keylog_filename(PySSLContext * self,void * c)167 _PySSLContext_get_keylog_filename(PySSLContext *self, void *c) {
168     if (self->keylog_filename != NULL) {
169         Py_INCREF(self->keylog_filename);
170         return self->keylog_filename;
171     } else {
172         Py_RETURN_NONE;
173     }
174 }
175 
176 static int
_PySSLContext_set_keylog_filename(PySSLContext * self,PyObject * arg,void * c)177 _PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) {
178     FILE *fp;
179     /* Reset variables and callback first */
180     SSL_CTX_set_keylog_callback(self->ctx, NULL);
181     Py_CLEAR(self->keylog_filename);
182     if (self->keylog_bio != NULL) {
183         BIO *bio = self->keylog_bio;
184         self->keylog_bio = NULL;
185         PySSL_BEGIN_ALLOW_THREADS
186         BIO_free_all(bio);
187         PySSL_END_ALLOW_THREADS
188     }
189 
190     if (arg == Py_None) {
191         /* None disables the callback */
192         return 0;
193     }
194 
195     /* _Py_fopen_obj() also checks that arg is of proper type. */
196     fp = _Py_fopen_obj(arg, "a" PY_STDIOTEXTMODE);
197     if (fp == NULL)
198         return -1;
199 
200     self->keylog_bio = BIO_new_fp(fp, BIO_CLOSE | BIO_FP_TEXT);
201     if (self->keylog_bio == NULL) {
202         PyErr_SetString(get_state_ctx(self)->PySSLErrorObject,
203                         "Can't malloc memory for keylog file");
204         return -1;
205     }
206     Py_INCREF(arg);
207     self->keylog_filename = arg;
208 
209     /* Write a header for seekable, empty files (this excludes pipes). */
210     PySSL_BEGIN_ALLOW_THREADS
211     if (BIO_tell(self->keylog_bio) == 0) {
212         BIO_puts(self->keylog_bio,
213                  "# TLS secrets log file, generated by OpenSSL / Python\n");
214         (void)BIO_flush(self->keylog_bio);
215     }
216     PySSL_END_ALLOW_THREADS
217     SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback);
218     return 0;
219 }
220