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