ech_shared.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package tls
  2. import (
  3. "crypto/ecdh"
  4. "crypto/rand"
  5. "encoding/pem"
  6. "golang.org/x/crypto/cryptobyte"
  7. )
  8. type ECHCapableConfig interface {
  9. Config
  10. ECHConfigList() []byte
  11. SetECHConfigList([]byte)
  12. }
  13. func ECHKeygenDefault(publicName string) (configPem string, keyPem string, err error) {
  14. echKey, err := ecdh.X25519().GenerateKey(rand.Reader)
  15. if err != nil {
  16. return
  17. }
  18. echConfig, err := marshalECHConfig(0, echKey.PublicKey().Bytes(), publicName, 0)
  19. if err != nil {
  20. return
  21. }
  22. configBuilder := cryptobyte.NewBuilder(nil)
  23. configBuilder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
  24. builder.AddBytes(echConfig)
  25. })
  26. configBytes, err := configBuilder.Bytes()
  27. if err != nil {
  28. return
  29. }
  30. keyBuilder := cryptobyte.NewBuilder(nil)
  31. keyBuilder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
  32. builder.AddBytes(echKey.Bytes())
  33. })
  34. keyBuilder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
  35. builder.AddBytes(echConfig)
  36. })
  37. keyBytes, err := keyBuilder.Bytes()
  38. if err != nil {
  39. return
  40. }
  41. configPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH CONFIGS", Bytes: configBytes}))
  42. keyPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBytes}))
  43. return
  44. }
  45. func marshalECHConfig(id uint8, pubKey []byte, publicName string, maxNameLen uint8) ([]byte, error) {
  46. const extensionEncryptedClientHello = 0xfe0d
  47. const DHKEM_X25519_HKDF_SHA256 = 0x0020
  48. const KDF_HKDF_SHA256 = 0x0001
  49. builder := cryptobyte.NewBuilder(nil)
  50. builder.AddUint16(extensionEncryptedClientHello)
  51. builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
  52. builder.AddUint8(id)
  53. builder.AddUint16(DHKEM_X25519_HKDF_SHA256) // The only DHKEM we support
  54. builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
  55. builder.AddBytes(pubKey)
  56. })
  57. builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
  58. const (
  59. AEAD_AES_128_GCM = 0x0001
  60. AEAD_AES_256_GCM = 0x0002
  61. AEAD_ChaCha20Poly1305 = 0x0003
  62. )
  63. for _, aeadID := range []uint16{AEAD_AES_128_GCM, AEAD_AES_256_GCM, AEAD_ChaCha20Poly1305} {
  64. builder.AddUint16(KDF_HKDF_SHA256) // The only KDF we support
  65. builder.AddUint16(aeadID)
  66. }
  67. })
  68. builder.AddUint8(maxNameLen)
  69. builder.AddUint8LengthPrefixed(func(builder *cryptobyte.Builder) {
  70. builder.AddBytes([]byte(publicName))
  71. })
  72. builder.AddUint16(0) // extensions
  73. })
  74. return builder.Bytes()
  75. }