Rob Crittenden wrote: > In an SSL client I want to force the SSL handshake to take place instead > of passively waiting for it to happen during the first write. > > Right after I connect to the server I'm currently doing this: > > SSL_ResetHandshake(ssl, /* asServer */ PR_FALSE); > do { > SSL_ForceHandshake(ssl); > PR_Recv (ssl, handshake, 1, PR_MSG_PEEK, 100); > err = PR_GetError(); > } while (err != PR_END_OF_FILE_ERROR && handshake_done == 0); > > If the handshake succeeds the my SSL_HandshakeCallback callback sets > handshake_done and I exit the loop. If it fails then sooner or later > PR_Recv will set the error to EOF. I don't care if I'm losing the error > from the handshake, I do the logging for failures in the > SSL_BadCertHook() callback.
Here are a few (?) questions and comments: 1. Is this a blocking socket, or non-blocking? 2. If non-blocking, are you certain that the connection has completed? That is, are you certain that the TCP's "three phase connect" is completely done? This is tricky for non-blocking sockets, and trivial for blocking sockets. 3. Is this the first handshake on the socket after the connect? or Is it a subsequent (e.g. second) handshake on the socket? 4. Is this a "server speaks first" application protocol? or is this a "client speaks first" protocol? 5. What if some other error occurs besides PR_END_OF_FILE_ERROR? This loop continues. IMO, it should not. Some errors leave the SSL socket in a state where it cannot continue. This includes PR_IO_TIMEOUT_ERROR, if I'm not mistaken. If you ignore the error code and call an I/O function on the SSL socket again, it will return an error again immediately. As coded, this will be an infinite loop. 6. IMO, you need to check every SSL call (and that includes PR_Recv) to see if it succeeded or failed, and not continue to use the socket on failure. PR_WOULD_BLOCK_ERROR (a.k.a. EWOULDBLOCK) is obviously an exception to this rule, but needs to be handled with PR_Poll. Don't rely on the value of PR_GetError to tell you whether the previous operation succeeded or failed. The SSL socket operations are defined such that the value returned by PR_GetError is only meaningful after a function returns some failure value. After a function returns a successful return, PR_GetError may return ANYTHING and is not meaningful. 7. Why are you using such a short timeout on PR_Recv? 8. Why are you using SSL_ForceHandshake at all? Why not use PR_Recv to do both the handshake and receive the first application message? > My questions are: > > 1. Do I need the loop or will the PR_Recv, even with such a short > timeout, do the trick for me? What trick are you trying to do? > 2. Is there a better way to do this? I'm sure the answer is "yes", but I can't advise you of an optimal solution without knowing the answers to my questions above. Also I don't really understand what you're trying to achieve with this loop. The usual reason for using SSL_ForceHandshake is when you're in a second handshake situation, where you're a server, you've received a request, you expect to receive nothing more until you've sent the response, you've started a second handshake to request client auth, and you have nothing to send until that handshake finishes. In that case, it is not appropriate to call either PR_Send/Write nor PR_Recv/Read, so you need SSL_ForceHandshake. In most other situations, where you're waiting for the other side to send you something, you can just use PR_Recv/Read to accomplish the handshake and wait for the message. On a blocking socket, no loop is needed. In this case, you're the client and you're waiting for the server to say something (apparently a "server speaks first" protocol, such as SMTP). Assuming your socket is blocking, PR_Recv by itself should do the job for you without a loop, and with a reasonable timeout. > rob -- Nelson B _______________________________________________ dev-tech-crypto mailing list dev-tech-crypto@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-tech-crypto