/src/nss/lib/ssl/sslcon.c
Line | Count | Source |
1 | | /* |
2 | | * Basic SSL handshake functions. |
3 | | * |
4 | | * This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | | |
8 | | #include "nssrenam.h" |
9 | | #include "cert.h" |
10 | | #include "secitem.h" |
11 | | #include "sechash.h" |
12 | | #include "cryptohi.h" /* for SGN_ funcs */ |
13 | | #include "keyhi.h" /* for SECKEY_ high level functions. */ |
14 | | #include "ssl.h" |
15 | | #include "sslimpl.h" |
16 | | #include "sslproto.h" |
17 | | #include "ssl3prot.h" |
18 | | #include "sslerr.h" |
19 | | #include "pk11func.h" |
20 | | #include "prinit.h" |
21 | | |
22 | | /* |
23 | | ** Put a string tag in the library so that we can examine an executable |
24 | | ** and see what kind of security it supports. |
25 | | */ |
26 | | const char *ssl_version = "SECURITY_VERSION:" |
27 | | " +us" |
28 | | " +export" |
29 | | #ifdef TRACE |
30 | | " +trace" |
31 | | #endif |
32 | | #ifdef DEBUG |
33 | | " +debug" |
34 | | #endif |
35 | | ; |
36 | | |
37 | | /*********************************************************************** |
38 | | * Gathers in and handles records/messages until either the handshake is |
39 | | * complete or application data is available. |
40 | | * |
41 | | * Called from ssl_Do1stHandshake() via function pointer ss->handshake. |
42 | | * Caller must hold handshake lock. |
43 | | * This function acquires and releases the RecvBufLock. |
44 | | * |
45 | | * returns SECSuccess for success. |
46 | | * returns SECFailure on error, setting PR_WOULD_BLOCK_ERROR if only blocked. |
47 | | * |
48 | | * The gather functions called by ssl_GatherRecord1stHandshake are expected |
49 | | * to return values interpreted as follows: |
50 | | * 1 : the function completed without error. |
51 | | * 0 : the function read EOF. |
52 | | * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. |
53 | | * |
54 | | * This code is similar to, and easily confused with, DoRecv() in sslsecur.c |
55 | | * |
56 | | * This function is called from ssl_Do1stHandshake(). |
57 | | * The following functions put ssl_GatherRecord1stHandshake into ss->handshake: |
58 | | * ssl_BeginClientHandshake |
59 | | * ssl3_RestartHandshakeAfterCertReq |
60 | | * ssl3_RestartHandshakeAfterServerCert |
61 | | * ssl_BeginServerHandshake |
62 | | */ |
63 | | SECStatus |
64 | | ssl_GatherRecord1stHandshake(sslSocket *ss) |
65 | 65.4k | { |
66 | 65.4k | int rv; |
67 | | |
68 | 65.4k | PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); |
69 | | |
70 | 65.4k | ssl_GetRecvBufLock(ss); |
71 | | |
72 | | /* Wait for handshake to complete, or application data to arrive. */ |
73 | 65.4k | rv = ssl3_GatherCompleteHandshake(ss, 0); |
74 | 65.4k | SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d", |
75 | 65.4k | SSL_GETPID(), ss->fd, rv)); |
76 | | |
77 | 65.4k | ssl_ReleaseRecvBufLock(ss); |
78 | | |
79 | 65.4k | if (rv <= 0) { |
80 | 60.6k | if (rv == 0) { |
81 | | /* EOF. Loser */ |
82 | 28.6k | PORT_SetError(PR_END_OF_FILE_ERROR); |
83 | 28.6k | } |
84 | 60.6k | if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) { |
85 | 4.86k | SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)", |
86 | 4.86k | SSL_GETPID(), ss->fd, ss->gs.remainder)); |
87 | 4.86k | } |
88 | 60.6k | return SECFailure; /* rv is < 0 here. */ |
89 | 60.6k | } |
90 | | |
91 | 4.73k | ss->handshake = NULL; |
92 | 4.73k | return SECSuccess; |
93 | 65.4k | } |
94 | | |
95 | | /* This function is called at the beginning of a handshake to ensure that at |
96 | | * least one SSL/TLS version is enabled. */ |
97 | | static SECStatus |
98 | | ssl_CheckConfigSanity(sslSocket *ss) |
99 | 62.7k | { |
100 | 62.7k | if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) { |
101 | 0 | SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.", |
102 | 0 | SSL_GETPID(), ss->fd)); |
103 | 0 | PORT_SetError(SSL_ERROR_SSL_DISABLED); |
104 | 0 | return SECFailure; |
105 | 0 | } |
106 | 62.7k | return SECSuccess; |
107 | 62.7k | } |
108 | | |
109 | | /* Sends out the initial client Hello message on the connection. |
110 | | * Acquires and releases the socket's xmitBufLock. |
111 | | */ |
112 | | SECStatus |
113 | | ssl_BeginClientHandshake(sslSocket *ss) |
114 | 31.8k | { |
115 | 31.8k | sslSessionID *sid = NULL; |
116 | 31.8k | SECStatus rv; |
117 | | |
118 | 31.8k | PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); |
119 | | |
120 | 31.8k | ss->sec.isServer = PR_FALSE; |
121 | | |
122 | 31.8k | rv = ssl_CheckConfigSanity(ss); |
123 | 31.8k | if (rv != SECSuccess) |
124 | 0 | goto loser; |
125 | | |
126 | | /* Get peer name of server */ |
127 | 31.8k | rv = ssl_GetPeerInfo(ss); |
128 | 31.8k | if (rv < 0) { |
129 | | #ifdef HPUX11 |
130 | | /* |
131 | | * On some HP-UX B.11.00 systems, getpeername() occasionally |
132 | | * fails with ENOTCONN after a successful completion of |
133 | | * non-blocking connect. I found that if we do a write() |
134 | | * and then retry getpeername(), it will work. |
135 | | */ |
136 | | if (PR_GetError() == PR_NOT_CONNECTED_ERROR) { |
137 | | char dummy; |
138 | | (void)PR_Write(ss->fd->lower, &dummy, 0); |
139 | | rv = ssl_GetPeerInfo(ss); |
140 | | if (rv < 0) { |
141 | | goto loser; |
142 | | } |
143 | | } |
144 | | #else |
145 | 0 | goto loser; |
146 | 0 | #endif |
147 | 0 | } |
148 | | |
149 | 31.8k | SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd)); |
150 | | |
151 | | /* If there's an sid set from an external cache, use it. */ |
152 | 31.8k | if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) { |
153 | 0 | sid = ss->sec.ci.sid; |
154 | 0 | SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd)); |
155 | 31.8k | } else if (!ss->opt.noCache) { |
156 | | /* Try to find server in our session-id cache */ |
157 | 16.4k | sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer, |
158 | 16.4k | ss->sec.ci.port, ss->peerID, ss->url); |
159 | 16.4k | } |
160 | | |
161 | 31.8k | if (sid) { |
162 | 0 | if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) { |
163 | 0 | PORT_Assert(!ss->sec.localCert); |
164 | 0 | ss->sec.localCert = CERT_DupCertificate(sid->localCert); |
165 | 0 | } else { |
166 | 0 | ssl_UncacheSessionID(ss); |
167 | 0 | if (ss->sec.ci.sid == sid) { |
168 | | /* sid aliases ss->sec.ci.sid (external cache); clear it so |
169 | | * the socket cannot hold a dangling pointer if the |
170 | | * ssl3_NewSessionID allocation below fails. */ |
171 | 0 | ss->sec.ci.sid = NULL; |
172 | 0 | } |
173 | 0 | ssl_FreeSID(sid); |
174 | 0 | sid = NULL; |
175 | 0 | } |
176 | 0 | } |
177 | 31.8k | if (!sid) { |
178 | 31.8k | sid = ssl3_NewSessionID(ss, PR_FALSE); |
179 | 31.8k | if (!sid) { |
180 | 0 | goto loser; |
181 | 0 | } |
182 | | /* This session is a dummy, which we don't want to resume. */ |
183 | 31.8k | sid->u.ssl3.keys.resumable = PR_FALSE; |
184 | 31.8k | } |
185 | 31.8k | ss->sec.ci.sid = sid; |
186 | | |
187 | 31.8k | ss->gs.state = GS_INIT; |
188 | 31.8k | ss->handshake = ssl_GatherRecord1stHandshake; |
189 | | |
190 | | /* ssl3_SendClientHello will override this if it succeeds. */ |
191 | 31.8k | ss->version = SSL_LIBRARY_VERSION_3_0; |
192 | | |
193 | 31.8k | ssl_GetSSL3HandshakeLock(ss); |
194 | 31.8k | ssl_GetXmitBufLock(ss); |
195 | 31.8k | rv = ssl3_SendClientHello(ss, client_hello_initial); |
196 | 31.8k | ssl_ReleaseXmitBufLock(ss); |
197 | 31.8k | ssl_ReleaseSSL3HandshakeLock(ss); |
198 | | |
199 | 31.8k | return rv; |
200 | | |
201 | 0 | loser: |
202 | 0 | return SECFailure; |
203 | 31.8k | } |
204 | | |
205 | | SECStatus |
206 | | ssl_BeginServerHandshake(sslSocket *ss) |
207 | 30.8k | { |
208 | 30.8k | SECStatus rv; |
209 | | |
210 | 30.8k | ss->sec.isServer = PR_TRUE; |
211 | 30.8k | ss->ssl3.hs.ws = wait_client_hello; |
212 | | |
213 | 30.8k | rv = ssl_CheckConfigSanity(ss); |
214 | 30.8k | if (rv != SECSuccess) |
215 | 0 | goto loser; |
216 | | |
217 | 30.8k | ss->handshake = ssl_GatherRecord1stHandshake; |
218 | 30.8k | return SECSuccess; |
219 | | |
220 | 0 | loser: |
221 | 0 | return SECFailure; |
222 | 30.8k | } |
223 | | |
224 | | /* This function doesn't really belong in this file. |
225 | | ** It's here to keep AIX compilers from optimizing it away, |
226 | | ** and not including it in the DSO. |
227 | | */ |
228 | | |
229 | | #include "nss.h" |
230 | | extern const char __nss_ssl_version[]; |
231 | | |
232 | | PRBool |
233 | | NSSSSL_VersionCheck(const char *importedVersion) |
234 | 0 | { |
235 | 0 | #define NSS_VERSION_VARIABLE __nss_ssl_version |
236 | 0 | #include "verref.h" |
237 | | |
238 | | /* |
239 | | * This is the secret handshake algorithm. |
240 | | * |
241 | | * This release has a simple version compatibility |
242 | | * check algorithm. This release is not backward |
243 | | * compatible with previous major releases. It is |
244 | | * not compatible with future major, minor, or |
245 | | * patch releases. |
246 | | */ |
247 | 0 | return NSS_VersionCheck(importedVersion); |
248 | 0 | } |
249 | | |
250 | | const char * |
251 | | NSSSSL_GetVersion(void) |
252 | 0 | { |
253 | 0 | return NSS_VERSION; |
254 | 0 | } |