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