github.com/3andne/restls-client-go@v0.1.6/u_quic.go (about) 1 // Copyright 2023 The uTLS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package tls 6 7 import ( 8 "context" 9 "errors" 10 ) 11 12 // A UQUICConn represents a connection which uses a QUIC implementation as the underlying 13 // transport as described in RFC 9001. 14 // 15 // Methods of UQUICConn are not safe for concurrent use. 16 type UQUICConn struct { 17 conn *UConn 18 19 sessionTicketSent bool 20 } 21 22 // QUICClient returns a new TLS client side connection using QUICTransport as the 23 // underlying transport. The config cannot be nil. 24 // 25 // The config's MinVersion must be at least TLS 1.3. 26 func UQUICClient(config *QUICConfig, clientHelloID ClientHelloID) *UQUICConn { 27 return newUQUICConn(UClient(nil, config.TLSConfig, clientHelloID)) 28 } 29 30 func newUQUICConn(uconn *UConn) *UQUICConn { 31 uconn.quic = &quicState{ 32 signalc: make(chan struct{}), 33 blockedc: make(chan struct{}), 34 } 35 uconn.quic.events = uconn.quic.eventArr[:0] 36 return &UQUICConn{ 37 conn: uconn, 38 } 39 } 40 41 // Start starts the client or server handshake protocol. 42 // It may produce connection events, which may be read with NextEvent. 43 // 44 // Start must be called at most once. 45 func (q *UQUICConn) Start(ctx context.Context) error { 46 if q.conn.quic.started { 47 return quicError(errors.New("tls: Start called more than once")) 48 } 49 q.conn.quic.started = true 50 if q.conn.config.MinVersion < VersionTLS13 { 51 return quicError(errors.New("tls: Config MinVersion must be at least TLS 1.13")) 52 } 53 go q.conn.HandshakeContext(ctx) 54 if _, ok := <-q.conn.quic.blockedc; !ok { 55 return q.conn.handshakeErr 56 } 57 return nil 58 } 59 60 func (q *UQUICConn) ApplyPreset(p *ClientHelloSpec) error { 61 return q.conn.ApplyPreset(p) 62 } 63 64 // NextEvent returns the next event occurring on the connection. 65 // It returns an event with a Kind of QUICNoEvent when no events are available. 66 func (q *UQUICConn) NextEvent() QUICEvent { 67 qs := q.conn.quic 68 if last := qs.nextEvent - 1; last >= 0 && len(qs.events[last].Data) > 0 { 69 // Write over some of the previous event's data, 70 // to catch callers erroniously retaining it. 71 qs.events[last].Data[0] = 0 72 } 73 if qs.nextEvent >= len(qs.events) { 74 qs.events = qs.events[:0] 75 qs.nextEvent = 0 76 return QUICEvent{Kind: QUICNoEvent} 77 } 78 e := qs.events[qs.nextEvent] 79 qs.events[qs.nextEvent] = QUICEvent{} // zero out references to data 80 qs.nextEvent++ 81 return e 82 } 83 84 // Close closes the connection and stops any in-progress handshake. 85 func (q *UQUICConn) Close() error { 86 if q.conn.quic.cancel == nil { 87 return nil // never started 88 } 89 q.conn.quic.cancel() 90 for range q.conn.quic.blockedc { 91 // Wait for the handshake goroutine to return. 92 } 93 return q.conn.handshakeErr 94 } 95 96 // HandleData handles handshake bytes received from the peer. 97 // It may produce connection events, which may be read with NextEvent. 98 func (q *UQUICConn) HandleData(level QUICEncryptionLevel, data []byte) error { 99 c := q.conn 100 if c.in.level != level { 101 return quicError(c.in.setErrorLocked(errors.New("tls: handshake data received at wrong level"))) 102 } 103 c.quic.readbuf = data 104 <-c.quic.signalc 105 _, ok := <-c.quic.blockedc 106 if ok { 107 // The handshake goroutine is waiting for more data. 108 return nil 109 } 110 // The handshake goroutine has exited. 111 c.hand.Write(c.quic.readbuf) 112 c.quic.readbuf = nil 113 for q.conn.hand.Len() >= 4 && q.conn.handshakeErr == nil { 114 b := q.conn.hand.Bytes() 115 n := int(b[1])<<16 | int(b[2])<<8 | int(b[3]) 116 if 4+n < len(b) { 117 return nil 118 } 119 if err := q.conn.handlePostHandshakeMessage(); err != nil { 120 return quicError(err) 121 } 122 } 123 if q.conn.handshakeErr != nil { 124 return quicError(q.conn.handshakeErr) 125 } 126 return nil 127 } 128 129 // SendSessionTicket sends a session ticket to the client. 130 // It produces connection events, which may be read with NextEvent. 131 // Currently, it can only be called once. 132 func (q *UQUICConn) SendSessionTicket(earlyData bool) error { 133 c := q.conn 134 if !c.isHandshakeComplete.Load() { 135 return quicError(errors.New("tls: SendSessionTicket called before handshake completed")) 136 } 137 if c.isClient { 138 return quicError(errors.New("tls: SendSessionTicket called on the client")) 139 } 140 if q.sessionTicketSent { 141 return quicError(errors.New("tls: SendSessionTicket called multiple times")) 142 } 143 q.sessionTicketSent = true 144 return quicError(c.sendSessionTicket(earlyData)) 145 } 146 147 // ConnectionState returns basic TLS details about the connection. 148 func (q *UQUICConn) ConnectionState() ConnectionState { 149 return q.conn.ConnectionState() 150 } 151 152 // SetTransportParameters sets the transport parameters to send to the peer. 153 // 154 // Server connections may delay setting the transport parameters until after 155 // receiving the client's transport parameters. See QUICTransportParametersRequired. 156 func (q *UQUICConn) SetTransportParameters(params []byte) { 157 if params == nil { 158 params = []byte{} 159 } 160 q.conn.quic.transportParams = params // this won't be used for building ClientHello when using a preset 161 162 // // instead, we set the transport parameters hold by the ClientHello 163 // for _, ext := range q.conn.Extensions { 164 // if qtp, ok := ext.(*QUICTransportParametersExtension); ok { 165 // qtp.TransportParametersExtData = params 166 // } 167 // } 168 169 if q.conn.quic.started { 170 <-q.conn.quic.signalc 171 <-q.conn.quic.blockedc 172 } 173 } 174 175 func (uc *UConn) QUICSetReadSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { 176 uc.quic.events = append(uc.quic.events, QUICEvent{ 177 Kind: QUICSetReadSecret, 178 Level: level, 179 Suite: suite, 180 Data: secret, 181 }) 182 } 183 184 func (uc *UConn) QUICSetWriteSecret(level QUICEncryptionLevel, suite uint16, secret []byte) { 185 uc.quic.events = append(uc.quic.events, QUICEvent{ 186 Kind: QUICSetWriteSecret, 187 Level: level, 188 Suite: suite, 189 Data: secret, 190 }) 191 } 192 193 func (uc *UConn) QUICGetTransportParameters() ([]byte, error) { 194 if uc.quic.transportParams == nil { 195 uc.quic.events = append(uc.quic.events, QUICEvent{ 196 Kind: QUICTransportParametersRequired, 197 }) 198 } 199 for uc.quic.transportParams == nil { 200 if err := uc.quicWaitForSignal(); err != nil { 201 return nil, err 202 } 203 } 204 return uc.quic.transportParams, nil 205 }