1
0

ech.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package tls
  2. import (
  3. "encoding/base64"
  4. "encoding/pem"
  5. "os"
  6. "github.com/xtls/reality/hpke"
  7. "github.com/xtls/xray-core/common"
  8. "github.com/xtls/xray-core/main/commands/base"
  9. "github.com/xtls/xray-core/transport/internet/tls"
  10. "golang.org/x/crypto/cryptobyte"
  11. )
  12. var cmdECH = &base.Command{
  13. UsageLine: `{{.Exec}} tls ech [--serverName (string)] [--pem] [-i "ECHServerKeys (base64.StdEncoding)"]`,
  14. Short: `Generate TLS-ECH certificates`,
  15. Long: `
  16. Generate TLS-ECH certificates.
  17. Set serverName to your custom string: {{.Exec}} tls ech --serverName (string)
  18. Generate into pem format: {{.Exec}} tls ech --pem
  19. Restore ECHConfigs from ECHServerKeys: {{.Exec}} tls ech -i "ECHServerKeys (base64.StdEncoding)"
  20. `, // Enable PQ signature schemes: {{.Exec}} tls ech --pq-signature-schemes-enabled
  21. }
  22. func init() {
  23. cmdECH.Run = executeECH
  24. }
  25. var input_echServerKeys = cmdECH.Flag.String("i", "", "ECHServerKeys (base64.StdEncoding)")
  26. // var input_pqSignatureSchemesEnabled = cmdECH.Flag.Bool("pqSignatureSchemesEnabled", false, "")
  27. var input_serverName = cmdECH.Flag.String("serverName", "cloudflare-ech.com", "")
  28. var input_pem = cmdECH.Flag.Bool("pem", false, "True == turn on pem output")
  29. func executeECH(cmd *base.Command, args []string) {
  30. var kem uint16
  31. // if *input_pqSignatureSchemesEnabled {
  32. // kem = 0x30 // hpke.KEM_X25519_KYBER768_DRAFT00
  33. // } else {
  34. kem = hpke.DHKEM_X25519_HKDF_SHA256
  35. // }
  36. echConfig, priv, err := tls.GenerateECHKeySet(0, *input_serverName, kem)
  37. common.Must(err)
  38. var configBuffer, keyBuffer []byte
  39. if *input_echServerKeys == "" {
  40. configBytes, _ := tls.MarshalBinary(echConfig)
  41. var b cryptobyte.Builder
  42. b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
  43. child.AddBytes(configBytes)
  44. })
  45. configBuffer, _ = b.Bytes()
  46. var b2 cryptobyte.Builder
  47. b2.AddUint16(uint16(len(priv)))
  48. b2.AddBytes(priv)
  49. b2.AddUint16(uint16(len(configBytes)))
  50. b2.AddBytes(configBytes)
  51. keyBuffer, _ = b2.Bytes()
  52. } else {
  53. keySetsByte, err := base64.StdEncoding.DecodeString(*input_echServerKeys)
  54. if err != nil {
  55. os.Stdout.WriteString("Failed to decode ECHServerKeys: " + err.Error() + "\n")
  56. return
  57. }
  58. keyBuffer = keySetsByte
  59. KeySets, err := tls.ConvertToGoECHKeys(keySetsByte)
  60. if err != nil {
  61. os.Stdout.WriteString("Failed to decode ECHServerKeys: " + err.Error() + "\n")
  62. return
  63. }
  64. var b cryptobyte.Builder
  65. for _, keySet := range KeySets {
  66. b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
  67. child.AddBytes(keySet.Config)
  68. })
  69. }
  70. configBuffer, _ = b.Bytes()
  71. }
  72. if *input_pem {
  73. configPEM := string(pem.EncodeToMemory(&pem.Block{Type: "ECH CONFIGS", Bytes: configBuffer}))
  74. keyPEM := string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBuffer}))
  75. os.Stdout.WriteString(configPEM)
  76. os.Stdout.WriteString(keyPEM)
  77. } else {
  78. os.Stdout.WriteString("ECH config list: \n" + base64.StdEncoding.EncodeToString(configBuffer) + "\n")
  79. os.Stdout.WriteString("ECH server keys: \n" + base64.StdEncoding.EncodeToString(keyBuffer) + "\n")
  80. }
  81. }