Daily bump.
[official-gcc.git] / libgo / go / crypto / tls / ticket.go
blob4cfc5a53ffeb1bff70cb3310ee0c5e6cd98221cb
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.
5 package tls
7 import (
8 "bytes"
9 "crypto/aes"
10 "crypto/cipher"
11 "crypto/hmac"
12 "crypto/sha256"
13 "crypto/subtle"
14 "errors"
15 "io"
18 // sessionState contains the information that is serialized into a session
19 // ticket in order to later resume a connection.
20 type sessionState struct {
21 vers uint16
22 cipherSuite uint16
23 masterSecret []byte
24 certificates [][]byte
27 func (s *sessionState) equal(i interface{}) bool {
28 s1, ok := i.(*sessionState)
29 if !ok {
30 return false
33 if s.vers != s1.vers ||
34 s.cipherSuite != s1.cipherSuite ||
35 !bytes.Equal(s.masterSecret, s1.masterSecret) {
36 return false
39 if len(s.certificates) != len(s1.certificates) {
40 return false
43 for i := range s.certificates {
44 if !bytes.Equal(s.certificates[i], s1.certificates[i]) {
45 return false
49 return true
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)
59 x := ret
60 x[0] = byte(s.vers >> 8)
61 x[1] = byte(s.vers)
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))
66 x = x[6:]
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))
72 x = x[2:]
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))
79 copy(x[4:], cert)
80 x = x[4+len(cert):]
83 return ret
86 func (s *sessionState) unmarshal(data []byte) bool {
87 if len(data) < 8 {
88 return false
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])
94 data = data[6:]
95 if len(data) < masterSecretLen {
96 return false
99 s.masterSecret = data[:masterSecretLen]
100 data = data[masterSecretLen:]
102 if len(data) < 2 {
103 return false
106 numCerts := int(data[0])<<8 | int(data[1])
107 data = data[2:]
109 s.certificates = make([][]byte, numCerts)
110 for i := range s.certificates {
111 if len(data) < 4 {
112 return false
114 certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3])
115 data = data[4:]
116 if certLen < 0 {
117 return false
119 if len(data) < certLen {
120 return false
122 s.certificates[i] = data[:certLen]
123 data = data[certLen:]
126 if len(data) > 0 {
127 return false
130 return true
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 {
140 return nil, err
142 block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
143 if err != nil {
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 {
157 return nil, false
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 {
168 return nil, false
171 block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
172 if err != nil {
173 return nil, false
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)
181 return state, ok