ech_keygen.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. //go:build with_ech
  2. package tls
  3. import (
  4. "bytes"
  5. "encoding/binary"
  6. "encoding/pem"
  7. cftls "github.com/sagernet/cloudflare-tls"
  8. E "github.com/sagernet/sing/common/exceptions"
  9. "github.com/cloudflare/circl/hpke"
  10. "github.com/cloudflare/circl/kem"
  11. )
  12. func ECHKeygenDefault(serverName string, pqSignatureSchemesEnabled bool) (configPem string, keyPem string, err error) {
  13. cipherSuites := []echCipherSuite{
  14. {
  15. kdf: hpke.KDF_HKDF_SHA256,
  16. aead: hpke.AEAD_AES128GCM,
  17. }, {
  18. kdf: hpke.KDF_HKDF_SHA256,
  19. aead: hpke.AEAD_ChaCha20Poly1305,
  20. },
  21. }
  22. keyConfig := []myECHKeyConfig{
  23. {id: 0, kem: hpke.KEM_X25519_HKDF_SHA256},
  24. }
  25. if pqSignatureSchemesEnabled {
  26. keyConfig = append(keyConfig, myECHKeyConfig{id: 1, kem: hpke.KEM_X25519_KYBER768_DRAFT00})
  27. }
  28. keyPairs, err := echKeygen(0xfe0d, serverName, keyConfig, cipherSuites)
  29. if err != nil {
  30. return
  31. }
  32. var configBuffer bytes.Buffer
  33. var totalLen uint16
  34. for _, keyPair := range keyPairs {
  35. totalLen += uint16(len(keyPair.rawConf))
  36. }
  37. binary.Write(&configBuffer, binary.BigEndian, totalLen)
  38. for _, keyPair := range keyPairs {
  39. configBuffer.Write(keyPair.rawConf)
  40. }
  41. var keyBuffer bytes.Buffer
  42. for _, keyPair := range keyPairs {
  43. keyBuffer.Write(keyPair.rawKey)
  44. }
  45. configPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH CONFIGS", Bytes: configBuffer.Bytes()}))
  46. keyPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBuffer.Bytes()}))
  47. return
  48. }
  49. type echKeyConfigPair struct {
  50. id uint8
  51. key cftls.EXP_ECHKey
  52. rawKey []byte
  53. conf myECHKeyConfig
  54. rawConf []byte
  55. }
  56. type echCipherSuite struct {
  57. kdf hpke.KDF
  58. aead hpke.AEAD
  59. }
  60. type myECHKeyConfig struct {
  61. id uint8
  62. kem hpke.KEM
  63. seed []byte
  64. }
  65. func echKeygen(version uint16, serverName string, conf []myECHKeyConfig, suite []echCipherSuite) ([]echKeyConfigPair, error) {
  66. be := binary.BigEndian
  67. // prepare for future update
  68. if version != 0xfe0d {
  69. return nil, E.New("unsupported ECH version", version)
  70. }
  71. suiteBuf := make([]byte, 0, len(suite)*4+2)
  72. suiteBuf = be.AppendUint16(suiteBuf, uint16(len(suite))*4)
  73. for _, s := range suite {
  74. if !s.kdf.IsValid() || !s.aead.IsValid() {
  75. return nil, E.New("invalid HPKE cipher suite")
  76. }
  77. suiteBuf = be.AppendUint16(suiteBuf, uint16(s.kdf))
  78. suiteBuf = be.AppendUint16(suiteBuf, uint16(s.aead))
  79. }
  80. pairs := []echKeyConfigPair{}
  81. for _, c := range conf {
  82. pair := echKeyConfigPair{}
  83. pair.id = c.id
  84. pair.conf = c
  85. if !c.kem.IsValid() {
  86. return nil, E.New("invalid HPKE KEM")
  87. }
  88. kpGenerator := c.kem.Scheme().GenerateKeyPair
  89. if len(c.seed) > 0 {
  90. kpGenerator = func() (kem.PublicKey, kem.PrivateKey, error) {
  91. pub, sec := c.kem.Scheme().DeriveKeyPair(c.seed)
  92. return pub, sec, nil
  93. }
  94. if len(c.seed) < c.kem.Scheme().PrivateKeySize() {
  95. return nil, E.New("HPKE KEM seed too short")
  96. }
  97. }
  98. pub, sec, err := kpGenerator()
  99. if err != nil {
  100. return nil, E.Cause(err, "generate ECH config key pair")
  101. }
  102. b := []byte{}
  103. b = be.AppendUint16(b, version)
  104. b = be.AppendUint16(b, 0) // length field
  105. // contents
  106. // key config
  107. b = append(b, c.id)
  108. b = be.AppendUint16(b, uint16(c.kem))
  109. pubBuf, err := pub.MarshalBinary()
  110. if err != nil {
  111. return nil, E.Cause(err, "serialize ECH public key")
  112. }
  113. b = be.AppendUint16(b, uint16(len(pubBuf)))
  114. b = append(b, pubBuf...)
  115. b = append(b, suiteBuf...)
  116. // end key config
  117. // max name len, not supported
  118. b = append(b, 0)
  119. // server name
  120. b = append(b, byte(len(serverName)))
  121. b = append(b, []byte(serverName)...)
  122. // extensions, not supported
  123. b = be.AppendUint16(b, 0)
  124. be.PutUint16(b[2:], uint16(len(b)-4))
  125. pair.rawConf = b
  126. secBuf, err := sec.MarshalBinary()
  127. if err != nil {
  128. return nil, E.Cause(err, "serialize ECH private key")
  129. }
  130. sk := []byte{}
  131. sk = be.AppendUint16(sk, uint16(len(secBuf)))
  132. sk = append(sk, secBuf...)
  133. sk = be.AppendUint16(sk, uint16(len(b)))
  134. sk = append(sk, b...)
  135. cfECHKeys, err := cftls.EXP_UnmarshalECHKeys(sk)
  136. if err != nil {
  137. return nil, E.Cause(err, "bug: can't parse generated ECH server key")
  138. }
  139. if len(cfECHKeys) != 1 {
  140. return nil, E.New("bug: unexpected server key count")
  141. }
  142. pair.key = cfECHKeys[0]
  143. pair.rawKey = sk
  144. pairs = append(pairs, pair)
  145. }
  146. return pairs, nil
  147. }