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