Closed
Bug 135261
Opened 22 years ago
Closed 22 years ago
SSL_REQUIRE_CERTIFICATE semantic troubles
Categories
(NSS :: Libraries, enhancement, P1)
Tracking
(Not tracked)
RESOLVED
FIXED
3.6
People
(Reporter: nelson, Assigned: nelson)
References
Details
Attachments
(1 file, 1 obsolete file)
2.08 KB,
patch
|
wtc
:
review+
|
Details | Diff | Splinter Review |
The SSL documentation recommends that servers that wish to require SSL cert-based client authentication should set SSL_REQUIRE_CERTIFICATE to PR_FALSE, and then check for the presence of a cert on the SSL socket after the handshake is complete (e.g. when getting the client's request), and deny the request at that time if the cert is absent. There's a problem with doing that with the current implementation of SSL_REQUIRE_CERTIFICATE. The problem occurs when an SSL client has previously established an SSL session with the server, one that did not include client authentication, and that has not expired. When the client connects to the server again, if SSL_REQUIRE_CERTIFICATE is 0 (PR_FALSE) the SSL code will simply restart the existing SSL session, and will not do a new FULL SSL handshake, with the result that the user's cert is not requested from the client, and the client repeatedly receives whatever error message the server sends back when client auth is absent. In that same situation, if SSL_REQUIRE_CERTIFICATE is 1 (PR_TRUE), SSL will refuse to restart the old SSL session, and will instead force a new FULL SSL handshake, requesting client authentication. But if the client does not have cert, the SSL library will terminate the handshake and the TCP connection, which doesn't allow the server to send back a better error message. (This is the behavior that the SSL documentation recommends NOT to do.) So, what is needed is another setting of SSL_REQUIRE_CERTIFICATE, one that behaves partly like PR_TRUE, in that it refuses to restart old SSL sessions if they didn't do client auth, but also behaves partly like PR_FALSE, in that it allows the SSL handshake to continue and doesn't terminate the TCP connection if the client fails to provide client auth. I can think of a couple of ways to implement this. One is to change the behavior of SSL when SSL_REQUIRE_CERTIFICATE is PR_FALSE so that it behaves as described in the preceeding paragraph. That change would assume that any server that requests SSL client auth really is going to require it, and is not going to allow operations (other than returning error message) to proceed without a client cert. Another is to create a new value for SSL_REQUIRE_CERTIFICATE that is neither PR_FALSE nor PR_TRUE. There actually already exists one such undocumented value. SSL_REQUIRE_CERTIFICATE can be set to ((PRBool)2). Then it behaves as for PR_TRUE, but only on the first handshake on a TCP connection. It behaves like PR_FALSE on subsequent handshakes. So, one could propose the new value ((PRBool)3) to have the behavior described above. Comments on the choice of these is invited. Soon, I will attach patches that implement these proposals.
Comment 1•22 years ago
|
||
I think some information is missing about the test case for this. At the time the client establishes its first connection and SSL session with the server, the server has both SSL_REQUIRE_CERTIFICATE set to PR_FALSE and SSL_REQUEST_CERTIFICATE set to PR_FALSE, so that the client doesn't get prompted for client auth. Then, the connection times out (eg. HTTP keep-alive). Then, the server gets reconfigured and now has SSL_REQUIRE_CERTIFICATE set to PR_FALSE and SSL_REQUEST_CERTIFICATE set to PR_TRUE for all new sockets. Then the client connects to the server again, and presents its session ID in the clienthelo. At that point, the server sees that there is no client certificate associated with the SSL session. It should force a full handshake to occur in order to get the client to prompt the user for a certificate, but still let the connection through with no certificate, to let the server check the certificate on the connection itself and send an error page if the certificate is missing.
Comment 2•22 years ago
|
||
Changed the QA contact to Bishakha.
QA Contact: sonja.mirtitsch → bishakhabanerjee
Updated•22 years ago
|
Priority: -- → P1
Target Milestone: --- → 3.6
Assignee | ||
Comment 3•22 years ago
|
||
I am about to check this in, barring objection.
Comment 4•22 years ago
|
||
Comment on attachment 84667 [details] [diff] [review] Patch implements proposal described above. >Index: ssl.h >=================================================================== >RCS file: /cvsroot/mozilla/security/nss/lib/ssl/ssl.h,v >retrieving revision 1.12 >diff -u -r1.12 ssl.h >--- ssl.h 8 Nov 2001 02:15:35 -0000 1.12 >+++ ssl.h 22 May 2002 20:00:26 -0000 >@@ -138,6 +138,12 @@ > #define SSL_ALLOWED 1 > #define SSL_RESTRICTED 2 /* only with "Step-Up" certs. */ > >+/* Values for "on" with SSL_REQUIRE_CERTIFICATE. */ >+#define SSL_REQUIRE_NEVER PR_FALSE >+#define SSL_REQUIRE_ALWAYS PR_TRUE >+#define SSL_REQUIRE_FIRST_HANDSHAKE ((PRBool)2) >+#define SSL_REQUIRE_NO_ERROR ((PRBool)3) >+ These should say #define SSL_REQUIRE_NEVER 0 #define SSL_REQUIRE_ALWAYS 1 #define SSL_REQUIRE_FIRST_HANDSHAKE 2 #define SSL_REQUIRE_NO_ERROR 3 These values are not the PRBool type.
Attachment #84667 -
Flags: needs-work+
Assignee | ||
Comment 5•22 years ago
|
||
These values get passed to SSL_OptionSet() as the "on" argument, which is a PRBool. That is why they are defined as either PRBools or cast to PRBools.
Updated•22 years ago
|
Attachment #84667 -
Flags: needs-work+
Comment 6•22 years ago
|
||
Comment on attachment 84667 [details] [diff] [review] Patch implements proposal described above. This is an abuse of the "on" argument for SSL_OptionSet(). Since we already use the values 0, 1, and 2 as the "on" argument in previous NSS releases, it is too late to fix this now. >+/* Values for "on" with SSL_REQUIRE_CERTIFICATE. */ >+#define SSL_REQUIRE_NEVER PR_FALSE >+#define SSL_REQUIRE_ALWAYS PR_TRUE >+#define SSL_REQUIRE_FIRST_HANDSHAKE ((PRBool)2) >+#define SSL_REQUIRE_NO_ERROR ((PRBool)3) I would change PR_FALSE and PR_TRUE to ((PRBool)0) and ((PRBool)1). It is strange to see PR_FALSE and PR_TRUE used not as the values of a boolean.
Assignee | ||
Comment 7•22 years ago
|
||
I agree that this patch is an abuse of PRBool. There are other possible solutions that do not abuse it, but would be MUCH bigger changes to the SSL code. I was opting for an expedient fix that minimized bloat and risk due to large changes to the SSL code for a point release. Agreed?
Attachment #84667 -
Attachment is obsolete: true
Comment 8•22 years ago
|
||
Comment on attachment 84718 [details] [diff] [review] Implements Wan-Teh's suggestion r=wtc. Julien, Christian, could you review Nelson's proposed interface?
Attachment #84718 -
Flags: review+
Comment 9•22 years ago
|
||
The interface is fine with me. I assume the Enterprise server would use the SSL_REQUIRE_NO_ERROR setting, right?
Assignee | ||
Comment 10•22 years ago
|
||
Yes. However, we still need to test that using SSL_REQUIRE_NO_ERROR will solve the server's problem.
Comment 11•22 years ago
|
||
The patch looks good. I will build it and see if it solves the problem with NES 6.1 .
Comment 12•22 years ago
|
||
I tested this with NES 6.1 . It does solve the problem. However, it required a modification of the application. I had to set SSL_REQUIRE_CERTIFICATE to SSL_REQUIRE_NO_ERROR to get the behavior I wanted, which was to request the client cert upon trying to resume the old SSL session without client auth, after the server configuration changed to request a client cert. I am wondering if this shouldn't be the default behavior when a server sets SSL_REQUEST_CERTIFICATE to PR_TRUE and SSL_REQUIRE_CERTIFICATE to PR_FALSE, as NES 6.1 is doing. Is there any reason for the server not to send the certificaterequest alert in that case ? We need to review the 4 possible values of SSL_REQUIRE_CERTIFICATE, examine what type of server application they correspond to, and document them. Perhaps the macro names could also be more intuitive, but I don't have any better idea right now. Combined with the fact that there is a separate SSL_REQUEST_CERTIFICATE bit, this really makes the SSL client auth API for servers overly complex to understand. If this is so hard for us and our internal customers, I can't imagine what it is for a mozilla and NSS newbie. We should definitely do it for NSS 4.0 at the latest and simplify it. Now, here is an attempt at summarizing the current behavior. There are 8 possibilities of bit values. I will describe what happens with new and restart handshakes, as well as discuss possible scenarii with server reconfiguration. Nelson, please correct me if any of this is wrong. 1) SSL_REQUEST_CERTIFICATE=PR_FALSE , SSL_REQUIRE_CERTIFICATE=xx : if SSL_REQUEST_CERTIFICATE is PR_FALSE, SSL_REQUIRE_CERTIFICATE is ignored. So, for these four cases, the server never asks the client to present its certificate during either a new session or a session resumption, for new handshakes or for restarts. This means there will never be a certificate in the SSL session for a new handshake. There may be a certificate in the SSL session if this is a restart handhsake and the SSL session was created when the server was in a different configuration and got a certificate. 2) SSL_REQUEST_CERTIFICATE=PR_TRUE, SSL_REQUIRE_CERTIFICATE=SSL_REQUIRE_NEVER : The server will request the certificate during the first handshake, without requiring it. This will allow communication to continue without client auth, perhaps falling back to another application-specific authentication method such as HTTP authentication, or providing an application error notification instead of an SSL error. For restarts, if the SSL session did not have a client certificate associated with it, then the session is restarted without a certificate request and communication is also allowed to continue. Note that this could mean that no certificate request was ever sent to the client for the lifetime of the SSL session, if the SSL session was created when the server was configured with SSL_REQUEST_CERTIFICATE=PR_FALSE. 3) SSL_REQUEST_CERTIFICATE=PR_TRUE, SSL_REQUIRE_CERTIFICATE=SSL_REQUIRE_ALWAYS : For every new SSL handshake, the server will ask the client for a certificate, and an SSL error will result if the client does not present a valid certificate, without any chance for further application communication. For restarts, if there isn't already a certificate, the SSL session is deleted and a new full handshake is done as described above; otherwise the session is restarted. 4) SSL_REQUEST_CERTIFICATE=PR_TRUE, SSL_REQUIRE_CERTIFICATE=SSL_REQUIRE_FIRST_HANDSHAKE : For the first handshake, this will behave like case 3) . For a restart handshake, it will behave like case 2). If you take into account the possibility that the server configuration was changed between the time the SSL session was created and then restarted, then you can see that this is a "dangerous" setting. I believe its intent is to make sure that client auth is enforced, but without incurring the performance impact of doing client auth on restart handshakes. The problem is that an SSL session could be created with the server in a different state, without a client certificate. Then the server configuration could be changed to this one, and there would be no client certificate available. This means this setting should never be used in servers that dynamically reconfigure themselves. 5) SSL_REQUEST_CERTIFICATE=PR_TRUE, SSL_REQUIRE_CERTIFICATE=SSL_REQUIRE_NO_ERROR : For new handshakes, this behaves like 2) . For restart handshakes, if the SSL session does not already have a certificate, then the session is deleted, and a new handshake is done, which behaves like 2). Effectively, this means all handshakes are full, and we are not doing any restarts. But there are never any SSL errors due to lack of a client authentication. Here are some sample uses of client authentication in server applications, from simplest to most complicated. I The entire site uses SSL without any client authentication This maps to the case described above under 1). II The site entire site is protected by SSL client authentication a. Client authentication is requested at the SSL level, and enforced at the application level with an error page. The application must invalidate the session after sending the error page in order to make sure the client can try again. b. There is also a fallback to application authentication. Client authentication is requested at the SSL level, and if a client certificate is not available, the application falls back to its own method of authentication. If the application authentication fails, the application must invalidate the SSL session after sending the error page, in order to make sure the client can try again. If the application authentication succeeds, it leaves the SSL session valid, and restart handshakes must be honored, without any further certificate requests. Both of these map to the case described above under 2). III The entire site is protected by SSL client authentication, which is required and enforced at the SSL level. This maps to the case described above under 3). IV The site is mixed unprotected/protected by client authentication. Most of the site is unprotected. So this maps to case described above under 1) for all first handshakes - we don't want to even request the client certificate for most content even if the user has one. For protected content, new handshakes will be done with configuration 5). V The site is mixed unprotected/protected by client authentication. The majority of the site is protected. In this case it makes sense to request the client certificate but not require it for first handshakes. This maps to case 5) above for first handshakes. For protected content, new handshakes need not be done, the client certificate can just be looked up in the socket by the application if available, and access denied if unavailable. However the exception to this rule is if the server was reconfigured and the session was created with a configuration different than 5), and never had a certificate request. In that case we would want to do a new handshake and ask the client again. However, there is no way in the API to know if there was a certificate request on the SSL session, so the application can't do that. I think it would be worthwile to add a field in the SSL session noting whether we attempted a cert request, regardless of whether it succeeded or failed. I think we should add the following logic : If no certificate request was done in the initial handshake (ie. SSL_REQUEST_CERTIFICATE was PR_FALSE), and we are doing a restart, but SSL_REQUEST_CERTIFICATE is now PR_TRUE, then we should force a new full handshake for all values of SSL_REQUIRE_CERTIFICATE - but only SSL_REQUIRE_ALWAYS would result in an SSL error if the client does not send a certificate.
Assignee | ||
Comment 13•22 years ago
|
||
I have checked in the patch above onto the trunk. Is there also some branch on which it should be checked in?
Comment 14•22 years ago
|
||
No. 3.6 is on the trunk right now. We don't need this in 3.5 (which is to support the Netscape 7.0 release).
Assignee | ||
Comment 15•22 years ago
|
||
OK, then I am marking this fixed. Julien has suggested that the value 3 ought to have a better name than the one I gave it, and I don't disagree, but I haven't got a better one. If you'd prefer another name, please suggest it here.
Status: NEW → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Assignee | ||
Comment 16•22 years ago
|
||
The mozilla documentation in the online SSL reference manual needs to be updated for this change. That used to be the exclusive domain of a tech writer and I had no CVS access to the CVS repository that held the documentation. If that repository is now accessible to me, please email me directions on how to access it. Thanks.
Comment 17•22 years ago
|
||
The value 2 in the initializer for ssl_defaults in sslsock.c should be replaced by the new symbolic constant (SSL_REQUIRE_FIRST_HANDSHAKE).
You need to log in
before you can comment on or make changes to this bug.
Description
•