blob: af56f9d28d16427e4500d0c1742fd7853d6ffe68 [file] [log] [blame]
Christian Heimesc7f70692019-05-31 11:44:05 +02001/* Debug helpers */
2
Christian Heimese35d1ba2019-06-03 20:40:15 +02003#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
Christian Heimesc7f70692019-05-31 11:44:05 +020010static void
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) {
Christian Heimes77cde502021-03-21 16:13:09 +010026 PyGILState_Release(threadstate);
Christian Heimesc7f70692019-05-31 11:44:05 +020027 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;
Christian Heimese35d1ba2019-06-03 20:40:15 +020052#ifdef SSL3_RT_HEADER
Christian Heimesc7f70692019-05-31 11:44:05 +020053 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;
Christian Heimese35d1ba2019-06-03 20:40:15 +020058#endif
Christian Heimesc7f70692019-05-31 11:44:05 +020059#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
87static PyObject *
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
97static int
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#ifdef HAVE_OPENSSL_KEYLOG
118
119static void
120_PySSL_keylog_callback(const SSL *ssl, const char *line)
121{
122 PyGILState_STATE threadstate;
123 PySSLSocket *ssl_obj = NULL; /* ssl._SSLSocket, borrowed ref */
124 int res, e;
125 static PyThread_type_lock *lock = NULL;
126
127 threadstate = PyGILState_Ensure();
128
Gregory P. Smitheb0d5c32020-06-20 12:15:03 -0700129 ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl);
130 assert(PySSLSocket_Check(ssl_obj));
131 if (ssl_obj->ctx->keylog_bio == NULL) {
132 return;
133 }
134
Christian Heimesc7f70692019-05-31 11:44:05 +0200135 /* Allocate a static lock to synchronize writes to keylog file.
136 * The lock is neither released on exit nor on fork(). The lock is
137 * also shared between all SSLContexts although contexts may write to
138 * their own files. IMHO that's good enough for a non-performance
139 * critical debug helper.
140 */
141 if (lock == NULL) {
142 lock = PyThread_allocate_lock();
143 if (lock == NULL) {
144 PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
145 PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value,
146 &ssl_obj->exc_tb);
147 return;
148 }
149 }
150
Christian Heimesc7f70692019-05-31 11:44:05 +0200151 PySSL_BEGIN_ALLOW_THREADS
152 PyThread_acquire_lock(lock, 1);
153 res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line);
154 e = errno;
155 (void)BIO_flush(ssl_obj->ctx->keylog_bio);
156 PyThread_release_lock(lock);
157 PySSL_END_ALLOW_THREADS
158
159 if (res == -1) {
160 errno = e;
161 PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError,
162 ssl_obj->ctx->keylog_filename);
163 PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb);
164 }
165 PyGILState_Release(threadstate);
166}
167
168static PyObject *
169_PySSLContext_get_keylog_filename(PySSLContext *self, void *c) {
170 if (self->keylog_filename != NULL) {
171 Py_INCREF(self->keylog_filename);
172 return self->keylog_filename;
173 } else {
174 Py_RETURN_NONE;
175 }
176}
177
178static int
179_PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) {
180 FILE *fp;
181 /* Reset variables and callback first */
182 SSL_CTX_set_keylog_callback(self->ctx, NULL);
183 Py_CLEAR(self->keylog_filename);
184 if (self->keylog_bio != NULL) {
185 BIO *bio = self->keylog_bio;
186 self->keylog_bio = NULL;
187 PySSL_BEGIN_ALLOW_THREADS
188 BIO_free_all(bio);
189 PySSL_END_ALLOW_THREADS
190 }
191
192 if (arg == Py_None) {
193 /* None disables the callback */
194 return 0;
195 }
196
197 /* _Py_fopen_obj() also checks that arg is of proper type. */
198 fp = _Py_fopen_obj(arg, "a" PY_STDIOTEXTMODE);
199 if (fp == NULL)
200 return -1;
201
202 self->keylog_bio = BIO_new_fp(fp, BIO_CLOSE | BIO_FP_TEXT);
203 if (self->keylog_bio == NULL) {
204 PyErr_SetString(PySSLErrorObject,
205 "Can't malloc memory for keylog file");
206 return -1;
207 }
208 Py_INCREF(arg);
209 self->keylog_filename = arg;
210
211 /* Write a header for seekable, empty files (this excludes pipes). */
212 PySSL_BEGIN_ALLOW_THREADS
213 if (BIO_tell(self->keylog_bio) == 0) {
214 BIO_puts(self->keylog_bio,
215 "# TLS secrets log file, generated by OpenSSL / Python\n");
216 (void)BIO_flush(self->keylog_bio);
217 }
218 PySSL_END_ALLOW_THREADS
219 SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback);
220 return 0;
221}
222
Christian Heimese35d1ba2019-06-03 20:40:15 +0200223#endif