LCOV - code coverage report
Current view: | top level - Modules/_ssl - debughelpers.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 0 | 113 | 0.0 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 0 | 6 | 0.0 %
|  |  | Branches: | 0 | 46 | 0.0 %

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

Generated by: LCOV version 1.14