2 * Gather (Read) entire SSL2 records from socket into buffer.
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 /* $Id: sslgathr.c,v 1.15 2012/04/25 14:50:12 gerv%gerv.net Exp $ */
13 /* Forward static declarations */
14 static SECStatus
ssl2_HandleV3HandshakeRecord(sslSocket
*ss
);
17 ** Gather a single record of data from the receiving stream. This code
18 ** first gathers the header (2 or 3 bytes long depending on the value of
19 ** the most significant bit in the first byte) then gathers up the data
20 ** for the record into gs->buf. This code handles non-blocking I/O
21 ** and is to be called multiple times until ss->sec.recordLen != 0.
22 ** This function decrypts the gathered record in place, in gs_buf.
24 * Caller must hold RecvBufLock.
26 * Returns +1 when it has gathered a complete SSLV2 record.
27 * Returns 0 if it hits EOF.
28 * Returns -1 (SECFailure) on any error
29 * Returns -2 (SECWouldBlock) when it gathers an SSL v3 client hello header.
31 ** The SSL2 Gather State machine has 4 states:
32 ** GS_INIT - Done reading in previous record. Haven't begun to read in
33 ** next record. When ssl2_GatherData is called with the machine
34 ** in this state, the machine will attempt to read the first 3
35 ** bytes of the SSL2 record header, and will advance the state
38 ** GS_HEADER - The machine is in this state while waiting for the completion
39 ** of the first 3 bytes of the SSL2 record. When complete, the
40 ** machine will compute the remaining unread length of this record
41 ** and will initiate a read of that many bytes. The machine will
42 ** advance to one of two states, depending on whether the record
43 ** is encrypted (GS_MAC), or unencrypted (GS_DATA).
45 ** GS_MAC - The machine is in this state while waiting for the remainder
46 ** of the SSL2 record to be read in. When the read is completed,
47 ** the machine checks the record for valid length, decrypts it,
48 ** and checks and discards the MAC, then advances to GS_INIT.
50 ** GS_DATA - The machine is in this state while waiting for the remainder
51 ** of the unencrypted SSL2 record to be read in. Upon completion,
52 ** the machine advances to the GS_INIT state and returns the data.
55 ssl2_GatherData(sslSocket
*ss
, sslGather
*gs
, int flags
)
61 PORT_Assert( ss
->opt
.noLocks
|| ssl_HaveRecvBufLock(ss
) );
63 if (gs
->state
== GS_INIT
) {
64 /* Initialize gathering engine */
65 gs
->state
= GS_HEADER
;
70 gs
->recordPadding
= 0;
77 PORT_Assert(ss
->sec
.hash
!= 0);
82 SSL_TRC(30, ("%d: SSL[%d]: gather state %d (need %d more)",
83 SSL_GETPID(), ss
->fd
, gs
->state
, gs
->remainder
));
84 bp
= ((gs
->state
!= GS_HEADER
) ? pBuf
: gs
->hdr
) + gs
->offset
;
85 nb
= ssl_DefRecv(ss
, bp
, gs
->remainder
, flags
);
87 PRINT_BUF(60, (ss
, "raw gather data:", bp
, nb
));
91 SSL_TRC(30, ("%d: SSL[%d]: EOF", SSL_GETPID(), ss
->fd
));
96 SSL_DBG(("%d: SSL[%d]: recv error %d", SSL_GETPID(), ss
->fd
,
105 if (gs
->remainder
> 0) {
109 /* Probably finished this piece */
112 if (!SSL3_ALL_VERSIONS_DISABLED(&ss
->vrange
) && !ss
->firstHsDone
) {
114 PORT_Assert( ss
->opt
.noLocks
|| ssl_Have1stHandshakeLock(ss
) );
116 /* If this looks like an SSL3 handshake record,
117 ** and we're expecting an SSL2 Hello message from our peer,
120 if (gs
->hdr
[0] == content_handshake
) {
121 if ((ss
->nextHandshake
== ssl2_HandleClientHelloMessage
) ||
122 (ss
->nextHandshake
== ssl2_HandleServerHelloMessage
)) {
123 rv
= ssl2_HandleV3HandshakeRecord(ss
);
124 if (rv
== SECFailure
) {
128 /* XXX_1 The call stack to here is:
129 * ssl_Do1stHandshake -> ssl_GatherRecord1stHandshake ->
130 * ssl2_GatherRecord -> here.
131 * We want to return all the way out to ssl_Do1stHandshake,
132 * and have it call ssl_GatherRecord1stHandshake again.
133 * ssl_GatherRecord1stHandshake will call
134 * ssl3_GatherCompleteHandshake when it is called again.
136 * Returning SECWouldBlock here causes
137 * ssl_GatherRecord1stHandshake to return without clearing
138 * ss->handshake, ensuring that ssl_Do1stHandshake will
139 * call it again immediately.
141 * If we return 1 here, ssl_GatherRecord1stHandshake will
142 * clear ss->handshake before returning, and thus will not
143 * be called again by ssl_Do1stHandshake.
145 return SECWouldBlock
;
146 } else if (gs
->hdr
[0] == content_alert
) {
147 if (ss
->nextHandshake
== ssl2_HandleServerHelloMessage
) {
148 /* XXX This is a hack. We're assuming that any failure
149 * XXX on the client hello is a failure to match
152 PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP
);
158 /* we've got the first 3 bytes. The header may be two or three. */
159 if (gs
->hdr
[0] & 0x80) {
160 /* This record has a 2-byte header, and no padding */
161 gs
->count
= ((gs
->hdr
[0] & 0x7f) << 8) | gs
->hdr
[1];
162 gs
->recordPadding
= 0;
164 /* This record has a 3-byte header that is all read in now. */
165 gs
->count
= ((gs
->hdr
[0] & 0x3f) << 8) | gs
->hdr
[1];
166 /* is_escape = (gs->hdr[0] & 0x40) != 0; */
167 gs
->recordPadding
= gs
->hdr
[2];
170 PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG
);
174 if (gs
->count
> gs
->buf
.space
) {
175 err
= sslBuffer_Grow(&gs
->buf
, gs
->count
);
183 if (gs
->hdr
[0] & 0x80) {
184 /* we've already read in the first byte of the body.
185 ** Put it into the buffer.
187 pBuf
[0] = gs
->hdr
[2];
189 gs
->remainder
= gs
->count
- 1;
192 gs
->remainder
= gs
->count
;
197 gs
->recordLen
= gs
->count
- gs
->recordPadding
198 - ss
->sec
.hash
->length
;
201 gs
->recordLen
= gs
->count
;
208 /* Have read in entire rest of the ciphertext.
209 ** Check for valid length.
213 PORT_Assert(gs
->encrypted
);
218 unsigned char mac
[SSL_MAX_MAC_BYTES
];
220 ssl_GetSpecReadLock(ss
); /**********************************/
222 /* If this is a stream cipher, blockSize will be 1,
223 * and this test will always be false.
224 * If this is a block cipher, this will detect records
225 * that are not a multiple of the blocksize in length.
227 if (gs
->count
& (ss
->sec
.blockSize
- 1)) {
228 /* This is an error. Sender is misbehaving */
229 SSL_DBG(("%d: SSL[%d]: sender, count=%d blockSize=%d",
230 SSL_GETPID(), ss
->fd
, gs
->count
,
232 PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING
);
234 goto spec_locked_done
;
236 PORT_Assert(gs
->count
== gs
->offset
);
238 if (gs
->offset
== 0) {
239 rv
= 0; /* means EOF. */
240 goto spec_locked_done
;
243 /* Decrypt the portion of data that we just received.
244 ** Decrypt it in place.
246 rv
= (*ss
->sec
.dec
)(ss
->sec
.readcx
, pBuf
, &nout
, gs
->offset
,
248 if (rv
!= SECSuccess
) {
249 goto spec_locked_done
;
253 /* Have read in all the MAC portion of record
255 ** Prepare MAC by resetting it and feeding it the shared secret
257 macLen
= ss
->sec
.hash
->length
;
258 if (gs
->offset
>= macLen
) {
259 PRUint32 sequenceNumber
= ss
->sec
.rcvSequence
++;
260 unsigned char seq
[4];
262 seq
[0] = (unsigned char) (sequenceNumber
>> 24);
263 seq
[1] = (unsigned char) (sequenceNumber
>> 16);
264 seq
[2] = (unsigned char) (sequenceNumber
>> 8);
265 seq
[3] = (unsigned char) (sequenceNumber
);
267 (*ss
->sec
.hash
->begin
)(ss
->sec
.hashcx
);
268 (*ss
->sec
.hash
->update
)(ss
->sec
.hashcx
, ss
->sec
.rcvSecret
.data
,
269 ss
->sec
.rcvSecret
.len
);
270 (*ss
->sec
.hash
->update
)(ss
->sec
.hashcx
, pBuf
+ macLen
,
271 gs
->offset
- macLen
);
272 (*ss
->sec
.hash
->update
)(ss
->sec
.hashcx
, seq
, 4);
273 (*ss
->sec
.hash
->end
)(ss
->sec
.hashcx
, mac
, &macLen
, macLen
);
275 PORT_Assert(macLen
== ss
->sec
.hash
->length
);
277 ssl_ReleaseSpecReadLock(ss
); /******************************/
279 if (NSS_SecureMemcmp(mac
, pBuf
, macLen
) != 0) {
280 /* MAC's didn't match... */
281 SSL_DBG(("%d: SSL[%d]: mac check failed, seq=%d",
282 SSL_GETPID(), ss
->fd
, ss
->sec
.rcvSequence
));
283 PRINT_BUF(1, (ss
, "computed mac:", mac
, macLen
));
284 PRINT_BUF(1, (ss
, "received mac:", pBuf
, macLen
));
285 PORT_SetError(SSL_ERROR_BAD_MAC_READ
);
290 ssl_ReleaseSpecReadLock(ss
); /******************************/
293 if (gs
->recordPadding
+ macLen
<= gs
->offset
) {
294 gs
->recordOffset
= macLen
;
295 gs
->readOffset
= macLen
;
296 gs
->writeOffset
= gs
->offset
- gs
->recordPadding
;
299 PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING
);
301 /* nothing in the buffer any more. */
302 gs
->recordOffset
= 0;
308 gs
->recordLen
= gs
->writeOffset
- gs
->readOffset
;
309 gs
->recordPadding
= 0; /* forget we did any padding. */
314 PRINT_BUF(50, (ss
, "recv clear record:",
315 pBuf
+ gs
->recordOffset
, gs
->recordLen
));
320 ssl_ReleaseSpecReadLock(ss
);
325 /* Have read in all the DATA portion of record */
327 gs
->recordOffset
= 0;
329 gs
->writeOffset
= gs
->offset
;
330 PORT_Assert(gs
->recordLen
== gs
->writeOffset
- gs
->readOffset
);
331 gs
->recordLen
= gs
->offset
;
332 gs
->recordPadding
= 0;
335 ++ss
->sec
.rcvSequence
;
337 PRINT_BUF(50, (ss
, "recv clear record:",
338 pBuf
+ gs
->recordOffset
, gs
->recordLen
));
341 } /* end switch gs->state */
342 } /* end gather loop. */
347 ** Gather a single record of data from the receiving stream. This code
348 ** first gathers the header (2 or 3 bytes long depending on the value of
349 ** the most significant bit in the first byte) then gathers up the data
350 ** for the record into the readBuf. This code handles non-blocking I/O
351 ** and is to be called multiple times until ss->sec.recordLen != 0.
353 * Returns +1 when it has gathered a complete SSLV2 record.
354 * Returns 0 if it hits EOF.
355 * Returns -1 (SECFailure) on any error
356 * Returns -2 (SECWouldBlock)
358 * Called by ssl_GatherRecord1stHandshake in sslcon.c,
359 * and by DoRecv in sslsecur.c
360 * Caller must hold RecvBufLock.
363 ssl2_GatherRecord(sslSocket
*ss
, int flags
)
365 return ssl2_GatherData(ss
, &ss
->gs
, flags
);
369 * Returns +1 when it has gathered a complete SSLV2 record.
370 * Returns 0 if it hits EOF.
371 * Returns -1 (SECFailure) on any error
372 * Returns -2 (SECWouldBlock)
374 * Called from SocksStartGather in sslsocks.c
375 * Caller must hold RecvBufLock.
378 ssl2_StartGatherBytes(sslSocket
*ss
, sslGather
*gs
, unsigned int count
)
382 PORT_Assert( ss
->opt
.noLocks
|| ssl_HaveRecvBufLock(ss
) );
384 gs
->remainder
= count
;
387 if (count
> gs
->buf
.space
) {
388 rv
= sslBuffer_Grow(&gs
->buf
, count
);
393 return ssl2_GatherData(ss
, gs
, 0);
396 /* Caller should hold RecvBufLock. */
398 ssl_InitGather(sslGather
*gs
)
405 gs
->dtlsPacketOffset
= 0;
406 gs
->dtlsPacket
.len
= 0;
407 status
= sslBuffer_Grow(&gs
->buf
, 4096);
411 /* Caller must hold RecvBufLock. */
413 ssl_DestroyGather(sslGather
*gs
)
415 if (gs
) { /* the PORT_*Free functions check for NULL pointers. */
416 PORT_ZFree(gs
->buf
.buf
, gs
->buf
.space
);
417 PORT_Free(gs
->inbuf
.buf
);
418 PORT_Free(gs
->dtlsPacket
.buf
);
422 /* Caller must hold RecvBufLock. */
424 ssl2_HandleV3HandshakeRecord(sslSocket
*ss
)
428 PORT_Assert( ss
->opt
.noLocks
|| ssl_HaveRecvBufLock(ss
) );
429 PORT_Assert( ss
->opt
.noLocks
|| ssl_Have1stHandshakeLock(ss
) );
431 /* We've read in 3 bytes, there are 2 more to go in an ssl3 header. */
432 ss
->gs
.remainder
= 2;
435 /* Clearing these handshake pointers ensures that
436 * ssl_Do1stHandshake won't call ssl2_HandleMessage when we return.
438 ss
->nextHandshake
= 0;
439 ss
->securityHandshake
= 0;
441 /* Setting ss->version to an SSL 3.x value will cause
442 ** ssl_GatherRecord1stHandshake to invoke ssl3_GatherCompleteHandshake()
443 ** the next time it is called.
445 rv
= ssl3_NegotiateVersion(ss
, SSL_LIBRARY_VERSION_MAX_SUPPORTED
,
447 if (rv
!= SECSuccess
) {
451 ss
->sec
.send
= ssl3_SendApplicationData
;