-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Multiple enhancements to support DTLS.
This still isn't complete but it's big and I wanted to get it landed. - Support for timeout and retransmission - Support for ACKs - Fixed 0-RTT support in nonblocking mode - Updated the test system to support parametrized tests and used that to simplify and expand the connection tests I also reworked the 0-RTT API to support streaming - When you are a client, and you are in 0-RTT mode, you can Write() when the handshake is not complete - When you are a server and have 0-RTT enabled() you can Read() at any time. Prior to handshake completion, this reads out of the 0-RTT buffer but doesn't cause a network read. After handshake completion, it just does a normal read (with the 0-RTT data buffer having been merged into the main buffer). This has the odd side effect that you can only read 0-RTT data off the network by doing Handshake(), so the way you drive the server is to do: for { server.Handshake() if server connected { break } server.Read() // 0-RTT data } There are still a number of defects that make DTLS not ready for prime time. - No timer backoff - No MTU backoff - I don't properly clean up the out-of-epoch cipher suites [This may be serious] - Finished isn't triggered properly at the end of handshake if loss occurs - There are way too few tests There are probably also a pile of bugs I don't know about.
- Loading branch information
Showing
20 changed files
with
1,399 additions
and
468 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -58,7 +58,7 @@ type clientStateStart struct { | |
cookie []byte | ||
firstClientHello *HandshakeMessage | ||
helloRetryRequest *HandshakeMessage | ||
hsCtx HandshakeContext | ||
hsCtx *HandshakeContext | ||
} | ||
|
||
var _ HandshakeState = &clientStateStart{} | ||
|
@@ -172,8 +172,10 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [ | |
} | ||
ch.CipherSuites = compatibleSuites | ||
|
||
// TODO([email protected]): Check that the ticket can be used for early | ||
// data. | ||
// Signal early data if we're going to do it | ||
if len(state.Opts.EarlyData) > 0 { | ||
if state.Config.AllowEarlyData { | ||
state.Params.ClientSendingEarlyData = true | ||
ed = &EarlyDataExtension{} | ||
err = ch.Extensions.Add(ed) | ||
|
@@ -255,9 +257,6 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [ | |
earlyTrafficSecret := deriveSecret(params, earlySecret, labelEarlyTrafficSecret, chHash) | ||
logf(logTypeCrypto, "early traffic secret: [%d] %x", len(earlyTrafficSecret), earlyTrafficSecret) | ||
clientEarlyTrafficKeys = makeTrafficKeys(params, earlyTrafficSecret) | ||
} else if len(state.Opts.EarlyData) > 0 { | ||
logf(logTypeHandshake, "[ClientStateWaitSH] Early data without PSK") | ||
return nil, nil, AlertInternalError | ||
} else { | ||
clientHello, err = state.hsCtx.hOut.HandshakeMessageFromBody(ch) | ||
if err != nil { | ||
|
@@ -291,7 +290,6 @@ func (state clientStateStart) Next(hr handshakeMessageReader) (HandshakeState, [ | |
if state.Params.ClientSendingEarlyData { | ||
toSend = append(toSend, []HandshakeAction{ | ||
RekeyOut{epoch: EpochEarlyData, KeySet: clientEarlyTrafficKeys}, | ||
SendEarlyData{}, | ||
}...) | ||
} | ||
|
||
|
@@ -302,7 +300,7 @@ type clientStateWaitSH struct { | |
Config *Config | ||
Opts ConnectionOptions | ||
Params ConnectionParameters | ||
hsCtx HandshakeContext | ||
hsCtx *HandshakeContext | ||
OfferedDH map[NamedGroup][]byte | ||
OfferedPSK PreSharedKey | ||
PSK []byte | ||
|
@@ -412,6 +410,11 @@ func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, | |
body: h.Sum(nil), | ||
} | ||
|
||
state.hsCtx.receivedEndOfFlight() | ||
|
||
// TODO([email protected]): Need to rekey with cleartext if we are on 0-RTT | ||
// mode. In DTLS, we also need to bump the sequence number. | ||
// This is a pre-existing defect in Mint. Issue #175. | ||
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateStart]") | ||
return clientStateStart{ | ||
Config: state.Config, | ||
|
@@ -515,7 +518,6 @@ func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, | |
logf(logTypeCrypto, "master secret: [%d] %x", len(masterSecret), masterSecret) | ||
|
||
serverHandshakeKeys := makeTrafficKeys(params, serverHandshakeTrafficSecret) | ||
|
||
logf(logTypeHandshake, "[ClientStateWaitSH] -> [ClientStateWaitEE]") | ||
nextState := clientStateWaitEE{ | ||
Config: state.Config, | ||
|
@@ -530,13 +532,20 @@ func (state clientStateWaitSH) Next(hr handshakeMessageReader) (HandshakeState, | |
toSend := []HandshakeAction{ | ||
RekeyIn{epoch: EpochHandshakeData, KeySet: serverHandshakeKeys}, | ||
} | ||
// We're definitely not going to have to send anything with | ||
// early data. | ||
if !state.Params.ClientSendingEarlyData { | ||
toSend = append(toSend, RekeyOut{epoch: EpochHandshakeData, | ||
KeySet: makeTrafficKeys(params, clientHandshakeTrafficSecret)}) | ||
} | ||
|
||
return nextState, toSend, AlertNoAlert | ||
} | ||
|
||
type clientStateWaitEE struct { | ||
Config *Config | ||
Params ConnectionParameters | ||
hsCtx HandshakeContext | ||
hsCtx *HandshakeContext | ||
cryptoParams CipherSuiteParams | ||
handshakeHash hash.Hash | ||
masterSecret []byte | ||
|
@@ -596,6 +605,14 @@ func (state clientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, | |
|
||
state.handshakeHash.Write(hm.Marshal()) | ||
|
||
toSend := []HandshakeAction{} | ||
|
||
if state.Params.ClientSendingEarlyData && !state.Params.UsingEarlyData { | ||
// We didn't get 0-RTT, so rekey to handshake. | ||
toSend = append(toSend, RekeyOut{epoch: EpochHandshakeData, | ||
KeySet: makeTrafficKeys(state.cryptoParams, state.clientHandshakeTrafficSecret)}) | ||
} | ||
|
||
if state.Params.UsingPSK { | ||
logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitFinished]") | ||
nextState := clientStateWaitFinished{ | ||
|
@@ -608,7 +625,7 @@ func (state clientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, | |
clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, | ||
serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, | ||
} | ||
return nextState, nil, AlertNoAlert | ||
return nextState, toSend, AlertNoAlert | ||
} | ||
|
||
logf(logTypeHandshake, "[ClientStateWaitEE] -> [ClientStateWaitCertCR]") | ||
|
@@ -622,13 +639,13 @@ func (state clientStateWaitEE) Next(hr handshakeMessageReader) (HandshakeState, | |
clientHandshakeTrafficSecret: state.clientHandshakeTrafficSecret, | ||
serverHandshakeTrafficSecret: state.serverHandshakeTrafficSecret, | ||
} | ||
return nextState, nil, AlertNoAlert | ||
return nextState, toSend, AlertNoAlert | ||
} | ||
|
||
type clientStateWaitCertCR struct { | ||
Config *Config | ||
Params ConnectionParameters | ||
hsCtx HandshakeContext | ||
hsCtx *HandshakeContext | ||
cryptoParams CipherSuiteParams | ||
handshakeHash hash.Hash | ||
masterSecret []byte | ||
|
@@ -706,7 +723,7 @@ func (state clientStateWaitCertCR) Next(hr handshakeMessageReader) (HandshakeSta | |
type clientStateWaitCert struct { | ||
Config *Config | ||
Params ConnectionParameters | ||
hsCtx HandshakeContext | ||
hsCtx *HandshakeContext | ||
cryptoParams CipherSuiteParams | ||
handshakeHash hash.Hash | ||
|
||
|
@@ -760,7 +777,7 @@ func (state clientStateWaitCert) Next(hr handshakeMessageReader) (HandshakeState | |
type clientStateWaitCV struct { | ||
Config *Config | ||
Params ConnectionParameters | ||
hsCtx HandshakeContext | ||
hsCtx *HandshakeContext | ||
cryptoParams CipherSuiteParams | ||
handshakeHash hash.Hash | ||
|
||
|
@@ -861,7 +878,7 @@ func (state clientStateWaitCV) Next(hr handshakeMessageReader) (HandshakeState, | |
|
||
type clientStateWaitFinished struct { | ||
Params ConnectionParameters | ||
hsCtx HandshakeContext | ||
hsCtx *HandshakeContext | ||
cryptoParams CipherSuiteParams | ||
handshakeHash hash.Hash | ||
|
||
|
@@ -933,6 +950,7 @@ func (state clientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS | |
toSend := []HandshakeAction{} | ||
|
||
if state.Params.UsingEarlyData { | ||
logf(logTypeHandshake, "Sending end of early data") | ||
// Note: We only send EOED if the server is actually going to use the early | ||
// data. Otherwise, it will never see it, and the transcripts will | ||
// mismatch. | ||
|
@@ -942,10 +960,11 @@ func (state clientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS | |
|
||
state.handshakeHash.Write(eoedm.Marshal()) | ||
logf(logTypeCrypto, "input to handshake hash [%d]: %x", len(eoedm.Marshal()), eoedm.Marshal()) | ||
} | ||
|
||
clientHandshakeKeys := makeTrafficKeys(state.cryptoParams, state.clientHandshakeTrafficSecret) | ||
toSend = append(toSend, RekeyOut{epoch: EpochHandshakeData, KeySet: clientHandshakeKeys}) | ||
// And then rekey to handshake | ||
toSend = append(toSend, RekeyOut{epoch: EpochHandshakeData, | ||
KeySet: makeTrafficKeys(state.cryptoParams, state.clientHandshakeTrafficSecret)}) | ||
} | ||
|
||
if state.Params.UsingClientAuth { | ||
// Extract constraints from certicateRequest | ||
|
@@ -1045,6 +1064,8 @@ func (state clientStateWaitFinished) Next(hr handshakeMessageReader) (HandshakeS | |
RekeyOut{epoch: EpochApplicationData, KeySet: clientTrafficKeys}, | ||
}...) | ||
|
||
state.hsCtx.receivedEndOfFlight() | ||
|
||
logf(logTypeHandshake, "[ClientStateWaitFinished] -> [StateConnected]") | ||
nextState := stateConnected{ | ||
Params: state.Params, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.