(root)/
Python-3.12.0/
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          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  }