Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* |
michael@0 | 2 | * Gather (Read) entire SSL3 records from socket into buffer. |
michael@0 | 3 | * |
michael@0 | 4 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 7 | |
michael@0 | 8 | #include "cert.h" |
michael@0 | 9 | #include "ssl.h" |
michael@0 | 10 | #include "sslimpl.h" |
michael@0 | 11 | #include "ssl3prot.h" |
michael@0 | 12 | |
michael@0 | 13 | /* |
michael@0 | 14 | * Attempt to read in an entire SSL3 record. |
michael@0 | 15 | * Blocks here for blocking sockets, otherwise returns -1 with |
michael@0 | 16 | * PR_WOULD_BLOCK_ERROR when socket would block. |
michael@0 | 17 | * |
michael@0 | 18 | * returns 1 if received a complete SSL3 record. |
michael@0 | 19 | * returns 0 if recv returns EOF |
michael@0 | 20 | * returns -1 if recv returns < 0 |
michael@0 | 21 | * (The error value may have already been set to PR_WOULD_BLOCK_ERROR) |
michael@0 | 22 | * |
michael@0 | 23 | * Caller must hold the recv buf lock. |
michael@0 | 24 | * |
michael@0 | 25 | * The Gather state machine has 3 states: GS_INIT, GS_HEADER, GS_DATA. |
michael@0 | 26 | * GS_HEADER: waiting for the 5-byte SSL3 record header to come in. |
michael@0 | 27 | * GS_DATA: waiting for the body of the SSL3 record to come in. |
michael@0 | 28 | * |
michael@0 | 29 | * This loop returns when either |
michael@0 | 30 | * (a) an error or EOF occurs, |
michael@0 | 31 | * (b) PR_WOULD_BLOCK_ERROR, |
michael@0 | 32 | * (c) data (entire SSL3 record) has been received. |
michael@0 | 33 | */ |
michael@0 | 34 | static int |
michael@0 | 35 | ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags) |
michael@0 | 36 | { |
michael@0 | 37 | unsigned char *bp; |
michael@0 | 38 | unsigned char *lbp; |
michael@0 | 39 | int nb; |
michael@0 | 40 | int err; |
michael@0 | 41 | int rv = 1; |
michael@0 | 42 | |
michael@0 | 43 | PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); |
michael@0 | 44 | if (gs->state == GS_INIT) { |
michael@0 | 45 | gs->state = GS_HEADER; |
michael@0 | 46 | gs->remainder = 5; |
michael@0 | 47 | gs->offset = 0; |
michael@0 | 48 | gs->writeOffset = 0; |
michael@0 | 49 | gs->readOffset = 0; |
michael@0 | 50 | gs->inbuf.len = 0; |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | lbp = gs->inbuf.buf; |
michael@0 | 54 | for(;;) { |
michael@0 | 55 | SSL_TRC(30, ("%d: SSL3[%d]: gather state %d (need %d more)", |
michael@0 | 56 | SSL_GETPID(), ss->fd, gs->state, gs->remainder)); |
michael@0 | 57 | bp = ((gs->state != GS_HEADER) ? lbp : gs->hdr) + gs->offset; |
michael@0 | 58 | nb = ssl_DefRecv(ss, bp, gs->remainder, flags); |
michael@0 | 59 | |
michael@0 | 60 | if (nb > 0) { |
michael@0 | 61 | PRINT_BUF(60, (ss, "raw gather data:", bp, nb)); |
michael@0 | 62 | } else if (nb == 0) { |
michael@0 | 63 | /* EOF */ |
michael@0 | 64 | SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd)); |
michael@0 | 65 | rv = 0; |
michael@0 | 66 | break; |
michael@0 | 67 | } else /* if (nb < 0) */ { |
michael@0 | 68 | SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd, |
michael@0 | 69 | PR_GetError())); |
michael@0 | 70 | rv = SECFailure; |
michael@0 | 71 | break; |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | PORT_Assert( nb <= gs->remainder ); |
michael@0 | 75 | if (nb > gs->remainder) { |
michael@0 | 76 | /* ssl_DefRecv is misbehaving! this error is fatal to SSL. */ |
michael@0 | 77 | gs->state = GS_INIT; /* so we don't crash next time */ |
michael@0 | 78 | rv = SECFailure; |
michael@0 | 79 | break; |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | gs->offset += nb; |
michael@0 | 83 | gs->remainder -= nb; |
michael@0 | 84 | if (gs->state == GS_DATA) |
michael@0 | 85 | gs->inbuf.len += nb; |
michael@0 | 86 | |
michael@0 | 87 | /* if there's more to go, read some more. */ |
michael@0 | 88 | if (gs->remainder > 0) { |
michael@0 | 89 | continue; |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | /* have received entire record header, or entire record. */ |
michael@0 | 93 | switch (gs->state) { |
michael@0 | 94 | case GS_HEADER: |
michael@0 | 95 | /* |
michael@0 | 96 | ** Have received SSL3 record header in gs->hdr. |
michael@0 | 97 | ** Now extract the length of the following encrypted data, |
michael@0 | 98 | ** and then read in the rest of the SSL3 record into gs->inbuf. |
michael@0 | 99 | */ |
michael@0 | 100 | gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4]; |
michael@0 | 101 | |
michael@0 | 102 | /* This is the max fragment length for an encrypted fragment |
michael@0 | 103 | ** plus the size of the record header. |
michael@0 | 104 | */ |
michael@0 | 105 | if(gs->remainder > (MAX_FRAGMENT_LENGTH + 2048 + 5)) { |
michael@0 | 106 | SSL3_SendAlert(ss, alert_fatal, unexpected_message); |
michael@0 | 107 | gs->state = GS_INIT; |
michael@0 | 108 | PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); |
michael@0 | 109 | return SECFailure; |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | gs->state = GS_DATA; |
michael@0 | 113 | gs->offset = 0; |
michael@0 | 114 | gs->inbuf.len = 0; |
michael@0 | 115 | |
michael@0 | 116 | if (gs->remainder > gs->inbuf.space) { |
michael@0 | 117 | err = sslBuffer_Grow(&gs->inbuf, gs->remainder); |
michael@0 | 118 | if (err) { /* realloc has set error code to no mem. */ |
michael@0 | 119 | return err; |
michael@0 | 120 | } |
michael@0 | 121 | lbp = gs->inbuf.buf; |
michael@0 | 122 | } |
michael@0 | 123 | break; /* End this case. Continue around the loop. */ |
michael@0 | 124 | |
michael@0 | 125 | |
michael@0 | 126 | case GS_DATA: |
michael@0 | 127 | /* |
michael@0 | 128 | ** SSL3 record has been completely received. |
michael@0 | 129 | */ |
michael@0 | 130 | gs->state = GS_INIT; |
michael@0 | 131 | return 1; |
michael@0 | 132 | } |
michael@0 | 133 | } |
michael@0 | 134 | |
michael@0 | 135 | return rv; |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | /* |
michael@0 | 139 | * Read in an entire DTLS record. |
michael@0 | 140 | * |
michael@0 | 141 | * Blocks here for blocking sockets, otherwise returns -1 with |
michael@0 | 142 | * PR_WOULD_BLOCK_ERROR when socket would block. |
michael@0 | 143 | * |
michael@0 | 144 | * This is simpler than SSL because we are reading on a datagram socket |
michael@0 | 145 | * and datagrams must contain >=1 complete records. |
michael@0 | 146 | * |
michael@0 | 147 | * returns 1 if received a complete DTLS record. |
michael@0 | 148 | * returns 0 if recv returns EOF |
michael@0 | 149 | * returns -1 if recv returns < 0 |
michael@0 | 150 | * (The error value may have already been set to PR_WOULD_BLOCK_ERROR) |
michael@0 | 151 | * |
michael@0 | 152 | * Caller must hold the recv buf lock. |
michael@0 | 153 | * |
michael@0 | 154 | * This loop returns when either |
michael@0 | 155 | * (a) an error or EOF occurs, |
michael@0 | 156 | * (b) PR_WOULD_BLOCK_ERROR, |
michael@0 | 157 | * (c) data (entire DTLS record) has been received. |
michael@0 | 158 | */ |
michael@0 | 159 | static int |
michael@0 | 160 | dtls_GatherData(sslSocket *ss, sslGather *gs, int flags) |
michael@0 | 161 | { |
michael@0 | 162 | int nb; |
michael@0 | 163 | int err; |
michael@0 | 164 | int rv = 1; |
michael@0 | 165 | |
michael@0 | 166 | SSL_TRC(30, ("dtls_GatherData")); |
michael@0 | 167 | |
michael@0 | 168 | PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); |
michael@0 | 169 | |
michael@0 | 170 | gs->state = GS_HEADER; |
michael@0 | 171 | gs->offset = 0; |
michael@0 | 172 | |
michael@0 | 173 | if (gs->dtlsPacketOffset == gs->dtlsPacket.len) { /* No data left */ |
michael@0 | 174 | gs->dtlsPacketOffset = 0; |
michael@0 | 175 | gs->dtlsPacket.len = 0; |
michael@0 | 176 | |
michael@0 | 177 | /* Resize to the maximum possible size so we can fit a full datagram */ |
michael@0 | 178 | /* This is the max fragment length for an encrypted fragment |
michael@0 | 179 | ** plus the size of the record header. |
michael@0 | 180 | ** This magic constant is copied from ssl3_GatherData, with 5 changed |
michael@0 | 181 | ** to 13 (the size of the record header). |
michael@0 | 182 | */ |
michael@0 | 183 | if (gs->dtlsPacket.space < MAX_FRAGMENT_LENGTH + 2048 + 13) { |
michael@0 | 184 | err = sslBuffer_Grow(&gs->dtlsPacket, |
michael@0 | 185 | MAX_FRAGMENT_LENGTH + 2048 + 13); |
michael@0 | 186 | if (err) { /* realloc has set error code to no mem. */ |
michael@0 | 187 | return err; |
michael@0 | 188 | } |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | /* recv() needs to read a full datagram at a time */ |
michael@0 | 192 | nb = ssl_DefRecv(ss, gs->dtlsPacket.buf, gs->dtlsPacket.space, flags); |
michael@0 | 193 | |
michael@0 | 194 | if (nb > 0) { |
michael@0 | 195 | PRINT_BUF(60, (ss, "raw gather data:", gs->dtlsPacket.buf, nb)); |
michael@0 | 196 | } else if (nb == 0) { |
michael@0 | 197 | /* EOF */ |
michael@0 | 198 | SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd)); |
michael@0 | 199 | rv = 0; |
michael@0 | 200 | return rv; |
michael@0 | 201 | } else /* if (nb < 0) */ { |
michael@0 | 202 | SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd, |
michael@0 | 203 | PR_GetError())); |
michael@0 | 204 | rv = SECFailure; |
michael@0 | 205 | return rv; |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | gs->dtlsPacket.len = nb; |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | /* At this point we should have >=1 complete records lined up in |
michael@0 | 212 | * dtlsPacket. Read off the header. |
michael@0 | 213 | */ |
michael@0 | 214 | if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < 13) { |
michael@0 | 215 | SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet " |
michael@0 | 216 | "too short to contain header", SSL_GETPID(), ss->fd)); |
michael@0 | 217 | PR_SetError(PR_WOULD_BLOCK_ERROR, 0); |
michael@0 | 218 | gs->dtlsPacketOffset = 0; |
michael@0 | 219 | gs->dtlsPacket.len = 0; |
michael@0 | 220 | rv = SECFailure; |
michael@0 | 221 | return rv; |
michael@0 | 222 | } |
michael@0 | 223 | memcpy(gs->hdr, gs->dtlsPacket.buf + gs->dtlsPacketOffset, 13); |
michael@0 | 224 | gs->dtlsPacketOffset += 13; |
michael@0 | 225 | |
michael@0 | 226 | /* Have received SSL3 record header in gs->hdr. */ |
michael@0 | 227 | gs->remainder = (gs->hdr[11] << 8) | gs->hdr[12]; |
michael@0 | 228 | |
michael@0 | 229 | if ((gs->dtlsPacket.len - gs->dtlsPacketOffset) < gs->remainder) { |
michael@0 | 230 | SSL_DBG(("%d: SSL3[%d]: rest of DTLS packet too short " |
michael@0 | 231 | "to contain rest of body", SSL_GETPID(), ss->fd)); |
michael@0 | 232 | PR_SetError(PR_WOULD_BLOCK_ERROR, 0); |
michael@0 | 233 | gs->dtlsPacketOffset = 0; |
michael@0 | 234 | gs->dtlsPacket.len = 0; |
michael@0 | 235 | rv = SECFailure; |
michael@0 | 236 | return rv; |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | /* OK, we have at least one complete packet, copy into inbuf */ |
michael@0 | 240 | if (gs->remainder > gs->inbuf.space) { |
michael@0 | 241 | err = sslBuffer_Grow(&gs->inbuf, gs->remainder); |
michael@0 | 242 | if (err) { /* realloc has set error code to no mem. */ |
michael@0 | 243 | return err; |
michael@0 | 244 | } |
michael@0 | 245 | } |
michael@0 | 246 | |
michael@0 | 247 | memcpy(gs->inbuf.buf, gs->dtlsPacket.buf + gs->dtlsPacketOffset, |
michael@0 | 248 | gs->remainder); |
michael@0 | 249 | gs->inbuf.len = gs->remainder; |
michael@0 | 250 | gs->offset = gs->remainder; |
michael@0 | 251 | gs->dtlsPacketOffset += gs->remainder; |
michael@0 | 252 | gs->state = GS_INIT; |
michael@0 | 253 | |
michael@0 | 254 | return 1; |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | /* Gather in a record and when complete, Handle that record. |
michael@0 | 258 | * Repeat this until the handshake is complete, |
michael@0 | 259 | * or until application data is available. |
michael@0 | 260 | * |
michael@0 | 261 | * Returns 1 when the handshake is completed without error, or |
michael@0 | 262 | * application data is available. |
michael@0 | 263 | * Returns 0 if ssl3_GatherData hits EOF. |
michael@0 | 264 | * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. |
michael@0 | 265 | * Returns -2 on SECWouldBlock return from ssl3_HandleRecord. |
michael@0 | 266 | * |
michael@0 | 267 | * Called from ssl_GatherRecord1stHandshake in sslcon.c, |
michael@0 | 268 | * and from SSL_ForceHandshake in sslsecur.c |
michael@0 | 269 | * and from ssl3_GatherAppDataRecord below (<- DoRecv in sslsecur.c). |
michael@0 | 270 | * |
michael@0 | 271 | * Caller must hold the recv buf lock. |
michael@0 | 272 | */ |
michael@0 | 273 | int |
michael@0 | 274 | ssl3_GatherCompleteHandshake(sslSocket *ss, int flags) |
michael@0 | 275 | { |
michael@0 | 276 | SSL3Ciphertext cText; |
michael@0 | 277 | int rv; |
michael@0 | 278 | PRBool keepGoing = PR_TRUE; |
michael@0 | 279 | |
michael@0 | 280 | SSL_TRC(30, ("ssl3_GatherCompleteHandshake")); |
michael@0 | 281 | |
michael@0 | 282 | /* ssl3_HandleRecord may end up eventually calling ssl_FinishHandshake, |
michael@0 | 283 | * which requires the 1stHandshakeLock, which must be acquired before the |
michael@0 | 284 | * RecvBufLock. |
michael@0 | 285 | */ |
michael@0 | 286 | PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); |
michael@0 | 287 | PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); |
michael@0 | 288 | |
michael@0 | 289 | do { |
michael@0 | 290 | PRBool handleRecordNow = PR_FALSE; |
michael@0 | 291 | |
michael@0 | 292 | ssl_GetSSL3HandshakeLock(ss); |
michael@0 | 293 | |
michael@0 | 294 | /* Without this, we may end up wrongly reporting |
michael@0 | 295 | * SSL_ERROR_RX_UNEXPECTED_* errors if we receive any records from the |
michael@0 | 296 | * peer while we are waiting to be restarted. |
michael@0 | 297 | */ |
michael@0 | 298 | if (ss->ssl3.hs.restartTarget) { |
michael@0 | 299 | ssl_ReleaseSSL3HandshakeLock(ss); |
michael@0 | 300 | PORT_SetError(PR_WOULD_BLOCK_ERROR); |
michael@0 | 301 | return (int) SECFailure; |
michael@0 | 302 | } |
michael@0 | 303 | |
michael@0 | 304 | /* Treat an empty msgState like a NULL msgState. (Most of the time |
michael@0 | 305 | * when ssl3_HandleHandshake returns SECWouldBlock, it leaves |
michael@0 | 306 | * behind a non-NULL but zero-length msgState). |
michael@0 | 307 | * Test: async_cert_restart_server_sends_hello_request_first_in_separate_record |
michael@0 | 308 | */ |
michael@0 | 309 | if (ss->ssl3.hs.msgState.buf) { |
michael@0 | 310 | if (ss->ssl3.hs.msgState.len == 0) { |
michael@0 | 311 | ss->ssl3.hs.msgState.buf = NULL; |
michael@0 | 312 | } else { |
michael@0 | 313 | handleRecordNow = PR_TRUE; |
michael@0 | 314 | } |
michael@0 | 315 | } |
michael@0 | 316 | |
michael@0 | 317 | ssl_ReleaseSSL3HandshakeLock(ss); |
michael@0 | 318 | |
michael@0 | 319 | if (handleRecordNow) { |
michael@0 | 320 | /* ssl3_HandleHandshake previously returned SECWouldBlock and the |
michael@0 | 321 | * as-yet-unprocessed plaintext of that previous handshake record. |
michael@0 | 322 | * We need to process it now before we overwrite it with the next |
michael@0 | 323 | * handshake record. |
michael@0 | 324 | */ |
michael@0 | 325 | rv = ssl3_HandleRecord(ss, NULL, &ss->gs.buf); |
michael@0 | 326 | } else { |
michael@0 | 327 | /* bring in the next sslv3 record. */ |
michael@0 | 328 | if (ss->recvdCloseNotify) { |
michael@0 | 329 | /* RFC 5246 Section 7.2.1: |
michael@0 | 330 | * Any data received after a closure alert is ignored. |
michael@0 | 331 | */ |
michael@0 | 332 | return 0; |
michael@0 | 333 | } |
michael@0 | 334 | if (!IS_DTLS(ss)) { |
michael@0 | 335 | rv = ssl3_GatherData(ss, &ss->gs, flags); |
michael@0 | 336 | } else { |
michael@0 | 337 | rv = dtls_GatherData(ss, &ss->gs, flags); |
michael@0 | 338 | |
michael@0 | 339 | /* If we got a would block error, that means that no data was |
michael@0 | 340 | * available, so we check the timer to see if it's time to |
michael@0 | 341 | * retransmit */ |
michael@0 | 342 | if (rv == SECFailure && |
michael@0 | 343 | (PORT_GetError() == PR_WOULD_BLOCK_ERROR)) { |
michael@0 | 344 | ssl_GetSSL3HandshakeLock(ss); |
michael@0 | 345 | dtls_CheckTimer(ss); |
michael@0 | 346 | ssl_ReleaseSSL3HandshakeLock(ss); |
michael@0 | 347 | /* Restore the error in case something succeeded */ |
michael@0 | 348 | PORT_SetError(PR_WOULD_BLOCK_ERROR); |
michael@0 | 349 | } |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | if (rv <= 0) { |
michael@0 | 353 | return rv; |
michael@0 | 354 | } |
michael@0 | 355 | |
michael@0 | 356 | /* decipher it, and handle it if it's a handshake. |
michael@0 | 357 | * If it's application data, ss->gs.buf will not be empty upon return. |
michael@0 | 358 | * If it's a change cipher spec, alert, or handshake message, |
michael@0 | 359 | * ss->gs.buf.len will be 0 when ssl3_HandleRecord returns SECSuccess. |
michael@0 | 360 | */ |
michael@0 | 361 | cText.type = (SSL3ContentType)ss->gs.hdr[0]; |
michael@0 | 362 | cText.version = (ss->gs.hdr[1] << 8) | ss->gs.hdr[2]; |
michael@0 | 363 | |
michael@0 | 364 | if (IS_DTLS(ss)) { |
michael@0 | 365 | int i; |
michael@0 | 366 | |
michael@0 | 367 | cText.version = dtls_DTLSVersionToTLSVersion(cText.version); |
michael@0 | 368 | /* DTLS sequence number */ |
michael@0 | 369 | cText.seq_num.high = 0; cText.seq_num.low = 0; |
michael@0 | 370 | for (i = 0; i < 4; i++) { |
michael@0 | 371 | cText.seq_num.high <<= 8; cText.seq_num.low <<= 8; |
michael@0 | 372 | cText.seq_num.high |= ss->gs.hdr[3 + i]; |
michael@0 | 373 | cText.seq_num.low |= ss->gs.hdr[7 + i]; |
michael@0 | 374 | } |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | cText.buf = &ss->gs.inbuf; |
michael@0 | 378 | rv = ssl3_HandleRecord(ss, &cText, &ss->gs.buf); |
michael@0 | 379 | } |
michael@0 | 380 | if (rv < 0) { |
michael@0 | 381 | return ss->recvdCloseNotify ? 0 : rv; |
michael@0 | 382 | } |
michael@0 | 383 | if (ss->gs.buf.len > 0) { |
michael@0 | 384 | /* We have application data to return to the application. This |
michael@0 | 385 | * prioritizes returning application data to the application over |
michael@0 | 386 | * completing any renegotiation handshake we may be doing. |
michael@0 | 387 | */ |
michael@0 | 388 | PORT_Assert(ss->firstHsDone); |
michael@0 | 389 | PORT_Assert(cText.type == content_application_data); |
michael@0 | 390 | break; |
michael@0 | 391 | } |
michael@0 | 392 | |
michael@0 | 393 | PORT_Assert(keepGoing); |
michael@0 | 394 | ssl_GetSSL3HandshakeLock(ss); |
michael@0 | 395 | if (ss->ssl3.hs.ws == idle_handshake) { |
michael@0 | 396 | /* We are done with the current handshake so stop trying to |
michael@0 | 397 | * handshake. Note that it would be safe to test ss->firstHsDone |
michael@0 | 398 | * instead of ss->ssl3.hs.ws. By testing ss->ssl3.hs.ws instead, |
michael@0 | 399 | * we prioritize completing a renegotiation handshake over sending |
michael@0 | 400 | * application data. |
michael@0 | 401 | */ |
michael@0 | 402 | PORT_Assert(ss->firstHsDone); |
michael@0 | 403 | PORT_Assert(!ss->ssl3.hs.canFalseStart); |
michael@0 | 404 | keepGoing = PR_FALSE; |
michael@0 | 405 | } else if (ss->ssl3.hs.canFalseStart) { |
michael@0 | 406 | /* Prioritize sending application data over trying to complete |
michael@0 | 407 | * the handshake if we're false starting. |
michael@0 | 408 | * |
michael@0 | 409 | * If we were to do this check at the beginning of the loop instead |
michael@0 | 410 | * of here, then this function would become be a no-op after |
michael@0 | 411 | * receiving the ServerHelloDone in the false start case, and we |
michael@0 | 412 | * would never complete the handshake. |
michael@0 | 413 | */ |
michael@0 | 414 | PORT_Assert(!ss->firstHsDone); |
michael@0 | 415 | |
michael@0 | 416 | if (ssl3_WaitingForStartOfServerSecondRound(ss)) { |
michael@0 | 417 | keepGoing = PR_FALSE; |
michael@0 | 418 | } else { |
michael@0 | 419 | ss->ssl3.hs.canFalseStart = PR_FALSE; |
michael@0 | 420 | } |
michael@0 | 421 | } |
michael@0 | 422 | ssl_ReleaseSSL3HandshakeLock(ss); |
michael@0 | 423 | } while (keepGoing); |
michael@0 | 424 | |
michael@0 | 425 | ss->gs.readOffset = 0; |
michael@0 | 426 | ss->gs.writeOffset = ss->gs.buf.len; |
michael@0 | 427 | return 1; |
michael@0 | 428 | } |
michael@0 | 429 | |
michael@0 | 430 | /* Repeatedly gather in a record and when complete, Handle that record. |
michael@0 | 431 | * Repeat this until some application data is received. |
michael@0 | 432 | * |
michael@0 | 433 | * Returns 1 when application data is available. |
michael@0 | 434 | * Returns 0 if ssl3_GatherData hits EOF. |
michael@0 | 435 | * Returns -1 on read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. |
michael@0 | 436 | * Returns -2 on SECWouldBlock return from ssl3_HandleRecord. |
michael@0 | 437 | * |
michael@0 | 438 | * Called from DoRecv in sslsecur.c |
michael@0 | 439 | * Caller must hold the recv buf lock. |
michael@0 | 440 | */ |
michael@0 | 441 | int |
michael@0 | 442 | ssl3_GatherAppDataRecord(sslSocket *ss, int flags) |
michael@0 | 443 | { |
michael@0 | 444 | int rv; |
michael@0 | 445 | |
michael@0 | 446 | /* ssl3_GatherCompleteHandshake requires both of these locks. */ |
michael@0 | 447 | PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); |
michael@0 | 448 | PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); |
michael@0 | 449 | |
michael@0 | 450 | do { |
michael@0 | 451 | rv = ssl3_GatherCompleteHandshake(ss, flags); |
michael@0 | 452 | } while (rv > 0 && ss->gs.buf.len == 0); |
michael@0 | 453 | |
michael@0 | 454 | return rv; |
michael@0 | 455 | } |