1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 // sessionState contains the information that is serialized into a session
19 // ticket in order to later resume a connection.
20 type sessionState
struct {
27 func (s
*sessionState
) equal(i
interface{}) bool {
28 s1
, ok
:= i
.(*sessionState
)
33 if s
.vers
!= s1
.vers ||
34 s
.cipherSuite
!= s1
.cipherSuite ||
35 !bytes
.Equal(s
.masterSecret
, s1
.masterSecret
) {
39 if len(s
.certificates
) != len(s1
.certificates
) {
43 for i
:= range s
.certificates
{
44 if !bytes
.Equal(s
.certificates
[i
], s1
.certificates
[i
]) {
52 func (s
*sessionState
) marshal() []byte {
53 length
:= 2 + 2 + 2 + len(s
.masterSecret
) + 2
54 for _
, cert
:= range s
.certificates
{
55 length
+= 4 + len(cert
)
58 ret
:= make([]byte, length
)
60 x
[0] = byte(s
.vers
>> 8)
62 x
[2] = byte(s
.cipherSuite
>> 8)
63 x
[3] = byte(s
.cipherSuite
)
64 x
[4] = byte(len(s
.masterSecret
) >> 8)
65 x
[5] = byte(len(s
.masterSecret
))
67 copy(x
, s
.masterSecret
)
68 x
= x
[len(s
.masterSecret
):]
70 x
[0] = byte(len(s
.certificates
) >> 8)
71 x
[1] = byte(len(s
.certificates
))
74 for _
, cert
:= range s
.certificates
{
75 x
[0] = byte(len(cert
) >> 24)
76 x
[1] = byte(len(cert
) >> 16)
77 x
[2] = byte(len(cert
) >> 8)
78 x
[3] = byte(len(cert
))
86 func (s
*sessionState
) unmarshal(data
[]byte) bool {
91 s
.vers
= uint16(data
[0])<<8 |
uint16(data
[1])
92 s
.cipherSuite
= uint16(data
[2])<<8 |
uint16(data
[3])
93 masterSecretLen
:= int(data
[4])<<8 |
int(data
[5])
95 if len(data
) < masterSecretLen
{
99 s
.masterSecret
= data
[:masterSecretLen
]
100 data
= data
[masterSecretLen
:]
106 numCerts
:= int(data
[0])<<8 |
int(data
[1])
109 s
.certificates
= make([][]byte, numCerts
)
110 for i
:= range s
.certificates
{
114 certLen
:= int(data
[0])<<24 |
int(data
[1])<<16 |
int(data
[2])<<8 |
int(data
[3])
119 if len(data
) < certLen
{
122 s
.certificates
[i
] = data
[:certLen
]
123 data
= data
[certLen
:]
133 func (c
*Conn
) encryptTicket(state
*sessionState
) ([]byte, error
) {
134 serialized
:= state
.marshal()
135 encrypted
:= make([]byte, aes
.BlockSize
+len(serialized
)+sha256
.Size
)
136 iv
:= encrypted
[:aes
.BlockSize
]
137 macBytes
:= encrypted
[len(encrypted
)-sha256
.Size
:]
139 if _
, err
:= io
.ReadFull(c
.config
.rand(), iv
); err
!= nil {
142 block
, err
:= aes
.NewCipher(c
.config
.SessionTicketKey
[:16])
144 return nil, errors
.New("tls: failed to create cipher while encrypting ticket: " + err
.Error())
146 cipher
.NewCTR(block
, iv
).XORKeyStream(encrypted
[aes
.BlockSize
:], serialized
)
148 mac
:= hmac
.New(sha256
.New
, c
.config
.SessionTicketKey
[16:32])
149 mac
.Write(encrypted
[:len(encrypted
)-sha256
.Size
])
150 mac
.Sum(macBytes
[:0])
152 return encrypted
, nil
155 func (c
*Conn
) decryptTicket(encrypted
[]byte) (*sessionState
, bool) {
156 if len(encrypted
) < aes
.BlockSize
+sha256
.Size
{
160 iv
:= encrypted
[:aes
.BlockSize
]
161 macBytes
:= encrypted
[len(encrypted
)-sha256
.Size
:]
163 mac
:= hmac
.New(sha256
.New
, c
.config
.SessionTicketKey
[16:32])
164 mac
.Write(encrypted
[:len(encrypted
)-sha256
.Size
])
165 expected
:= mac
.Sum(nil)
167 if subtle
.ConstantTimeCompare(macBytes
, expected
) != 1 {
171 block
, err
:= aes
.NewCipher(c
.config
.SessionTicketKey
[:16])
175 ciphertext
:= encrypted
[aes
.BlockSize
: len(encrypted
)-sha256
.Size
]
176 plaintext
:= ciphertext
177 cipher
.NewCTR(block
, iv
).XORKeyStream(plaintext
, ciphertext
)
179 state
:= new(sessionState
)
180 ok
:= state
.unmarshal(plaintext
)