| 
									
										
										
										
											2019-05-31 11:44:05 +02:00
										 |  |  | /* Debug helpers */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-03 20:40:15 +02:00
										 |  |  | #ifndef SSL3_MT_CHANGE_CIPHER_SPEC
 | 
					
						
							|  |  |  | /* Dummy message type for handling CCS like a normal handshake message
 | 
					
						
							|  |  |  |  * not defined in OpenSSL 1.0.2 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define SSL3_MT_CHANGE_CIPHER_SPEC              0x0101
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 11:44:05 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | _PySSL_msg_callback(int write_p, int version, int content_type, | 
					
						
							|  |  |  |                     const void *buf, size_t len, SSL *ssl, void *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const char *cbuf = (const char *)buf; | 
					
						
							|  |  |  |     PyGILState_STATE threadstate; | 
					
						
							|  |  |  |     PyObject *res = NULL; | 
					
						
							|  |  |  |     PySSLSocket *ssl_obj = NULL;  /* ssl._SSLSocket, borrowed ref */ | 
					
						
							|  |  |  |     PyObject *ssl_socket = NULL;  /* ssl.SSLSocket or ssl.SSLObject */ | 
					
						
							|  |  |  |     int msg_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     threadstate = PyGILState_Ensure(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl); | 
					
						
							|  |  |  |     assert(PySSLSocket_Check(ssl_obj)); | 
					
						
							|  |  |  |     if (ssl_obj->ctx->msg_cb == NULL) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (ssl_obj->owner) | 
					
						
							|  |  |  |         ssl_socket = PyWeakref_GetObject(ssl_obj->owner); | 
					
						
							|  |  |  |     else if (ssl_obj->Socket) | 
					
						
							|  |  |  |         ssl_socket = PyWeakref_GetObject(ssl_obj->Socket); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         ssl_socket = (PyObject *)ssl_obj; | 
					
						
							|  |  |  |     Py_INCREF(ssl_socket); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* assume that OpenSSL verifies all payload and buf len is of sufficient
 | 
					
						
							|  |  |  |        length */ | 
					
						
							|  |  |  |     switch(content_type) { | 
					
						
							|  |  |  |       case SSL3_RT_CHANGE_CIPHER_SPEC: | 
					
						
							|  |  |  |         msg_type = SSL3_MT_CHANGE_CIPHER_SPEC; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case SSL3_RT_ALERT: | 
					
						
							|  |  |  |         /* byte 0: level */ | 
					
						
							|  |  |  |         /* byte 1: alert type */ | 
					
						
							|  |  |  |         msg_type = (int)cbuf[1]; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       case SSL3_RT_HANDSHAKE: | 
					
						
							|  |  |  |         msg_type = (int)cbuf[0]; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2019-06-03 20:40:15 +02:00
										 |  |  | #ifdef SSL3_RT_HEADER
 | 
					
						
							| 
									
										
										
										
											2019-05-31 11:44:05 +02:00
										 |  |  |       case SSL3_RT_HEADER: | 
					
						
							|  |  |  |         /* frame header encodes version in bytes 1..2 */ | 
					
						
							|  |  |  |         version = cbuf[1] << 8 | cbuf[2]; | 
					
						
							|  |  |  |         msg_type = (int)cbuf[0]; | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2019-06-03 20:40:15 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-05-31 11:44:05 +02:00
										 |  |  | #ifdef SSL3_RT_INNER_CONTENT_TYPE
 | 
					
						
							|  |  |  |       case SSL3_RT_INNER_CONTENT_TYPE: | 
					
						
							|  |  |  |         msg_type = (int)cbuf[0]; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         /* never SSL3_RT_APPLICATION_DATA */ | 
					
						
							|  |  |  |         msg_type = -1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res = PyObject_CallFunction( | 
					
						
							|  |  |  |         ssl_obj->ctx->msg_cb, "Osiiiy#", | 
					
						
							|  |  |  |         ssl_socket, write_p ? "write" : "read", | 
					
						
							|  |  |  |         version, content_type, msg_type, | 
					
						
							|  |  |  |         buf, len | 
					
						
							|  |  |  |     ); | 
					
						
							|  |  |  |     if (res == NULL) { | 
					
						
							|  |  |  |         PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         Py_DECREF(res); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_XDECREF(ssl_socket); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PyGILState_Release(threadstate); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _PySSLContext_get_msg_callback(PySSLContext *self, void *c) { | 
					
						
							|  |  |  |     if (self->msg_cb != NULL) { | 
					
						
							|  |  |  |         Py_INCREF(self->msg_cb); | 
					
						
							|  |  |  |         return self->msg_cb; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         Py_RETURN_NONE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _PySSLContext_set_msg_callback(PySSLContext *self, PyObject *arg, void *c) { | 
					
						
							|  |  |  |     Py_CLEAR(self->msg_cb); | 
					
						
							|  |  |  |     if (arg == Py_None) { | 
					
						
							|  |  |  |         SSL_CTX_set_msg_callback(self->ctx, NULL); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         if (!PyCallable_Check(arg)) { | 
					
						
							|  |  |  |             SSL_CTX_set_msg_callback(self->ctx, NULL); | 
					
						
							|  |  |  |             PyErr_SetString(PyExc_TypeError, | 
					
						
							|  |  |  |                             "not a callable object"); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         Py_INCREF(arg); | 
					
						
							|  |  |  |         self->msg_cb = arg; | 
					
						
							|  |  |  |         SSL_CTX_set_msg_callback(self->ctx, _PySSL_msg_callback); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef HAVE_OPENSSL_KEYLOG
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | _PySSL_keylog_callback(const SSL *ssl, const char *line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyGILState_STATE threadstate; | 
					
						
							|  |  |  |     PySSLSocket *ssl_obj = NULL;  /* ssl._SSLSocket, borrowed ref */ | 
					
						
							|  |  |  |     int res, e; | 
					
						
							|  |  |  |     static PyThread_type_lock *lock = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     threadstate = PyGILState_Ensure(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-21 12:11:41 -07:00
										 |  |  |     ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl); | 
					
						
							|  |  |  |     assert(PySSLSocket_Check(ssl_obj)); | 
					
						
							|  |  |  |     if (ssl_obj->ctx->keylog_bio == NULL) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-31 11:44:05 +02:00
										 |  |  |     /* Allocate a static lock to synchronize writes to keylog file.
 | 
					
						
							|  |  |  |      * The lock is neither released on exit nor on fork(). The lock is | 
					
						
							|  |  |  |      * also shared between all SSLContexts although contexts may write to | 
					
						
							|  |  |  |      * their own files. IMHO that's good enough for a non-performance | 
					
						
							|  |  |  |      * critical debug helper. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (lock == NULL) { | 
					
						
							|  |  |  |         lock = PyThread_allocate_lock(); | 
					
						
							|  |  |  |         if (lock == NULL) { | 
					
						
							|  |  |  |             PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock"); | 
					
						
							|  |  |  |             PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, | 
					
						
							|  |  |  |                         &ssl_obj->exc_tb); | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     PySSL_BEGIN_ALLOW_THREADS | 
					
						
							|  |  |  |     PyThread_acquire_lock(lock, 1); | 
					
						
							|  |  |  |     res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line); | 
					
						
							|  |  |  |     e = errno; | 
					
						
							|  |  |  |     (void)BIO_flush(ssl_obj->ctx->keylog_bio); | 
					
						
							|  |  |  |     PyThread_release_lock(lock); | 
					
						
							|  |  |  |     PySSL_END_ALLOW_THREADS | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (res == -1) { | 
					
						
							|  |  |  |         errno = e; | 
					
						
							|  |  |  |         PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, | 
					
						
							|  |  |  |                                              ssl_obj->ctx->keylog_filename); | 
					
						
							|  |  |  |         PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyGILState_Release(threadstate); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | _PySSLContext_get_keylog_filename(PySSLContext *self, void *c) { | 
					
						
							|  |  |  |     if (self->keylog_filename != NULL) { | 
					
						
							|  |  |  |         Py_INCREF(self->keylog_filename); | 
					
						
							|  |  |  |         return self->keylog_filename; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         Py_RETURN_NONE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | _PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) { | 
					
						
							|  |  |  |     FILE *fp; | 
					
						
							|  |  |  |     /* Reset variables and callback first */ | 
					
						
							|  |  |  |     SSL_CTX_set_keylog_callback(self->ctx, NULL); | 
					
						
							|  |  |  |     Py_CLEAR(self->keylog_filename); | 
					
						
							|  |  |  |     if (self->keylog_bio != NULL) { | 
					
						
							|  |  |  |         BIO *bio = self->keylog_bio; | 
					
						
							|  |  |  |         self->keylog_bio = NULL; | 
					
						
							|  |  |  |         PySSL_BEGIN_ALLOW_THREADS | 
					
						
							|  |  |  |         BIO_free_all(bio); | 
					
						
							|  |  |  |         PySSL_END_ALLOW_THREADS | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (arg == Py_None) { | 
					
						
							|  |  |  |         /* None disables the callback */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* _Py_fopen_obj() also checks that arg is of proper type. */ | 
					
						
							|  |  |  |     fp = _Py_fopen_obj(arg, "a" PY_STDIOTEXTMODE); | 
					
						
							|  |  |  |     if (fp == NULL) | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     self->keylog_bio = BIO_new_fp(fp, BIO_CLOSE | BIO_FP_TEXT); | 
					
						
							|  |  |  |     if (self->keylog_bio == NULL) { | 
					
						
							|  |  |  |         PyErr_SetString(PySSLErrorObject, | 
					
						
							|  |  |  |                         "Can't malloc memory for keylog file"); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_INCREF(arg); | 
					
						
							|  |  |  |     self->keylog_filename = arg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Write a header for seekable, empty files (this excludes pipes). */ | 
					
						
							|  |  |  |     PySSL_BEGIN_ALLOW_THREADS | 
					
						
							|  |  |  |     if (BIO_tell(self->keylog_bio) == 0) { | 
					
						
							|  |  |  |         BIO_puts(self->keylog_bio, | 
					
						
							|  |  |  |                  "# TLS secrets log file, generated by OpenSSL / Python\n"); | 
					
						
							|  |  |  |         (void)BIO_flush(self->keylog_bio); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PySSL_END_ALLOW_THREADS | 
					
						
							|  |  |  |     SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-03 20:40:15 +02:00
										 |  |  | #endif
 |