1
15
16 package gmtls
17
18 import (
19 "crypto"
20 "crypto/hmac"
21 "crypto/md5"
22 "crypto/sha1"
23 "crypto/sha256"
24 "crypto/sha512"
25 "errors"
26 "fmt"
27 "hash"
28
29 "github.com/tjfoc/gmsm/sm3"
30 )
31
32
33 func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
34 s1 = secret[0 : (len(secret)+1)/2]
35 s2 = secret[len(secret)/2:]
36 return
37 }
38
39
40 func pHash(result, secret, seed []byte, hash func() hash.Hash) {
41 h := hmac.New(hash, secret)
42 h.Write(seed)
43 a := h.Sum(nil)
44
45 j := 0
46 for j < len(result) {
47 h.Reset()
48 h.Write(a)
49 h.Write(seed)
50 b := h.Sum(nil)
51 todo := len(b)
52 if j+todo > len(result) {
53 todo = len(result) - j
54 }
55 copy(result[j:j+todo], b)
56 j += todo
57
58 h.Reset()
59 h.Write(a)
60 a = h.Sum(nil)
61 }
62 }
63
64
65 func prf10(result, secret, label, seed []byte) {
66 hashSHA1 := sha1.New
67 hashMD5 := md5.New
68
69 labelAndSeed := make([]byte, len(label)+len(seed))
70 copy(labelAndSeed, label)
71 copy(labelAndSeed[len(label):], seed)
72
73 s1, s2 := splitPreMasterSecret(secret)
74 pHash(result, s1, labelAndSeed, hashMD5)
75 result2 := make([]byte, len(result))
76 pHash(result2, s2, labelAndSeed, hashSHA1)
77
78 for i, b := range result2 {
79 result[i] ^= b
80 }
81 }
82
83
84 func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
85 return func(result, secret, label, seed []byte) {
86 labelAndSeed := make([]byte, len(label)+len(seed))
87 copy(labelAndSeed, label)
88 copy(labelAndSeed[len(label):], seed)
89
90 pHash(result, secret, labelAndSeed, hashFunc)
91 }
92 }
93
94
95
96 func prf30(result, secret, label, seed []byte) {
97 hashSHA1 := sha1.New()
98 hashMD5 := md5.New()
99
100 done := 0
101 i := 0
102
103
104
105
106 var b [11]byte
107 for done < len(result) {
108 for j := 0; j <= i; j++ {
109 b[j] = 'A' + byte(i)
110 }
111
112 hashSHA1.Reset()
113 hashSHA1.Write(b[:i+1])
114 hashSHA1.Write(secret)
115 hashSHA1.Write(seed)
116 digest := hashSHA1.Sum(nil)
117
118 hashMD5.Reset()
119 hashMD5.Write(secret)
120 hashMD5.Write(digest)
121
122 done += copy(result[done:], hashMD5.Sum(nil))
123 i++
124 }
125 }
126
127 const (
128 tlsRandomLength = 32
129 masterSecretLength = 48
130 finishedVerifyLength = 12
131 )
132
133 var masterSecretLabel = []byte("master secret")
134 var keyExpansionLabel = []byte("key expansion")
135 var clientFinishedLabel = []byte("client finished")
136 var serverFinishedLabel = []byte("server finished")
137
138 func prfAndHashForGM() func(result, secret, label, seed []byte) {
139 return prf12(sm3.New)
140 }
141
142 func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
143 switch version {
144 case VersionSSL30:
145 return prf30, crypto.Hash(0)
146 case VersionTLS10, VersionTLS11:
147 return prf10, crypto.Hash(0)
148 case VersionTLS12:
149 if suite.flags&suiteSHA384 != 0 {
150 return prf12(sha512.New384), crypto.SHA384
151 }
152 return prf12(sha256.New), crypto.SHA256
153 default:
154 panic("unknown version")
155 }
156 }
157
158 func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
159 var prf func(result, secret, label, seed []byte)
160 if version == VersionGMSSL {
161 prf = prfAndHashForGM()
162 } else {
163 prf, _ = prfAndHashForVersion(version, suite)
164 }
165 return prf
166 }
167
168
169
170 func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
171 seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
172 seed = append(seed, clientRandom...)
173 seed = append(seed, serverRandom...)
174
175 masterSecret := make([]byte, masterSecretLength)
176 prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
177 return masterSecret
178 }
179
180
181
182
183 func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
184 seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
185 seed = append(seed, serverRandom...)
186 seed = append(seed, clientRandom...)
187
188 n := 2*macLen + 2*keyLen + 2*ivLen
189 keyMaterial := make([]byte, n)
190 prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
191 clientMAC = keyMaterial[:macLen]
192 keyMaterial = keyMaterial[macLen:]
193 serverMAC = keyMaterial[:macLen]
194 keyMaterial = keyMaterial[macLen:]
195 clientKey = keyMaterial[:keyLen]
196 keyMaterial = keyMaterial[keyLen:]
197 serverKey = keyMaterial[:keyLen]
198 keyMaterial = keyMaterial[keyLen:]
199 clientIV = keyMaterial[:ivLen]
200 keyMaterial = keyMaterial[ivLen:]
201 serverIV = keyMaterial[:ivLen]
202 return
203 }
204
205
206
207 func lookupTLSHash(signatureAlgorithm SignatureScheme) (crypto.Hash, error) {
208 switch signatureAlgorithm {
209 case PKCS1WithSHA1, ECDSAWithSHA1:
210 return crypto.SHA1, nil
211 case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
212 return crypto.SHA256, nil
213 case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
214 return crypto.SHA384, nil
215 case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
216 return crypto.SHA512, nil
217 default:
218 return 0, fmt.Errorf("tls: unsupported signature algorithm: %#04x", signatureAlgorithm)
219 }
220 }
221 func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
222 var buffer []byte
223 if version == VersionSSL30 || version >= VersionTLS12 {
224 buffer = []byte{}
225 }
226
227 var prf func(result, secret, label, seed []byte)
228
229 if version == VersionGMSSL {
230 prf = prfAndHashForGM()
231 return finishedHash{sm3.New(), sm3.New(), nil, nil, buffer, version, prf}
232 } else {
233 prf, hash := prfAndHashForVersion(version, cipherSuite)
234 if hash != 0 {
235 return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
236 }
237 }
238
239 return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
240 }
241
242
243
244 type finishedHash struct {
245 client hash.Hash
246 server hash.Hash
247
248
249 clientMD5 hash.Hash
250 serverMD5 hash.Hash
251
252
253 buffer []byte
254
255 version uint16
256 prf func(result, secret, label, seed []byte)
257 }
258
259 func (h *finishedHash) Write(msg []byte) (n int, err error) {
260 h.client.Write(msg)
261 h.server.Write(msg)
262
263 if h.version < VersionTLS12 {
264 h.clientMD5.Write(msg)
265 h.serverMD5.Write(msg)
266 }
267
268 if h.buffer != nil {
269 h.buffer = append(h.buffer, msg...)
270 }
271
272 return len(msg), nil
273 }
274
275 func (h finishedHash) Sum() []byte {
276 if h.version >= VersionTLS12 || h.version == VersionGMSSL {
277 return h.client.Sum(nil)
278 }
279
280 out := make([]byte, 0, md5.Size+sha1.Size)
281 out = h.clientMD5.Sum(out)
282 return h.client.Sum(out)
283 }
284
285
286
287
288 func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
289 md5.Write(magic)
290 md5.Write(masterSecret)
291 md5.Write(ssl30Pad1[:])
292 md5Digest := md5.Sum(nil)
293
294 md5.Reset()
295 md5.Write(masterSecret)
296 md5.Write(ssl30Pad2[:])
297 md5.Write(md5Digest)
298 md5Digest = md5.Sum(nil)
299
300 sha1.Write(magic)
301 sha1.Write(masterSecret)
302 sha1.Write(ssl30Pad1[:40])
303 sha1Digest := sha1.Sum(nil)
304
305 sha1.Reset()
306 sha1.Write(masterSecret)
307 sha1.Write(ssl30Pad2[:40])
308 sha1.Write(sha1Digest)
309 sha1Digest = sha1.Sum(nil)
310
311 ret := make([]byte, len(md5Digest)+len(sha1Digest))
312 copy(ret, md5Digest)
313 copy(ret[len(md5Digest):], sha1Digest)
314 return ret
315 }
316
317 var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
318 var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
319
320
321
322 func (h finishedHash) clientSum(masterSecret []byte) []byte {
323 if h.version == VersionSSL30 {
324 return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
325 }
326
327 out := make([]byte, finishedVerifyLength)
328 h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
329 return out
330 }
331
332
333
334 func (h finishedHash) serverSum(masterSecret []byte) []byte {
335 if h.version == VersionSSL30 {
336 return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
337 }
338
339 out := make([]byte, finishedVerifyLength)
340 h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
341 return out
342 }
343
344
345
346 func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) ([]byte, error) {
347 if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
348 panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
349 }
350
351 if h.version == VersionSSL30 {
352 if sigType != signaturePKCS1v15 {
353 return nil, errors.New("tls: unsupported signature type for client certificate")
354 }
355
356 md5Hash := md5.New()
357 md5Hash.Write(h.buffer)
358 sha1Hash := sha1.New()
359 sha1Hash.Write(h.buffer)
360 return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), nil
361 }
362 if h.version >= VersionTLS12 {
363 hash := hashAlg.New()
364 hash.Write(h.buffer)
365 return hash.Sum(nil), nil
366 }
367
368 if sigType == signatureECDSA {
369 return h.server.Sum(nil), nil
370 }
371
372 return h.Sum(), nil
373 }
374
375
376
377 func (h *finishedHash) discardHandshakeBuffer() {
378 h.buffer = nil
379 }
380
381
382
383
384 func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
385 return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
386 }
387
388
389
390 func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
391 return func(label string, context []byte, length int) ([]byte, error) {
392 switch label {
393 case "client finished", "server finished", "master secret", "key expansion":
394
395 return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label)
396 }
397
398 seedLen := len(serverRandom) + len(clientRandom)
399 if context != nil {
400 seedLen += 2 + len(context)
401 }
402 seed := make([]byte, 0, seedLen)
403
404 seed = append(seed, clientRandom...)
405 seed = append(seed, serverRandom...)
406
407 if context != nil {
408 if len(context) >= 1<<16 {
409 return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long")
410 }
411 seed = append(seed, byte(len(context)>>8), byte(len(context)))
412 seed = append(seed, context...)
413 }
414
415 keyMaterial := make([]byte, length)
416 prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed)
417 return keyMaterial, nil
418 }
419 }
420
View as plain text