Skip to content
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

Upgrade ECH target to draft-ietf-tls-esni-10 #44

Closed
wants to merge 2 commits into from
Closed
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
13 changes: 13 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/bash

if [ "$#" -ne 2 ]; then
echo "usage: $0 <client> <server>"
echo
echo "where <client> and <server> are one of the following:"
echo "boringssl, cloudflare-go, nss, rustls"
exit 1
fi

env SERVER_SRC=./impl-endpoints SERVER=$2 \
CLIENT_SRC=./impl-endpoints CLIENT=$1 \
docker-compose build
3 changes: 2 additions & 1 deletion cmd/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ func main() {
} else if *makeECH {
err = utils.MakeECHKey(
utils.ECHConfigTemplate{
Id: 123, // This is chosen at random by the client-facing server.
PublicName: *hostName,
Version: utils.ECHVersionDraft09,
Version: utils.ECHVersionDraft10,
KemId: uint16(hpke.KEM_X25519_HKDF_SHA256),
KdfIds: []uint16{
uint16(hpke.KDF_HKDF_SHA256),
Expand Down
4 changes: 2 additions & 2 deletions impl-endpoints/cloudflare-go/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ FROM golang:latest AS builder

RUN apt-get update && \
apt-get install git
RUN git clone https://github.com/cloudflare/go /cf
RUN git clone --branch cf https://github.com/cloudflare/go /cf

WORKDIR /cf/src
RUN git checkout 2a17ea31d28264fccfec4e59dc2ac733b6c73dec
RUN git checkout 7c96cb688f153fcbd51bb2c2e2e38f85820ee5c7
RUN ./make.bash

FROM ubuntu:20.04
Expand Down
2 changes: 1 addition & 1 deletion impl-endpoints/nss/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ RUN cd /build \
&& hg clone https://hg.mozilla.org/projects/nspr \
--rev b09175587dad2bfb923ec87250ac80461f620577 \
&& hg clone https://hg.mozilla.org/projects/nss \
--rev 38a91427d65fffd0d7f7d2b6d0bcee7dc8b77a37 \
&& cd nss \
&& hg pull -u -r 98542d9c204f8e91336f0a36239d776d82dc8989 https://hg.mozilla.org/projects/nss-try \

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string and cellotape!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These change will be reverted once your PR lands.

&& ./build.sh -Denable_draft_hpke=1 \
&& cd /

Expand Down
39 changes: 26 additions & 13 deletions impl-endpoints/nss/ech_key_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

* struct {
* opaque pkcs8_ech_keypair<0..2^16-1>;
* ECHConfigs configs<0..2^16>; // draft-ietf-tls-esni-09
* ECHConfigList configs<0..2^16>; // draft-ietf-tls-esni-09
* } ECHKey;
"""

import sys
import struct
import base64

ECH_VERSION = 0xFE09
ECH_VERSION = 0xFE0A
DHKEM_X25519_SHA256 = 0x0020

# Hardcoded ASN.1 for ECPrivateKey, curve25519. See section 2 of rfc5958.
Expand All @@ -30,42 +30,55 @@ def convert_ech_key(in_file, out_file):
ech_keypair = base64.b64decode(f.read(), None, True)

offset = 0

# Parse the private key.
length = struct.unpack("!H", ech_keypair[:2])[0]
offset += 2
private_key = ech_keypair[offset : offset + length]
offset += length

ech_configs = ech_keypair[offset:]
# Encode the ECHConfigList that will be output.
ech_config_list = ech_keypair[offset:]

# Parse the public key out of the ECHConfig.
# Parse the length of the ECHConfigList.
length = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
offset += 2

# Parse ECHConfig.version, where ECHConfig is the first configuration in
# ECHConfigList.
version = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
offset += 2

# Verify that the version number is as expected.
if version != ECH_VERSION:
print("ECHConfig.version is not 0xFE09: %x", hex(version))
print("ECHConfig.version is not 0xfe0a: got", hex(version))
exit(1)

# Parse ECHConfig.Length, which indicates the length of
# ECHConfig.contents.
length = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
offset += 2

# Public name
length = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
offset += 2 + length
# Parse ECHConfig.contents.key_config.config_id.
config_id = struct.unpack("!B", ech_keypair[offset : offset + 1])[0]
offset += 1

# Public key
length = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
# Parse ECHConfig.contents.key_config.kem_id.
kem_id = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
offset += 2
public_key = ech_keypair[offset : offset + length]
offset += length

# Verify that the KEM is X25519. We don't support anything else.
kem_id = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
if kem_id != DHKEM_X25519_SHA256:
print("Unsupported KEM ID: %x", hex(kem_id))
exit(1)

# Parse ECHConfig.contents.key_config.public_key.
length = struct.unpack("!H", ech_keypair[offset : offset + 2])[0]
offset += 2
public_key = ech_keypair[offset : offset + length]
offset += length

pkcs8 = bytearray()
pkcs8 += (
bytearray(pkcs8_start)
Expand All @@ -75,7 +88,7 @@ def convert_ech_key(in_file, out_file):
)

out_bytes = bytearray()
out_bytes += struct.pack("!H", len(pkcs8)) + pkcs8 + ech_configs
out_bytes += struct.pack("!H", len(pkcs8)) + pkcs8 + ech_config_list

out = open(out_file, "wb")
out.write(base64.b64encode(out_bytes))
Expand Down
16 changes: 10 additions & 6 deletions internal/utils/ech.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import (
)

const (
ECHVersionDraft09 uint16 = 0xfe09 // draft-ietf-tls-esni-09
ECHVersionDraft10 uint16 = 0xfe0a // draft-ietf-tls-esni-10
)

// ECHConfigTemplate defines the parameters for generating an ECH config and
// corresponding key.
type ECHConfigTemplate struct {
// The 1-byte configuration identifier.
Id uint8

// The version of ECH to use for this configuration.
Version uint16

Expand Down Expand Up @@ -65,7 +68,7 @@ type ECHKey struct {
// GenerateECHKey generates an ECH config and corresponding key using the
// parameters specified by template.
func GenerateECHKey(template ECHConfigTemplate) (*ECHKey, error) {
if template.Version != ECHVersionDraft09 {
if template.Version != ECHVersionDraft10 {
return nil, errors.New("template version not supported")
}

Expand All @@ -92,13 +95,11 @@ func GenerateECHKey(template ECHConfigTemplate) (*ECHKey, error) {
var c cryptobyte.Builder
c.AddUint16(template.Version)
c.AddUint16LengthPrefixed(func(c *cryptobyte.Builder) { // contents
c.AddUint16LengthPrefixed(func(c *cryptobyte.Builder) {
c.AddBytes([]byte(template.PublicName))
})
c.AddUint8(template.Id)
c.AddUint16(template.KemId)
c.AddUint16LengthPrefixed(func(c *cryptobyte.Builder) {
c.AddBytes(publicKey)
})
c.AddUint16(template.KemId)
c.AddUint16LengthPrefixed(func(c *cryptobyte.Builder) {
for _, kdfId := range template.KdfIds {
for _, aeadId := range template.AeadIds {
Expand All @@ -108,6 +109,9 @@ func GenerateECHKey(template ECHConfigTemplate) (*ECHKey, error) {
}
})
c.AddUint16(template.MaximumNameLength)
c.AddUint16LengthPrefixed(func(c *cryptobyte.Builder) {
c.AddBytes([]byte(template.PublicName))
})
c.AddUint16LengthPrefixed(func(c *cryptobyte.Builder) {
c.AddBytes(template.Extensions)
})
Expand Down
23 changes: 23 additions & 0 deletions run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

# After typing Ctrl-C, Docker waits this number of seconds to interrupt the
# containers.
TIMEOUT=0

if [ "$#" -ne 3 ]; then
echo "usage: $0 <client> <server> <testcase>"
echo
echo "where <client> and <server> are one of the following:"
echo "boringssl, cloudflare-go, nss, rustls"
echo
echo "and <testcase> is one of the following:"
echo "dc, ech-accept, ech-reject"
exit 1
fi

env SERVER_SRC=./impl-endpoints SERVER=$2 \
CLIENT_SRC=./impl-endpoints CLIENT=$1 \
TESTCASE=$3 \
docker-compose up --timeout $TIMEOUT

docker-compose stop