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