Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Sources/NIOSSL/QUIC/NIOSSLQUICHandshake.swift
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,16 @@ public final class NIOSSLQUICHandshake {
}
let rc = CNIOBoringSSL_SSL_do_handshake(self.ssl)
if rc == 1 {
// A client that offered 0-RTT reaches SSL_do_handshake == 1 as soon as
// it may send early data, while SSL_in_early_data() is still true and
// the handshake is not yet complete: the server confirms or rejects the
// 0-RTT in its response (RFC 9001 § 4.6.1). Report completion only once
// the client has left the early-data state, so a driver keeps advancing
// to consume that response instead of stopping short and never learning
// whether its 0-RTT was accepted.
if CNIOBoringSSL_SSL_in_early_data(self.ssl) == 1 {
return .wantsMoreData
}
return .complete
}
let result = CNIOBoringSSL_SSL_get_error(self.ssl, rc)
Expand Down
23 changes: 23 additions & 0 deletions Tests/NIOSSLTests/NIOSSLQUICHandshakeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1080,4 +1080,27 @@ final class NIOSSLQUICHandshakeTests: XCTestCase {
XCTAssertTrue(client.handshake.earlyDataAccepted, "the client did not see its 0-RTT accepted")
XCTAssertTrue(server.handshake.earlyDataAccepted, "the server did not accept the offered 0-RTT")
}

func testOfferedEarlyDataStaysInHandshakeUntilConfirmed() throws {
// A client that offers 0-RTT reaches SSL_do_handshake == 1 as soon as it
// may send early data, while the handshake is still in flight: advance()
// must report .wantsMoreData, not .complete, so a driver keeps advancing
// to consume the server's confirmation (RFC 9001 § 4.6.1). Reporting
// completion here would strand the 0-RTT unconfirmed.
let clientContext = try self.makeClientContext()
let serverContext = try self.makeServerContext()
let earlyDataContext = Array("nioquic".utf8)
let session = try self.earlyDataSession(
clientContext: clientContext,
serverContext: serverContext,
earlyDataContext: earlyDataContext
)
let client = try NIOSSLQUICHandshake(
context: clientContext,
role: .client,
localTransportParameters: Self.clientTransportParameters,
resumption: .offerEarlyData(session: session)
)
XCTAssertEqual(try client.advance(), .wantsMoreData)
}
}
Loading