Home | History | Annotate | Download | only in tls
      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.
      4 
      5 package tls
      6 
      7 import (
      8 	"bytes"
      9 	"crypto/aes"
     10 	"crypto/cipher"
     11 	"crypto/hmac"
     12 	"crypto/sha256"
     13 	"crypto/subtle"
     14 	"errors"
     15 	"io"
     16 )
     17 
     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
     25 	// usedOldKey is true if the ticket from which this session came from
     26 	// was encrypted with an older key and thus should be refreshed.
     27 	usedOldKey bool
     28 }
     29 
     30 func (s *sessionState) equal(i interface{}) bool {
     31 	s1, ok := i.(*sessionState)
     32 	if !ok {
     33 		return false
     34 	}
     35 
     36 	if s.vers != s1.vers ||
     37 		s.cipherSuite != s1.cipherSuite ||
     38 		!bytes.Equal(s.masterSecret, s1.masterSecret) {
     39 		return false
     40 	}
     41 
     42 	if len(s.certificates) != len(s1.certificates) {
     43 		return false
     44 	}
     45 
     46 	for i := range s.certificates {
     47 		if !bytes.Equal(s.certificates[i], s1.certificates[i]) {
     48 			return false
     49 		}
     50 	}
     51 
     52 	return true
     53 }
     54 
     55 func (s *sessionState) marshal() []byte {
     56 	length := 2 + 2 + 2 + len(s.masterSecret) + 2
     57 	for _, cert := range s.certificates {
     58 		length += 4 + len(cert)
     59 	}
     60 
     61 	ret := make([]byte, length)
     62 	x := ret
     63 	x[0] = byte(s.vers >> 8)
     64 	x[1] = byte(s.vers)
     65 	x[2] = byte(s.cipherSuite >> 8)
     66 	x[3] = byte(s.cipherSuite)
     67 	x[4] = byte(len(s.masterSecret) >> 8)
     68 	x[5] = byte(len(s.masterSecret))
     69 	x = x[6:]
     70 	copy(x, s.masterSecret)
     71 	x = x[len(s.masterSecret):]
     72 
     73 	x[0] = byte(len(s.certificates) >> 8)
     74 	x[1] = byte(len(s.certificates))
     75 	x = x[2:]
     76 
     77 	for _, cert := range s.certificates {
     78 		x[0] = byte(len(cert) >> 24)
     79 		x[1] = byte(len(cert) >> 16)
     80 		x[2] = byte(len(cert) >> 8)
     81 		x[3] = byte(len(cert))
     82 		copy(x[4:], cert)
     83 		x = x[4+len(cert):]
     84 	}
     85 
     86 	return ret
     87 }
     88 
     89 func (s *sessionState) unmarshal(data []byte) bool {
     90 	if len(data) < 8 {
     91 		return false
     92 	}
     93 
     94 	s.vers = uint16(data[0])<<8 | uint16(data[1])
     95 	s.cipherSuite = uint16(data[2])<<8 | uint16(data[3])
     96 	masterSecretLen := int(data[4])<<8 | int(data[5])
     97 	data = data[6:]
     98 	if len(data) < masterSecretLen {
     99 		return false
    100 	}
    101 
    102 	s.masterSecret = data[:masterSecretLen]
    103 	data = data[masterSecretLen:]
    104 
    105 	if len(data) < 2 {
    106 		return false
    107 	}
    108 
    109 	numCerts := int(data[0])<<8 | int(data[1])
    110 	data = data[2:]
    111 
    112 	s.certificates = make([][]byte, numCerts)
    113 	for i := range s.certificates {
    114 		if len(data) < 4 {
    115 			return false
    116 		}
    117 		certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3])
    118 		data = data[4:]
    119 		if certLen < 0 {
    120 			return false
    121 		}
    122 		if len(data) < certLen {
    123 			return false
    124 		}
    125 		s.certificates[i] = data[:certLen]
    126 		data = data[certLen:]
    127 	}
    128 
    129 	if len(data) > 0 {
    130 		return false
    131 	}
    132 
    133 	return true
    134 }
    135 
    136 func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
    137 	serialized := state.marshal()
    138 	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size)
    139 	keyName := encrypted[:ticketKeyNameLen]
    140 	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
    141 	macBytes := encrypted[len(encrypted)-sha256.Size:]
    142 
    143 	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
    144 		return nil, err
    145 	}
    146 	key := c.config.ticketKeys()[0]
    147 	copy(keyName, key.keyName[:])
    148 	block, err := aes.NewCipher(key.aesKey[:])
    149 	if err != nil {
    150 		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
    151 	}
    152 	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized)
    153 
    154 	mac := hmac.New(sha256.New, key.hmacKey[:])
    155 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
    156 	mac.Sum(macBytes[:0])
    157 
    158 	return encrypted, nil
    159 }
    160 
    161 func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
    162 	if c.config.SessionTicketsDisabled ||
    163 		len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
    164 		return nil, false
    165 	}
    166 
    167 	keyName := encrypted[:ticketKeyNameLen]
    168 	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
    169 	macBytes := encrypted[len(encrypted)-sha256.Size:]
    170 
    171 	keys := c.config.ticketKeys()
    172 	keyIndex := -1
    173 	for i, candidateKey := range keys {
    174 		if bytes.Equal(keyName, candidateKey.keyName[:]) {
    175 			keyIndex = i
    176 			break
    177 		}
    178 	}
    179 
    180 	if keyIndex == -1 {
    181 		return nil, false
    182 	}
    183 	key := &keys[keyIndex]
    184 
    185 	mac := hmac.New(sha256.New, key.hmacKey[:])
    186 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
    187 	expected := mac.Sum(nil)
    188 
    189 	if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
    190 		return nil, false
    191 	}
    192 
    193 	block, err := aes.NewCipher(key.aesKey[:])
    194 	if err != nil {
    195 		return nil, false
    196 	}
    197 	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
    198 	plaintext := ciphertext
    199 	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
    200 
    201 	state := &sessionState{usedOldKey: keyIndex > 0}
    202 	ok := state.unmarshal(plaintext)
    203 	return state, ok
    204 }
    205