Source file
src/crypto/tls/key_agreement.go
1
2
3
4
5 package tls
6
7 import (
8 "crypto"
9 "crypto/ecdh"
10 "crypto/md5"
11 "crypto/rsa"
12 "crypto/sha1"
13 "crypto/x509"
14 "errors"
15 "fmt"
16 "io"
17 "slices"
18 )
19
20
21
22 type keyAgreement interface {
23
24
25
26
27
28 generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
29 processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
30
31
32
33
34
35 processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
36 generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
37 }
38
39 var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
40 var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
41
42
43
44 type rsaKeyAgreement struct{}
45
46 func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
47 return nil, nil
48 }
49
50 func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
51 if len(ckx.ciphertext) < 2 {
52 return nil, errClientKeyExchange
53 }
54 ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
55 if ciphertextLen != len(ckx.ciphertext)-2 {
56 return nil, errClientKeyExchange
57 }
58 ciphertext := ckx.ciphertext[2:]
59
60 priv, ok := cert.PrivateKey.(crypto.Decrypter)
61 if !ok {
62 return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
63 }
64
65 preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
66 if err != nil {
67 return nil, err
68 }
69
70
71
72
73
74
75 return preMasterSecret, nil
76 }
77
78 func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
79 return errors.New("tls: unexpected ServerKeyExchange")
80 }
81
82 func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
83 preMasterSecret := make([]byte, 48)
84 preMasterSecret[0] = byte(clientHello.vers >> 8)
85 preMasterSecret[1] = byte(clientHello.vers)
86 _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
87 if err != nil {
88 return nil, nil, err
89 }
90
91 rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
92 if !ok {
93 return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
94 }
95 encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
96 if err != nil {
97 return nil, nil, err
98 }
99 ckx := new(clientKeyExchangeMsg)
100 ckx.ciphertext = make([]byte, len(encrypted)+2)
101 ckx.ciphertext[0] = byte(len(encrypted) >> 8)
102 ckx.ciphertext[1] = byte(len(encrypted))
103 copy(ckx.ciphertext[2:], encrypted)
104 return preMasterSecret, ckx, nil
105 }
106
107
108 func sha1Hash(slices [][]byte) []byte {
109 hsha1 := sha1.New()
110 for _, slice := range slices {
111 hsha1.Write(slice)
112 }
113 return hsha1.Sum(nil)
114 }
115
116
117
118 func md5SHA1Hash(slices [][]byte) []byte {
119 md5sha1 := make([]byte, md5.Size+sha1.Size)
120 hmd5 := md5.New()
121 for _, slice := range slices {
122 hmd5.Write(slice)
123 }
124 copy(md5sha1, hmd5.Sum(nil))
125 copy(md5sha1[md5.Size:], sha1Hash(slices))
126 return md5sha1
127 }
128
129
130
131 func hashForServerKeyExchange(sigType uint8, slices ...[]byte) []byte {
132 if sigType == signatureECDSA {
133 return sha1Hash(slices)
134 }
135 return md5SHA1Hash(slices)
136 }
137
138
139
140
141
142 type ecdheKeyAgreement struct {
143 version uint16
144 isRSA bool
145
146
147
148 ckx *clientKeyExchangeMsg
149 preMasterSecret []byte
150
151
152
153 curveID CurveID
154 signatureAlgorithm SignatureScheme
155 key *ecdh.PrivateKey
156 }
157
158 func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
159 for _, c := range clientHello.supportedCurves {
160 if config.supportsCurve(ka.version, c) {
161 ka.curveID = c
162 break
163 }
164 }
165
166 if ka.curveID == 0 {
167 return nil, errors.New("tls: no supported elliptic curves offered")
168 }
169 if _, ok := curveForCurveID(ka.curveID); !ok {
170 return nil, errors.New("tls: CurvePreferences includes unsupported curve")
171 }
172
173 key, err := generateECDHEKey(config.rand(), ka.curveID)
174 if err != nil {
175 return nil, err
176 }
177 ka.key = key
178
179
180 ecdhePublic := key.PublicKey().Bytes()
181 serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
182 serverECDHEParams[0] = 3
183 serverECDHEParams[1] = byte(ka.curveID >> 8)
184 serverECDHEParams[2] = byte(ka.curveID)
185 serverECDHEParams[3] = byte(len(ecdhePublic))
186 copy(serverECDHEParams[4:], ecdhePublic)
187
188 priv, ok := cert.PrivateKey.(crypto.Signer)
189 if !ok {
190 return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey)
191 }
192
193 var sig []byte
194 if ka.version >= VersionTLS12 {
195 ka.signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms)
196 if err != nil {
197 return nil, err
198 }
199 sigType, sigHash, err := typeAndHashFromSignatureScheme(ka.signatureAlgorithm)
200 if err != nil {
201 return nil, err
202 }
203 if sigHash == crypto.SHA1 {
204 tlssha1.Value()
205 tlssha1.IncNonDefault()
206 }
207 signed := slices.Concat(clientHello.random, hello.random, serverECDHEParams)
208 if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
209 return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
210 }
211 signOpts := crypto.SignerOpts(sigHash)
212 if sigType == signatureRSAPSS {
213 signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
214 }
215 sig, err = crypto.SignMessage(priv, config.rand(), signed, signOpts)
216 if err != nil {
217 return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
218 }
219 } else {
220 sigType, sigHash, err := legacyTypeAndHashFromPublicKey(priv.Public())
221 if err != nil {
222 return nil, err
223 }
224 signed := hashForServerKeyExchange(sigType, clientHello.random, hello.random, serverECDHEParams)
225 if (sigType == signaturePKCS1v15) != ka.isRSA {
226 return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
227 }
228 sig, err = priv.Sign(config.rand(), signed, sigHash)
229 if err != nil {
230 return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
231 }
232 }
233
234 skx := new(serverKeyExchangeMsg)
235 sigAndHashLen := 0
236 if ka.version >= VersionTLS12 {
237 sigAndHashLen = 2
238 }
239 skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig))
240 copy(skx.key, serverECDHEParams)
241 k := skx.key[len(serverECDHEParams):]
242 if ka.version >= VersionTLS12 {
243 k[0] = byte(ka.signatureAlgorithm >> 8)
244 k[1] = byte(ka.signatureAlgorithm)
245 k = k[2:]
246 }
247 k[0] = byte(len(sig) >> 8)
248 k[1] = byte(len(sig))
249 copy(k[2:], sig)
250
251 return skx, nil
252 }
253
254 func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
255 if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
256 return nil, errClientKeyExchange
257 }
258
259 peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:])
260 if err != nil {
261 return nil, errClientKeyExchange
262 }
263 preMasterSecret, err := ka.key.ECDH(peerKey)
264 if err != nil {
265 return nil, errClientKeyExchange
266 }
267
268 return preMasterSecret, nil
269 }
270
271 func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
272 if len(skx.key) < 4 {
273 return errServerKeyExchange
274 }
275 if skx.key[0] != 3 {
276 return errors.New("tls: server selected unsupported curve")
277 }
278 ka.curveID = CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
279
280 publicLen := int(skx.key[3])
281 if publicLen+4 > len(skx.key) {
282 return errServerKeyExchange
283 }
284 serverECDHEParams := skx.key[:4+publicLen]
285 publicKey := serverECDHEParams[4:]
286
287 sig := skx.key[4+publicLen:]
288 if len(sig) < 2 {
289 return errServerKeyExchange
290 }
291 if ka.version >= VersionTLS12 {
292 ka.signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
293 sig = sig[2:]
294 if len(sig) < 2 {
295 return errServerKeyExchange
296 }
297 }
298 sigLen := int(sig[0])<<8 | int(sig[1])
299 if sigLen+2 != len(sig) {
300 return errServerKeyExchange
301 }
302 sig = sig[2:]
303
304 if !slices.Contains(clientHello.supportedCurves, ka.curveID) {
305 return errors.New("tls: server selected unoffered curve")
306 }
307
308 if _, ok := curveForCurveID(ka.curveID); !ok {
309 return errors.New("tls: server selected unsupported curve")
310 }
311
312 key, err := generateECDHEKey(config.rand(), ka.curveID)
313 if err != nil {
314 return err
315 }
316 ka.key = key
317
318 peerKey, err := key.Curve().NewPublicKey(publicKey)
319 if err != nil {
320 return errServerKeyExchange
321 }
322 ka.preMasterSecret, err = key.ECDH(peerKey)
323 if err != nil {
324 return errServerKeyExchange
325 }
326
327 ourPublicKey := key.PublicKey().Bytes()
328 ka.ckx = new(clientKeyExchangeMsg)
329 ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey))
330 ka.ckx.ciphertext[0] = byte(len(ourPublicKey))
331 copy(ka.ckx.ciphertext[1:], ourPublicKey)
332
333 var sigType uint8
334 var sigHash crypto.Hash
335 if ka.version >= VersionTLS12 {
336 if !isSupportedSignatureAlgorithm(ka.signatureAlgorithm, clientHello.supportedSignatureAlgorithms) {
337 return errors.New("tls: certificate used with invalid signature algorithm")
338 }
339 sigType, sigHash, err = typeAndHashFromSignatureScheme(ka.signatureAlgorithm)
340 if err != nil {
341 return err
342 }
343 if sigHash == crypto.SHA1 {
344 tlssha1.Value()
345 tlssha1.IncNonDefault()
346 }
347 if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
348 return errServerKeyExchange
349 }
350 signed := slices.Concat(clientHello.random, serverHello.random, serverECDHEParams)
351 if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil {
352 return errors.New("tls: invalid signature by the server certificate: " + err.Error())
353 }
354 } else {
355 sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey)
356 if err != nil {
357 return err
358 }
359 if (sigType == signaturePKCS1v15) != ka.isRSA {
360 return errServerKeyExchange
361 }
362 signed := hashForServerKeyExchange(sigType, clientHello.random, serverHello.random, serverECDHEParams)
363 if err := verifyLegacyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil {
364 return errors.New("tls: invalid signature by the server certificate: " + err.Error())
365 }
366 }
367
368 return nil
369 }
370
371 func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
372 if ka.ckx == nil {
373 return nil, nil, errors.New("tls: missing ServerKeyExchange message")
374 }
375
376 return ka.preMasterSecret, ka.ckx, nil
377 }
378
379
380
381 func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) {
382 curve, ok := curveForCurveID(curveID)
383 if !ok {
384 return nil, errors.New("tls: internal error: unsupported curve")
385 }
386
387 return curve.GenerateKey(rand)
388 }
389
390 func curveForCurveID(id CurveID) (ecdh.Curve, bool) {
391 switch id {
392 case X25519:
393 return ecdh.X25519(), true
394 case CurveP256:
395 return ecdh.P256(), true
396 case CurveP384:
397 return ecdh.P384(), true
398 case CurveP521:
399 return ecdh.P521(), true
400 default:
401 return nil, false
402 }
403 }
404
View as plain text