static void decrypt()

in c/src/tls/openssl.c [2109:2199]


static void decrypt(pn_tls_t *tls) {
  assert(tls);
  buff_ptr curr_result = current_decrypted_result(tls);
  pbuffer_t *pending = next_decrypt_pending(tls);
  bool peek_needed = false;

  bool decrypt_done = false;
  while (!decrypt_done) {
    if (tls->pn_tls_err)
      return;

    // Insert encrypted data into openssl filter chain.
    while (pending && !tls->dec_wblocked && !tls->dec_closed) {
      size_t n = pending->size - tls->decrypt_pending_offset;
      if (n) {
        char *bytes = pending->bytes + pending->offset + tls->decrypt_pending_offset;
        int wcount = BIO_write(tls->bio_net_io, bytes, n);
        if (wcount < (int) n)
          tls->dec_wblocked = true;
        if (wcount > 0) {
          if (!tls->dec_closed)
            tls->dec_rblocked = false;
          tls->enc_rblocked = false;
          tls->decrypt_pending_offset += wcount;
          // new write side content may generate decrypted bytes, EOS, error
          peek_needed = true;
          // tls_trace_callback("tls decrypt: scanned %d bytes", wcount);)
        }
      }
      pending = next_decrypt_pending(tls);
    }

    // Extract decrypted data from other side of filter chain.
    while (curr_result && !tls->dec_rblocked) {
      pbuffer_t *result = &tls->dresult_buffers[curr_result-1];
      size_t n = room(result);
      assert(n);
      int rcount = SSL_read(tls->ssl, result->bytes + result->offset + result->size, n);
      if (rcount > 0) {
        tls->dec_wblocked = false;
        peek_needed = true;  // May or may not have drained all available decrypted bytes.
        if (result->size == 0) {
          // first data inserted: convert from blank type to encrypted type
          assert(result->type == buff_dresult_blank);
          blank_dresult_pop(tls, curr_result);
          decrypted_result_add(tls, curr_result);
        }
        result->size += rcount;
        if (room(result) == 0) {
          // Tentatively set a blank buffer for future output without popping.
          curr_result = tls->dresult_first_blank;
        }
      } else {
        tls->dec_rblocked = true;
        peek_needed = false;
        tls->dec_rpending = false;
        check_error_reason(tls, rcount);
      }
    }

    // Done if not possible to move any more bytes from input to output bufs
    if ( (tls->dec_closed || !pending || tls->dec_wblocked) /* write side */ &&
         (!curr_result || tls->dec_rblocked) ) /* read side */ {
      decrypt_done = true;
      if (peek_needed && !tls->pn_tls_err && !tls->dec_closed) {
        // Set dec_rpending.
        // Make OpenSSL process input to at least first decrypted byte (if any)
        char unused;
        int pcount = SSL_peek(tls->ssl, &unused, 1);
        tls->dec_rpending = (pcount == 1);
        if (pcount <= 0) {
          check_error_reason(tls, pcount);
        }

        // Peek may have made more room in buffer (i.e. handshake followed by large
        // incomplete application record and dec_wblocked). If we did not process an
        // application record, we must have processed at least one non-app record.
        // No longer write blocked after peek.  PROTON-2736.
        if (!tls->dec_rpending && tls->dec_wblocked) {
          decrypt_done = false;
          tls->dec_wblocked = false;
        }
      }
    }
  }

  if (!tls->handshake_ok && SSL_do_handshake(tls->ssl) == 1) {
    tls->handshake_ok = true;
    tls->can_shutdown = true;
  }
}