(root)/
Python-3.11.7/
Modules/
_ssl/
debughelpers.c
       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          PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb);
      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          Py_INCREF(self->msg_cb);
      91          return self->msg_cb;
      92      } else {
      93          Py_RETURN_NONE;
      94      }
      95  }
      96  
      97  static int
      98  _PySSLContext_set_msg_callback(PySSLContext *self, PyObject *arg, void *c) {
      99      Py_CLEAR(self->msg_cb);
     100      if (arg == Py_None) {
     101          SSL_CTX_set_msg_callback(self->ctx, NULL);
     102      }
     103      else {
     104          if (!PyCallable_Check(arg)) {
     105              SSL_CTX_set_msg_callback(self->ctx, NULL);
     106              PyErr_SetString(PyExc_TypeError,
     107                              "not a callable object");
     108              return -1;
     109          }
     110          Py_INCREF(arg);
     111          self->msg_cb = arg;
     112          SSL_CTX_set_msg_callback(self->ctx, _PySSL_msg_callback);
     113      }
     114      return 0;
     115  }
     116  
     117  static void
     118  _PySSL_keylog_callback(const SSL *ssl, const char *line)
     119  {
     120      PyGILState_STATE threadstate;
     121      PySSLSocket *ssl_obj = NULL;  /* ssl._SSLSocket, borrowed ref */
     122      int res, e;
     123      static PyThread_type_lock *lock = NULL;
     124  
     125      threadstate = PyGILState_Ensure();
     126  
     127      ssl_obj = (PySSLSocket *)SSL_get_app_data(ssl);
     128      assert(Py_IS_TYPE(ssl_obj, get_state_sock(ssl_obj)->PySSLSocket_Type));
     129      if (ssl_obj->ctx->keylog_bio == NULL) {
     130          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      if (lock == NULL) {
     140          lock = PyThread_allocate_lock();
     141          if (lock == NULL) {
     142              PyErr_SetString(PyExc_MemoryError, "Unable to allocate lock");
     143              PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value,
     144                          &ssl_obj->exc_tb);
     145              return;
     146          }
     147      }
     148  
     149      PySSL_BEGIN_ALLOW_THREADS
     150      PyThread_acquire_lock(lock, 1);
     151      res = BIO_printf(ssl_obj->ctx->keylog_bio, "%s\n", line);
     152      e = errno;
     153      (void)BIO_flush(ssl_obj->ctx->keylog_bio);
     154      PyThread_release_lock(lock);
     155      PySSL_END_ALLOW_THREADS
     156  
     157      if (res == -1) {
     158          errno = e;
     159          PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError,
     160                                               ssl_obj->ctx->keylog_filename);
     161          PyErr_Fetch(&ssl_obj->exc_type, &ssl_obj->exc_value, &ssl_obj->exc_tb);
     162      }
     163      PyGILState_Release(threadstate);
     164  }
     165  
     166  static PyObject *
     167  _PySSLContext_get_keylog_filename(PySSLContext *self, void *c) {
     168      if (self->keylog_filename != NULL) {
     169          Py_INCREF(self->keylog_filename);
     170          return self->keylog_filename;
     171      } else {
     172          Py_RETURN_NONE;
     173      }
     174  }
     175  
     176  static int
     177  _PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) {
     178      FILE *fp;
     179      /* Reset variables and callback first */
     180      SSL_CTX_set_keylog_callback(self->ctx, NULL);
     181      Py_CLEAR(self->keylog_filename);
     182      if (self->keylog_bio != NULL) {
     183          BIO *bio = self->keylog_bio;
     184          self->keylog_bio = NULL;
     185          PySSL_BEGIN_ALLOW_THREADS
     186          BIO_free_all(bio);
     187          PySSL_END_ALLOW_THREADS
     188      }
     189  
     190      if (arg == Py_None) {
     191          /* None disables the callback */
     192          return 0;
     193      }
     194  
     195      /* _Py_fopen_obj() also checks that arg is of proper type. */
     196      fp = _Py_fopen_obj(arg, "a" PY_STDIOTEXTMODE);
     197      if (fp == NULL)
     198          return -1;
     199  
     200      self->keylog_bio = BIO_new_fp(fp, BIO_CLOSE | BIO_FP_TEXT);
     201      if (self->keylog_bio == NULL) {
     202          PyErr_SetString(get_state_ctx(self)->PySSLErrorObject,
     203                          "Can't malloc memory for keylog file");
     204          return -1;
     205      }
     206      Py_INCREF(arg);
     207      self->keylog_filename = arg;
     208  
     209      /* Write a header for seekable, empty files (this excludes pipes). */
     210      PySSL_BEGIN_ALLOW_THREADS
     211      if (BIO_tell(self->keylog_bio) == 0) {
     212          BIO_puts(self->keylog_bio,
     213                   "# TLS secrets log file, generated by OpenSSL / Python\n");
     214          (void)BIO_flush(self->keylog_bio);
     215      }
     216      PySSL_END_ALLOW_THREADS
     217      SSL_CTX_set_keylog_callback(self->ctx, _PySSL_keylog_callback);
     218      return 0;
     219  }