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
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 ssl_obj->exc = PyErr_GetRaisedException();
78 } else {
79 Py_DECREF(res);
80 }
81 Py_XDECREF(ssl_socket);
82
83 PyGILState_Release(threadstate);
84 }
85
86
87 static PyObject *
88 _PySSLContext_get_msg_callback(PySSLContext *self, void *c) {
89 if (self->msg_cb != NULL) {
90 return Py_NewRef(self->msg_cb);
91 } else {
92 Py_RETURN_NONE;
93 }
94 }
95
96 static int
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 self->msg_cb = Py_NewRef(arg);
110 SSL_CTX_set_msg_callback(self->ctx, _PySSL_msg_callback);
111 }
112 return 0;
113 }
114
115 static void
116 _PySSL_keylog_callback(const SSL *ssl, const char *line)
117 {
118 PyGILState_STATE threadstate;
119 PySSLSocket *ssl_obj = NULL; /* ssl._SSLSocket, borrowed ref */
120 int res, e;
121
122 threadstate = PyGILState_Ensure();
123
124 ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl);
125 assert(Py_IS_TYPE(ssl_obj, get_state_sock(ssl_obj)->PySSLSocket_Type));
126 PyThread_type_lock lock = get_state_sock(ssl_obj)->keylog_lock;
127 assert(lock != NULL);
128 if (ssl_obj->ctx->keylog_bio == NULL) {
129 return;
130 }
131 /*
132 * The lock is neither released on exit nor on fork(). The lock is
133 * also shared between all SSLContexts although contexts may write to
134 * their own files. IMHO that's good enough for a non-performance
135 * critical debug helper.
136 */
137
138 PySSL_BEGIN_ALLOW_THREADS
139 PyThread_acquire_lock(lock, 1);
140 res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line);
141 e = errno;
142 (void)BIO_flush(ssl_obj->ctx->keylog_bio);
143 PyThread_release_lock(lock);
144 PySSL_END_ALLOW_THREADS
145
146 if (res == -1) {
147 errno = e;
148 PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError,
149 ssl_obj->ctx->keylog_filename);
150 ssl_obj->exc = PyErr_GetRaisedException();
151 }
152 PyGILState_Release(threadstate);
153 }
154
155 static PyObject *
156 _PySSLContext_get_keylog_filename(PySSLContext *self, void *c) {
157 if (self->keylog_filename != NULL) {
158 return Py_NewRef(self->keylog_filename);
159 } else {
160 Py_RETURN_NONE;
161 }
162 }
163
164 static int
165 _PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) {
166 FILE *fp;
167 /* Reset variables and callback first */
168 SSL_CTX_set_keylog_callback(self->ctx, NULL);
169 Py_CLEAR(self->keylog_filename);
170 if (self->keylog_bio != NULL) {
171 BIO *bio = self->keylog_bio;
172 self->keylog_bio = NULL;
173 PySSL_BEGIN_ALLOW_THREADS
174 BIO_free_all(bio);
175 PySSL_END_ALLOW_THREADS
176 }
177
178 if (arg == Py_None) {
179 /* None disables the callback */
180 return 0;
181 }
182
183 /* _Py_fopen_obj() also checks that arg is of proper type. */
184 fp = _Py_fopen_obj(arg, "a" PY_STDIOTEXTMODE);
185 if (fp == NULL)
186 return -1;
187
188 self->keylog_bio = BIO_new_fp(fp, BIO_CLOSE | BIO_FP_TEXT);
189 if (self->keylog_bio == NULL) {
190 PyErr_SetString(get_state_ctx(self)->PySSLErrorObject,
191 "Can't malloc memory for keylog file");
192 return -1;
193 }
194 self->keylog_filename = Py_NewRef(arg);
195
196 /* Write a header for seekable, empty files (this excludes pipes). */
197 PySSL_BEGIN_ALLOW_THREADS
198 if (BIO_tell(self->keylog_bio) == 0) {
199 BIO_puts(self->keylog_bio,
200 "# TLS secrets log file, generated by OpenSSL / Python\n");
201 (void)BIO_flush(self->keylog_bio);
202 }
203 PySSL_END_ALLOW_THREADS
204 SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback);
205 return 0;
206 }