-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement TLSFlags extension #151
base: cf
Are you sure you want to change the base?
Conversation
It needs some tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to tests. We should at least test that, when the flags are enabled by the client in crypto/tls.Config, the server sees the value in the ClientHello.
Another high-level question: How does this interact with ECH?
- Is the the extension present in both the inner and outer handshake?
- If so, should it appear only in the inner handshake?
@@ -851,6 +858,8 @@ type Config struct { | |||
// See https://tools.ietf.org/html/draft-ietf-tls-subcerts. | |||
SupportDelegatedCredential bool | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document here what TLSFlagSet
is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TLSFlagsSupported
still needs to be documented. It appears that it controls both the client and server-supported flags.
You should document that this is currently limited to controlling TLS Flags in the Server Hello. The spec also allows EncryptedExtensions, Certificate, Hello Retry Request.
type TLSFlag uint16 | ||
|
||
const ( | ||
FlagSupportMTLS TLSFlag = 0x50 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please document what this is. IIRC this is not yet a codepoint that's documented? If so, we should mark it as experimental in the API.
FlagSupportMTLS TLSFlag = 0x50 | |
/// ExperimentalFlagSuppportMTLS ... | |
ExperimentalFlagSupportMTLS TLSFlag = 0x50 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intentional that this flag occupies 11 bytes? 0x50 is 80 decimal, and since we start counting at 0, this occupies ceil(81 / 8) = 11
bytes.
Very good question. |
Added code for server side. |
Currently the extension will be added to the inner handshake only: https://github.com/cloudflare/go/blob/cf/src/crypto/tls/ech.go#L81-L85 Only specific extensions are copied into the outer handshake: https://github.com/cloudflare/go/blob/cf/src/crypto/tls/ech.go#L92-L106 In my opinion, this is the correct behavior, assuming conservatively that the value of the TLS flags extension is privacy sensitive: https://www.ietf.org/archive/id/draft-ietf-tls-esni-16.html#name-outer-clienthello Note that since it appears in the inner handshake, it will be used by the server to terminate the connection. OTOH, if ECH is rejected, then it won't be used by the server to terminate the connection. |
fd0be4b
to
1b8ed4f
Compare
(Rebased on the |
return false | ||
} | ||
m.tlsFlags = append(m.tlsFlags, flagByte) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this whole block can be simplified to:
var flagsList cryptobyte.String
if !extData.ReadUint8LengthPrefixed(&flagsList) || flagsList.Empty() {
return false
}
m.tlsFlags = flagsList
That would save some unnecessary memory allocations as well by avoiding the append
. A cryptobyte.String
is an alias for []byte
: https://pkg.go.dev/golang.org/x/crypto/cryptobyte#String
@@ -318,6 +319,23 @@ GroupSelection: | |||
c.sendAlert(alertIllegalParameter) | |||
return errors.New("tls: invalid client key share") | |||
} | |||
if len(hs.clientHello.tlsFlags) != 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing check: hs.clientHello.tlsFlags[0] != 0
or else you need to c.sendAlert(alertIllegalParameter)
.
To comply with: "An implementation that receives an all-zero value for this extension or a value that contains trailing zero bytes MUST generate a fatal illegal_parameter alert."
if len(hs.clientHello.tlsFlags) != 0 { | ||
supportedFlags, err := encodeFlags(hs.c.config.TLSFlagsSupported) | ||
if err != nil { | ||
return errors.New("tls: invalid server flags") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you should also send an internal error alert here?
@@ -465,6 +466,12 @@ const ( | |||
ECDSAWithSHA1 SignatureScheme = 0x0203 | |||
) | |||
|
|||
type TLSFlag uint16 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make clear that this is the flag number (index) rather than the raw representation:
type TLSFlag uint16 | |
// TLSFlag represents the flag number. | |
type TLSFlag uint16 |
@@ -125,6 +125,7 @@ const ( | |||
extensionRenegotiationInfo uint16 = 0xff01 | |||
extensionECH uint16 = 0xfe0d // draft-ietf-tls-esni-13 | |||
extensionECHOuterExtensions uint16 = 0xfd00 // draft-ietf-tls-esni-13 | |||
extensionTLSFlags uint16 = 0xfe01 // draft-ietf-tls-tlsflags-12 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
0xfe01 (65025) belongs to the "Unassigned" namespace. Unless we have it assigned, we should probably stick to the "Reserved for Private Use" namespace which has a range starting at 0xff02 (65282).
@@ -851,6 +858,8 @@ type Config struct { | |||
// See https://tools.ietf.org/html/draft-ietf-tls-subcerts. | |||
SupportDelegatedCredential bool | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TLSFlagsSupported
still needs to be documented. It appears that it controls both the client and server-supported flags.
You should document that this is currently limited to controlling TLS Flags in the Server Hello. The spec also allows EncryptedExtensions, Certificate, Hello Retry Request.
flagNo := byteIndex*8 + i | ||
if flagNo >= int(maxTLSFlag) { | ||
return nil, fmt.Errorf("TLS flag is out of range: %d", flagNo) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optimization: This check can be removed by checking outside the outer loop. Fail on len(flagBytes) > 255
or alternatively len(flagBytes) * 8 > maxTLSFlag
.
type TLSFlag uint16 | ||
|
||
const ( | ||
FlagSupportMTLS TLSFlag = 0x50 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intentional that this flag occupies 11 bytes? 0x50 is 80 decimal, and since we start counting at 0, this occupies ceil(81 / 8) = 11
bytes.
3086991
to
891ed94
Compare
b071690
to
ead11a3
Compare
Add README Co-authored-by: Peter Wu <[email protected]>
Include the `-cf` tag so this fork can be identified. Include the `devel` tag such that we can potentially add new APIs to the api/next.txt file in order to please the TestDependencies test.
This allows applications to use build tags to maintain compatibility with both this fork as well as standard Go. [ bas 2023-10-6: Fix cfgo build tag and add a test (#156) ]
Tests can be run from the repo with: `docker-compose run test`
[pwu: Go 1.22.0: resolve conflicts: git rm -r .github/ISSUE_TEMPLATE]
The "API check" test requires new APIs to be tracked in api/go1.X.txt or api/next/X.txt. Since Go 1.19 (commit b7041c7), every line in these files also need a comment with the approval issue number. To reduce development friction, we disable the requirement of updating these files when the `-cf` tag is present in the VERSION file.
Add basic support for handshake metrics: * Adds the ability to set a callback via the CFEventHandlerContextKey context value on the handshake context. It will be called at various points during the handshake to respond to various events. See #146. * Use this callback to expose client and server intra-handshake state machine durations, respectively. Each event records elapsed timestamps (durations) for relevant events during the course of a connection, such as reading and writing handshake messages of interest. This will be useful for recording intra-stack costs of TLS extensions such as ECH and KEMTLS. [pwu: Go 1.20.4: moved Config.CFEventHandler to context value] [pwu: Go 1.20.4: moved CFEvent code from tls_cf.go to cfevent.go]
This patch adds: - X25519Kyber768Draft00, this is the de facto standard for early deployment, see https://mailarchive.ietf.org/arch/msg/tls/HAWpNpgptl--UZNSYuvsjB-Pc2k/ https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/02/ - X25519Kyber768Draft00Old, which is the same as the previous, but under an old identifiers. - X25519Kyber512Draft00. This should only be used for testing, whether the smaller shares are advantageous. - P256Kyber768Draft00. Uses a non-standard identifier. Should not be used. Adds CFEvents to detect `HelloRetryRequest`s and to signal which key agreement was used. Co-authored-by: Christopher Wood <[email protected]> Co-authored-by: Peter Wu <[email protected]>
To avoid having to regenerate all testdata files, add an option to control whether PQ signature algorithms are advertised. Tests were added for the client side. Since Go 1.19, FIPS-only mode must remain disabled to enable PQ sigalgs. [pwu: Go 1.17: moved parsePublicKey changes from x509/x509.go to x509/parser.go] [pwu: Go 1.22.5: add eddilithium2 support, fix eddilithium3, by Bas in #176] Co-authored-by: Christopher Patton <[email protected]> Co-authored-by: Peter Wu <[email protected]>
* Define API for delegated credentials so they are fetched using the same mechanisms used to fetch certificates * Allow the usage of other keyUsage when checking for the DC extension. * Add tool for generating delegated credentials. Co-authored-by: Jonathan Hoyland <[email protected]>
Adds support for draft 13 of the Encrypted ClientHello (ECH) extension for TLS. This requires CIRCL to implement draft 08 or later of the HPKE specification (draft-irtf-cfrg-hpke-08). Adds a CFEvent for reporting when ECH is offered or greased by the client, when ECH is accepted or rejected by the server, and when the outer SNI doesn't match the public name of the ECH config. Missing ECH features: * Record-level padding. * Proper validation of the public name by the client. * Retry after rejection. * PSKs are disabled when ECH is accepted.
…o send RTG-2919 [ Bas 1.21.3: Send empty keyshare extension instead of leaving it out ]
In contrast to upstream Go, we will send an HelloRetryRequest and accept an extra roundtrip if there is a more preferred group, than the one the client has provided a keyshare for in the initial ClientHello. Cf. https://datatracker.ietf.org/doc/draft-davidben-tls-key-share-prediction/
DummyKex is a key agreeement similar in size but purposefully incompatible with X25519. The goal is to have a key agreement that servers will not support, so we can test HelloRetryRquest.
ead11a3
to
4092d3f
Compare
This PR implements the first half of the TLS Flags extension.