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