robbiehanson/CocoaAsyncSocket — pull request #255 by epatey (2014-08-01 13:52:40+00:00)
Title: Fix bug in GCDAsyncSocketManuallyEvaluateTrust flow that can result in a dead socket.

When using SecureTransport, the TLS handshake likely requires multiple calls to `SSLHandshake`. That method will return a variety of errors. Two errors, `errSSLWouldBlock` and `errSSLPeerAuthCompleted` in particular, require special handling.

`errSSLWouldBlock` is returned when the handshake protocol is awaiting more data - either outbound or inbound. We more data is available, `SSLHandshake` should be called again to resume the protocol.

`errSSLPeerAuthCompleted` is returned when the the peer's cert has been validated **or** manual verification has been requested. In the manual verification case, `SSLHandshake` should be called again upon successful completion of the manual verification.

The bug is that the code that intends to resume the protocol when new data is available calls `SSLWrite` even when the last error was not `errSSLWouldBlock`. Specifically, the availability of new data was inducing a call to `SSLWrite` when the last error was `errSSLPeerAuthCompleted` and the manual verification code was in the process of executing.

Sometimes, the impact is that the cert is declared valid to the handshake protocol prior to the verification completing. Other times, the impact is that the socket becomes broken. In my experience, when this happens data can be successfully written to the socket, but nothing can EVER be read.

An easy way to reproduce the error is to:
1. artificially delay completion of `socket:didReceiveTrust:completionHandler:`
2. have the peer send data to the client immediately upon TLS handshake completing on its end (which will be prior to the manual cert verification completion)