Skip to content

Conversation

@cwyang
Copy link
Contributor

@cwyang cwyang commented Nov 18, 2015

To support renegotiation, it is sufficient to flush write buffer
when write operation is happened in SSL_read().

To support renegotiation, it is sufficient to flush write buffer
when write operation is happened in SSL_read().
@cwyang
Copy link
Contributor Author

cwyang commented Nov 18, 2015

Greetings,

Submitted patch is tested by hands:

$ openssl s_client -connect {h2o_ipaddr:h2o_port}
Pressing R to trigger renegotiation

Patched version does renegotiation properly
while original version is failed as follows:
139675521959584:error:1409E0E5:SSL routines:SSL3_WRITE_BYTES:ssl handshake failure:s3_pkt.c:598:

Best regards,
Chul-Woong

@kazuho
Copy link
Member

kazuho commented Nov 19, 2015

Interesting!

However, to make it always work, you must check if there is any write in flight before calling do_write. The socket structure of H2O is not designed to have more than one write request in flight at once.

Can you look into resolving the issue?

Also, it would be great if you could provide how you are going to use the renegotiation. H2O does not provide an interface to obtain the client certificate (or an interface to initiate renegotiation). Are you using libh2o as an event loop?

Added spare output buffer, waitbuf, to queue output payloads
while another write operation is in flight.

At now, waitbuf is only used for coping to renegotiation case.
There can be, however, other use for waitbuf since waitbuf
enables queing multiple writes at any time.
It can be used for increasing overall I/O performance.

Two assertions are put in code:
1) on_handshake_complete() expects waitbuf to be empty.
   That is, there should be no write operation while another write is in flight
   in handshake phase.
2) h2o_socket_write() expects waitbuf to be empty .
   Note that output may not be empty at h2o_socket_write()
   since pending waitbuf is moved to output at the write completion
   callback.
@cwyang
Copy link
Contributor Author

cwyang commented Nov 20, 2015

First commit should always work in handling renegotiation case.
Renegotiation attempt while another write request in flight is ignored in
proposed implementation safely by following reason.

Let's think of situation that peer A receives renegotiation request from peer B.
Proposed implementation adds renegotiation payload onto output.
When there is write operation (let' say it FOO) in flight, the added renego payload are
appended to tail of previous output buffer and removed at on_write_complete()
without actually sending to peer B.
However, B initiated renegotiation but B received FOO, not handshake message.
So B abort the session and A gets notified.
This is a normal consequence.
Proper SSL peers should begin renegotiation only when there is no payload in transit.
In other words, renegotiation breaks in full-duplex data transmission state and should be
attempted in half-duplex state.

But I can think of following imaginary scenario:

  1. A send payload [FOO].
    [FOO] is on the wire, but A's event loop are delayed and on_write_complete() does not called
  2. B receives [FOO]
  3. B sends renegotiation request [HELLO-REQ]
  4. A receives [HELLO-REQ]
  5. A puts [CLI-HELLO] onto output
  6. A's on_write_complete() is called and [CLI-HELO] is discarded.
    • A waits for B's [SVR-HELLO] and
    • B wait for A's [CLI-HELLO]

It's not likely that [FOO]'s completion function to be delayed so much, but it can be possible.
So I submit another commit. I would be grateful if you look into it.

Yes, I'm reading and tinkering with some parts of you code. I like your approach of timer handling in event loop. Iibh2o is already too big to use it as a whole to me.

@kazuho
Copy link
Member

kazuho commented Nov 23, 2015

Thank you for the fix. The code looks fine to me.

My understanding is that your fix has actual value, since client-initiated renegotiation may occur while server is sending data.

Do you have any proposal for exposing renegotiation layer to libh2o and the standalone server?

At least we should have the following:

  • API to request renegotiation to h2o_socket_t
  • API to obtain client certificate (and related info) from h2o_socket_t
  • define configuration directives and implement them

I can work for them, but I would appreciate it if you could come up with a PR.

@cwyang
Copy link
Contributor Author

cwyang commented Dec 1, 2015

Thanks for a review.

Supporting client authentication feature on h2o requires some work and
I'm not sure I'm the right person on that work.
I'll pay an attention to it when i'm ready.
It's busy season near year-end. :-)

Regards,
Chul-Woong

@kazuho
Copy link
Member

kazuho commented Dec 1, 2015

My pleasure.

Supporting client authentication feature on h2o requires some work and
I'm not sure I'm the right person on that work.
I'll pay an attention to it when i'm ready.
It's busy season near year-end. :-)

I understand. Thank you for your help anyways in providing the PR. I believe your contribution will help us implementing client authentication to h2o.

@RealEnder
Copy link

Client certificate authentication is widely used in eGovernment and online banking services in Europe. Implementing this feature will allow using h2o in such environments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants