Peter Djalaliev wrote: > I have a question about what happens when the first SSL handshake on a > SSL connection tries to gather data from a socket that would block > (e.g. there is no data tobe read yet).
Peter, Rather than answer your questions about the functions in the code, one by one, I'm going to try to give you the "big picture". I'll also explain about that historic artifact known as "SECWouldBlock". Maybe the behavior of the code will make more sense in light of this information. NSS's libSSL is a "pushable" layer on an NSPR socket. It modifies the behavior of an NSPR socket, by adding SSL protocol to it. With or without the presence of libSSL, the semantics of an NSPR socket with respect to blocking/non-blocking behavior are the same. NSPR sockets are defined to operate as blocking or non-blocking sockets. The behaviors of these are very similar, but not quite identical, to unix BSD sockets. Under the hood, inside of NSPR, NSPR always uses non-blocking sockets from the underlying OS implementation. NSPR then implements NSPR socket semantics on top of the underlying non-blocking socket. That is, NSPR implements blocking or non-blocking semantics, as the application has requested, on top of the underlying non-blocking OS socket. For the purposes of the application, and the purposes of NSS, it doesn't matter that NSPR uses non-blocking sockets underneath. The layers above NSPR concern themselves only with the semantic behavior provided by NSPR to its users. When NSS refers to a socket as blocking or non-blocking, it is referring to the NSPR behavior of the socket, not the underlying OS socket behavior. So, it's best to just forget that you know that NSPR sockets are always non-blocking under the hood, and just think of them as being blocking or non-blocking as you would for the OS sockets if you weren't use NSPR. NSPR blocking sockets have the property that they NEVER return a short write, with or without SSL. They also never return PR_FAILURE with error code PR_WOULD_BLOCK_ERROR. As seen by the application, the behavior of NSPR sockets, with respect to blocking or non-blocking, is the same with or without SSL. With or without libSSL, a read on a non-blocking NSPR socket that cannot proceed because no data is available to be read will return PR_FAILURE with error code PR_WOULD_BLOCK_ERROR. The presence of libSSL does not change the behavior of the socket from non-blocking to blocking. Even in the middle of a handshake on a non-blocking socket, if the handshake protocol requires the receipt of a record from the peer, and no data is available to be read from the underlying socket, the SSL socket will return PR_FAILURE with error code PR_WOULD_BLOCK_ERROR. If the SSL code sees that it has received PR_WOULD_BLOCK_ERROR from the lower layer, it may safely assume that it is operating on a non-blocking NSPR socket, and therefore it must also provide non-blocking NSPR socket semantics, and must return the same result to its caller. If an application wants a PR_Read or PR_Write to not return until the handshake is over and the first application data has been sent or received, the NSPR socket must be configured as a blocking socket. That is the default condition of a new NSPR socket, by the way. An application will not see a non-blocking socket unless it sets the NSPR socket option to be non-blocking. An NSPR socket that is returned from PR_Accept will inherit its blocking/non-blocking status from the listen FD passed to PR_Accept. Finally, I must speak to SECWouldBlock. SECWouldBlock is not part of the definition of an NSPR socket. An NSPR socket (with or without SSL) does not return SECWouldBlock in response to any NSPR function (e.g. PR_Read never returns SECWouldBlock). SECWouldBlock is a value used inside libSSL for various purposes. Some of the callback interfaces, where libSSL calls out to application- supplied functions, are defined to allow the called function to return SECWouldBlock to libSSL. More on that below. SECWouldBlock is largely an artifact of the days before NSS was converted to use NSPR (which was in NSS 1.5). Before NSS 1.5, libSSL would return SECSuccess, SECFailure, or SECWouldBlock to any caller of the SSL socket IO functions (e.g. SSL_Read). SECWouldBlock does NOT mean the same thing as PR_WOULD_BLOCK_ERROR, and never did. It does NOT mean that the underlying socket is awaiting I/O completion. The meaning of SECWouldBlock is context dependent, and is used throughout NSS in various places with various meanings, usually to distinguish the cases of "function failed", and "function succeeded but results were negative". For example, when various PK11_* password functions return SECWouldBlock, it means the function succeeded but the entered password was bad. I won't discuss all the places it is used in NSS, but I will mention how it is used in the context of SSL. When ssl2_GatherData returns SECWouldBlock, it means that ssl2_GatherData has gathered (and processed) an SSL3/TLS record, and the caller should switch from the SSL2 record gathering engine to the SSL3/TLS record gathering engine. In other contexts within libSSL, SECWouldBlock means that the progress on the SSL socket is stopped because of something that is NOT related to the underlying socket. It indicates that the caller should NOT use a poll/select type function to determine when further progress can be made on the socket. libSSL defines interfaces for calling application-supplied callback functions for several purposes, some of which are: a) validating a received cert chain, b) the "bad cert" callback, which allows the application to choose to override an error in the received cert chain, and c) the client authentication certificate selection callback, which asks the client application to choose a client auth certificate to send to the server. The callbacks listed above may initiate other activity that must finish before further progress can be made in the SSL handshake. For example, an OCSP request may be sent, or the callback may choose to ask the user (through a dialog)how to proceed (e.g. to choose a cert from among several). While the application is waiting for response from the user (or OCSP responder), the application may not wish to stop the entire thread waiting for that result. So, the callback may return SECWouldBlock to libSSL, telling it that the answer for which the callback was called is not yet known. LibSSL responds to that value by taking a path of execution that suspends the progress of the SSL state machine at that point, and returns to the caller (e.g. to the caller of PR_Read). When that happens, libSSL returns PR_FAILURE with PR_WOULD_BLOCK_ERROR. That is, libSSL effectively turns SECWouldBlock into PR_WOULD_BLOCK_ERROR. This means that upon return of PR_Read, the calling application cannot distinguish between the cases where the SSL socket is blocked waiting for more data to arrive on the SSL socket itself, and the case where the socket if effectively blocked waiting on local user UI action or OCSP response, based solely on the error code. But since the callback function that returns SECWouldBlock to libSSL comes from the same application that called PR_Read, presumably the application can arrange to communicate that knowledge to itself. See also http://lxr.mozilla.org/mozilla/source/security/nss/lib/ssl/notes.txt -- Nelson B _______________________________________________ dev-tech-crypto mailing list dev-tech-crypto@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-tech-crypto