Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(714)

Side by Side Diff: net/third_party/nss/ssl/sslgathr.c

Issue 394003: Linux: enable building with a local version of libssl. (Closed)
Patch Set: ... Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/third_party/nss/ssl/sslerr.c ('k') | net/third_party/nss/ssl/sslimpl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Gather (Read) entire SSL2 records from socket into buffer.
3 *
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is the Netscape security libraries.
18 *
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39 /* $Id: sslgathr.c,v 1.10 2009/10/16 17:45:35 wtc%google.com Exp $ */
40 #include "cert.h"
41 #include "ssl.h"
42 #include "sslimpl.h"
43 #include "sslproto.h"
44
45 /* Forward static declarations */
46 static SECStatus ssl2_HandleV3HandshakeRecord(sslSocket *ss);
47
48 /*
49 ** Gather a single record of data from the receiving stream. This code
50 ** first gathers the header (2 or 3 bytes long depending on the value of
51 ** the most significant bit in the first byte) then gathers up the data
52 ** for the record into gs->buf. This code handles non-blocking I/O
53 ** and is to be called multiple times until ss->sec.recordLen != 0.
54 ** This function decrypts the gathered record in place, in gs_buf.
55 *
56 * Caller must hold RecvBufLock.
57 *
58 * Returns +1 when it has gathered a complete SSLV2 record.
59 * Returns 0 if it hits EOF.
60 * Returns -1 (SECFailure) on any error
61 * Returns -2 (SECWouldBlock) when it gathers an SSL v3 client hello header.
62 **
63 ** The SSL2 Gather State machine has 4 states:
64 ** GS_INIT - Done reading in previous record. Haven't begun to read in
65 ** next record. When ssl2_GatherData is called with the machine
66 ** in this state, the machine will attempt to read the first 3
67 ** bytes of the SSL2 record header, and will advance the state
68 ** to GS_HEADER.
69 **
70 ** GS_HEADER - The machine is in this state while waiting for the completion
71 ** of the first 3 bytes of the SSL2 record. When complete, the
72 ** machine will compute the remaining unread length of this record
73 ** and will initiate a read of that many bytes. The machine will
74 ** advance to one of two states, depending on whether the record
75 ** is encrypted (GS_MAC), or unencrypted (GS_DATA).
76 **
77 ** GS_MAC - The machine is in this state while waiting for the remainder
78 ** of the SSL2 record to be read in. When the read is completed,
79 ** the machine checks the record for valid length, decrypts it,
80 ** and checks and discards the MAC, then advances to GS_INIT.
81 **
82 ** GS_DATA - The machine is in this state while waiting for the remainder
83 ** of the unencrypted SSL2 record to be read in. Upon completion,
84 ** the machine advances to the GS_INIT state and returns the data.
85 */
86 int
87 ssl2_GatherData(sslSocket *ss, sslGather *gs, int flags)
88 {
89 unsigned char * bp;
90 unsigned char * pBuf;
91 int nb, err, rv;
92
93 PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
94
95 if (gs->state == GS_INIT) {
96 /* Initialize gathering engine */
97 gs->state = GS_HEADER;
98 gs->remainder = 3;
99 gs->count = 3;
100 gs->offset = 0;
101 gs->recordLen = 0;
102 gs->recordPadding = 0;
103 gs->hdr[2] = 0;
104
105 gs->writeOffset = 0;
106 gs->readOffset = 0;
107 }
108 if (gs->encrypted) {
109 PORT_Assert(ss->sec.hash != 0);
110 }
111
112 pBuf = gs->buf.buf;
113 for (;;) {
114 SSL_TRC(30, ("%d: SSL[%d]: gather state %d (need %d more)",
115 SSL_GETPID(), ss->fd, gs->state, gs->remainder));
116 bp = ((gs->state != GS_HEADER) ? pBuf : gs->hdr) + gs->offset;
117 nb = ssl_DefRecv(ss, bp, gs->remainder, flags);
118 if (nb > 0) {
119 PRINT_BUF(60, (ss, "raw gather data:", bp, nb));
120 }
121 if (nb == 0) {
122 /* EOF */
123 SSL_TRC(30, ("%d: SSL[%d]: EOF", SSL_GETPID(), ss->fd));
124 rv = 0;
125 break;
126 }
127 if (nb < 0) {
128 SSL_DBG(("%d: SSL[%d]: recv error %d", SSL_GETPID(), ss->fd,
129 PR_GetError()));
130 rv = SECFailure;
131 break;
132 }
133
134 gs->offset += nb;
135 gs->remainder -= nb;
136
137 if (gs->remainder > 0) {
138 continue;
139 }
140
141 /* Probably finished this piece */
142 switch (gs->state) {
143 case GS_HEADER:
144 if ((ss->opt.enableSSL3 || ss->opt.enableTLS) && !ss->firstHsDone) {
145
146 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
147
148 /* If this looks like an SSL3 handshake record,
149 ** and we're expecting an SSL2 Hello message from our peer,
150 ** handle it here.
151 */
152 if (gs->hdr[0] == content_handshake) {
153 if ((ss->nextHandshake == ssl2_HandleClientHelloMessage) ||
154 (ss->nextHandshake == ssl2_HandleServerHelloMessage)) {
155 rv = ssl2_HandleV3HandshakeRecord(ss);
156 if (rv == SECFailure) {
157 return SECFailure;
158 }
159 }
160 /* XXX_1 The call stack to here is:
161 * ssl_Do1stHandshake -> ssl_GatherRecord1stHandshake ->
162 * ssl2_GatherRecord -> here.
163 * We want to return all the way out to ssl_Do1stHandshake,
164 * and have it call ssl_GatherRecord1stHandshake again.
165 * ssl_GatherRecord1stHandshake will call
166 * ssl3_GatherCompleteHandshake when it is called again.
167 *
168 * Returning SECWouldBlock here causes
169 * ssl_GatherRecord1stHandshake to return without clearing
170 * ss->handshake, ensuring that ssl_Do1stHandshake will
171 * call it again immediately.
172 *
173 * If we return 1 here, ssl_GatherRecord1stHandshake will
174 * clear ss->handshake before returning, and thus will not
175 * be called again by ssl_Do1stHandshake.
176 */
177 return SECWouldBlock;
178 } else if (gs->hdr[0] == content_alert) {
179 if (ss->nextHandshake == ssl2_HandleServerHelloMessage) {
180 /* XXX This is a hack. We're assuming that any failure
181 * XXX on the client hello is a failure to match
182 * XXX ciphers.
183 */
184 PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
185 return SECFailure;
186 }
187 }
188 } /* ((ss->opt.enableSSL3 || ss->opt.enableTLS) && !ss->firstHsDon e) */
189
190 /* we've got the first 3 bytes. The header may be two or three. */
191 if (gs->hdr[0] & 0x80) {
192 /* This record has a 2-byte header, and no padding */
193 gs->count = ((gs->hdr[0] & 0x7f) << 8) | gs->hdr[1];
194 gs->recordPadding = 0;
195 } else {
196 /* This record has a 3-byte header that is all read in now. */
197 gs->count = ((gs->hdr[0] & 0x3f) << 8) | gs->hdr[1];
198 /* is_escape = (gs->hdr[0] & 0x40) != 0; */
199 gs->recordPadding = gs->hdr[2];
200 }
201 if (!gs->count) {
202 PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
203 goto cleanup;
204 }
205
206 if (gs->count > gs->buf.space) {
207 err = sslBuffer_Grow(&gs->buf, gs->count);
208 if (err) {
209 return err;
210 }
211 pBuf = gs->buf.buf;
212 }
213
214
215 if (gs->hdr[0] & 0x80) {
216 /* we've already read in the first byte of the body.
217 ** Put it into the buffer.
218 */
219 pBuf[0] = gs->hdr[2];
220 gs->offset = 1;
221 gs->remainder = gs->count - 1;
222 } else {
223 gs->offset = 0;
224 gs->remainder = gs->count;
225 }
226
227 if (gs->encrypted) {
228 gs->state = GS_MAC;
229 gs->recordLen = gs->count - gs->recordPadding
230 - ss->sec.hash->length;
231 } else {
232 gs->state = GS_DATA;
233 gs->recordLen = gs->count;
234 }
235
236 break;
237
238
239 case GS_MAC:
240 /* Have read in entire rest of the ciphertext.
241 ** Check for valid length.
242 ** Decrypt it.
243 ** Check the MAC.
244 */
245 PORT_Assert(gs->encrypted);
246
247 {
248 unsigned int macLen;
249 int nout;
250 unsigned char mac[SSL_MAX_MAC_BYTES];
251
252 ssl_GetSpecReadLock(ss); /**********************************/
253
254 /* If this is a stream cipher, blockSize will be 1,
255 * and this test will always be false.
256 * If this is a block cipher, this will detect records
257 * that are not a multiple of the blocksize in length.
258 */
259 if (gs->count & (ss->sec.blockSize - 1)) {
260 /* This is an error. Sender is misbehaving */
261 SSL_DBG(("%d: SSL[%d]: sender, count=%d blockSize=%d",
262 SSL_GETPID(), ss->fd, gs->count,
263 ss->sec.blockSize));
264 PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING);
265 rv = SECFailure;
266 goto spec_locked_done;
267 }
268 PORT_Assert(gs->count == gs->offset);
269
270 if (gs->offset == 0) {
271 rv = 0; /* means EOF. */
272 goto spec_locked_done;
273 }
274
275 /* Decrypt the portion of data that we just recieved.
276 ** Decrypt it in place.
277 */
278 rv = (*ss->sec.dec)(ss->sec.readcx, pBuf, &nout, gs->offset,
279 pBuf, gs->offset);
280 if (rv != SECSuccess) {
281 goto spec_locked_done;
282 }
283
284
285 /* Have read in all the MAC portion of record
286 **
287 ** Prepare MAC by resetting it and feeding it the shared secret
288 */
289 macLen = ss->sec.hash->length;
290 if (gs->offset >= macLen) {
291 PRUint32 sequenceNumber = ss->sec.rcvSequence++;
292 unsigned char seq[4];
293
294 seq[0] = (unsigned char) (sequenceNumber >> 24);
295 seq[1] = (unsigned char) (sequenceNumber >> 16);
296 seq[2] = (unsigned char) (sequenceNumber >> 8);
297 seq[3] = (unsigned char) (sequenceNumber);
298
299 (*ss->sec.hash->begin)(ss->sec.hashcx);
300 (*ss->sec.hash->update)(ss->sec.hashcx, ss->sec.rcvSecret.data,
301 ss->sec.rcvSecret.len);
302 (*ss->sec.hash->update)(ss->sec.hashcx, pBuf + macLen,
303 gs->offset - macLen);
304 (*ss->sec.hash->update)(ss->sec.hashcx, seq, 4);
305 (*ss->sec.hash->end)(ss->sec.hashcx, mac, &macLen, macLen);
306 }
307
308 PORT_Assert(macLen == ss->sec.hash->length);
309
310 ssl_ReleaseSpecReadLock(ss); /******************************/
311
312 if (NSS_SecureMemcmp(mac, pBuf, macLen) != 0) {
313 /* MAC's didn't match... */
314 SSL_DBG(("%d: SSL[%d]: mac check failed, seq=%d",
315 SSL_GETPID(), ss->fd, ss->sec.rcvSequence));
316 PRINT_BUF(1, (ss, "computed mac:", mac, macLen));
317 PRINT_BUF(1, (ss, "received mac:", pBuf, macLen));
318 PORT_SetError(SSL_ERROR_BAD_MAC_READ);
319 rv = SECFailure;
320 goto cleanup;
321 }
322
323
324 PORT_Assert(gs->recordPadding + macLen <= gs->offset);
325 if (gs->recordPadding + macLen <= gs->offset) {
326 gs->recordOffset = macLen;
327 gs->readOffset = macLen;
328 gs->writeOffset = gs->offset - gs->recordPadding;
329 rv = 1;
330 } else {
331 PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING);
332 cleanup:
333 /* nothing in the buffer any more. */
334 gs->recordOffset = 0;
335 gs->readOffset = 0;
336 gs->writeOffset = 0;
337 rv = SECFailure;
338 }
339
340 gs->recordLen = gs->writeOffset - gs->readOffset;
341 gs->recordPadding = 0; /* forget we did any padding. */
342 gs->state = GS_INIT;
343
344
345 if (rv > 0) {
346 PRINT_BUF(50, (ss, "recv clear record:",
347 pBuf + gs->recordOffset, gs->recordLen));
348 }
349 return rv;
350
351 spec_locked_done:
352 ssl_ReleaseSpecReadLock(ss);
353 return rv;
354 }
355
356 case GS_DATA:
357 /* Have read in all the DATA portion of record */
358
359 gs->recordOffset = 0;
360 gs->readOffset = 0;
361 gs->writeOffset = gs->offset;
362 PORT_Assert(gs->recordLen == gs->writeOffset - gs->readOffset);
363 gs->recordLen = gs->offset;
364 gs->recordPadding = 0;
365 gs->state = GS_INIT;
366
367 ++ss->sec.rcvSequence;
368
369 PRINT_BUF(50, (ss, "recv clear record:",
370 pBuf + gs->recordOffset, gs->recordLen));
371 return 1;
372
373 } /* end switch gs->state */
374 } /* end gather loop. */
375 return rv;
376 }
377
378 /*
379 ** Gather a single record of data from the receiving stream. This code
380 ** first gathers the header (2 or 3 bytes long depending on the value of
381 ** the most significant bit in the first byte) then gathers up the data
382 ** for the record into the readBuf. This code handles non-blocking I/O
383 ** and is to be called multiple times until ss->sec.recordLen != 0.
384 *
385 * Returns +1 when it has gathered a complete SSLV2 record.
386 * Returns 0 if it hits EOF.
387 * Returns -1 (SECFailure) on any error
388 * Returns -2 (SECWouldBlock)
389 *
390 * Called by ssl_GatherRecord1stHandshake in sslcon.c,
391 * and by DoRecv in sslsecur.c
392 * Caller must hold RecvBufLock.
393 */
394 int
395 ssl2_GatherRecord(sslSocket *ss, int flags)
396 {
397 return ssl2_GatherData(ss, &ss->gs, flags);
398 }
399
400 /*
401 * Returns +1 when it has gathered a complete SSLV2 record.
402 * Returns 0 if it hits EOF.
403 * Returns -1 (SECFailure) on any error
404 * Returns -2 (SECWouldBlock)
405 *
406 * Called from SocksStartGather in sslsocks.c
407 * Caller must hold RecvBufLock.
408 */
409 int
410 ssl2_StartGatherBytes(sslSocket *ss, sslGather *gs, unsigned int count)
411 {
412 int rv;
413
414 PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
415 gs->state = GS_DATA;
416 gs->remainder = count;
417 gs->count = count;
418 gs->offset = 0;
419 if (count > gs->buf.space) {
420 rv = sslBuffer_Grow(&gs->buf, count);
421 if (rv) {
422 return rv;
423 }
424 }
425 return ssl2_GatherData(ss, gs, 0);
426 }
427
428 /* Caller should hold RecvBufLock. */
429 SECStatus
430 ssl_InitGather(sslGather *gs)
431 {
432 SECStatus status;
433
434 gs->state = GS_INIT;
435 gs->writeOffset = 0;
436 gs->readOffset = 0;
437 status = sslBuffer_Grow(&gs->buf, 4096);
438 return status;
439 }
440
441 /* Caller must hold RecvBufLock. */
442 void
443 ssl_DestroyGather(sslGather *gs)
444 {
445 if (gs) { /* the PORT_*Free functions check for NULL pointers. */
446 PORT_ZFree(gs->buf.buf, gs->buf.space);
447 PORT_Free(gs->inbuf.buf);
448 }
449 }
450
451 /* Caller must hold RecvBufLock. */
452 static SECStatus
453 ssl2_HandleV3HandshakeRecord(sslSocket *ss)
454 {
455 SECStatus rv;
456 SSL3ProtocolVersion version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2];
457
458 PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
459 PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
460
461 /* We've read in 3 bytes, there are 2 more to go in an ssl3 header. */
462 ss->gs.remainder = 2;
463 ss->gs.count = 0;
464
465 /* Clearing these handshake pointers ensures that
466 * ssl_Do1stHandshake won't call ssl2_HandleMessage when we return.
467 */
468 ss->nextHandshake = 0;
469 ss->securityHandshake = 0;
470
471 /* Setting ss->version to an SSL 3.x value will cause
472 ** ssl_GatherRecord1stHandshake to invoke ssl3_GatherCompleteHandshake()
473 ** the next time it is called.
474 **/
475 rv = ssl3_NegotiateVersion(ss, version);
476 if (rv != SECSuccess) {
477 return rv;
478 }
479
480 ss->sec.send = ssl3_SendApplicationData;
481
482 return SECSuccess;
483 }
OLDNEW
« no previous file with comments | « net/third_party/nss/ssl/sslerr.c ('k') | net/third_party/nss/ssl/sslimpl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698