...

Source file src/crypto/tls/ticket.go

Documentation: crypto/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  	"golang.org/x/crypto/cryptobyte"
		18  )
		19  
		20  // sessionState contains the information that is serialized into a session
		21  // ticket in order to later resume a connection.
		22  type sessionState struct {
		23  	vers				 uint16
		24  	cipherSuite	uint16
		25  	createdAt		uint64
		26  	masterSecret []byte // opaque master_secret<1..2^16-1>;
		27  	// struct { opaque certificate<1..2^24-1> } Certificate;
		28  	certificates [][]byte // Certificate certificate_list<0..2^24-1>;
		29  
		30  	// usedOldKey is true if the ticket from which this session came from
		31  	// was encrypted with an older key and thus should be refreshed.
		32  	usedOldKey bool
		33  }
		34  
		35  func (m *sessionState) marshal() []byte {
		36  	var b cryptobyte.Builder
		37  	b.AddUint16(m.vers)
		38  	b.AddUint16(m.cipherSuite)
		39  	addUint64(&b, m.createdAt)
		40  	b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
		41  		b.AddBytes(m.masterSecret)
		42  	})
		43  	b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
		44  		for _, cert := range m.certificates {
		45  			b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
		46  				b.AddBytes(cert)
		47  			})
		48  		}
		49  	})
		50  	return b.BytesOrPanic()
		51  }
		52  
		53  func (m *sessionState) unmarshal(data []byte) bool {
		54  	*m = sessionState{usedOldKey: m.usedOldKey}
		55  	s := cryptobyte.String(data)
		56  	if ok := s.ReadUint16(&m.vers) &&
		57  		s.ReadUint16(&m.cipherSuite) &&
		58  		readUint64(&s, &m.createdAt) &&
		59  		readUint16LengthPrefixed(&s, &m.masterSecret) &&
		60  		len(m.masterSecret) != 0; !ok {
		61  		return false
		62  	}
		63  	var certList cryptobyte.String
		64  	if !s.ReadUint24LengthPrefixed(&certList) {
		65  		return false
		66  	}
		67  	for !certList.Empty() {
		68  		var cert []byte
		69  		if !readUint24LengthPrefixed(&certList, &cert) {
		70  			return false
		71  		}
		72  		m.certificates = append(m.certificates, cert)
		73  	}
		74  	return s.Empty()
		75  }
		76  
		77  // sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first
		78  // version (revision = 0) doesn't carry any of the information needed for 0-RTT
		79  // validation and the nonce is always empty.
		80  type sessionStateTLS13 struct {
		81  	// uint8 version	= 0x0304;
		82  	// uint8 revision = 0;
		83  	cipherSuite			uint16
		84  	createdAt				uint64
		85  	resumptionSecret []byte			// opaque resumption_master_secret<1..2^8-1>;
		86  	certificate			Certificate // CertificateEntry certificate_list<0..2^24-1>;
		87  }
		88  
		89  func (m *sessionStateTLS13) marshal() []byte {
		90  	var b cryptobyte.Builder
		91  	b.AddUint16(VersionTLS13)
		92  	b.AddUint8(0) // revision
		93  	b.AddUint16(m.cipherSuite)
		94  	addUint64(&b, m.createdAt)
		95  	b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
		96  		b.AddBytes(m.resumptionSecret)
		97  	})
		98  	marshalCertificate(&b, m.certificate)
		99  	return b.BytesOrPanic()
	 100  }
	 101  
	 102  func (m *sessionStateTLS13) unmarshal(data []byte) bool {
	 103  	*m = sessionStateTLS13{}
	 104  	s := cryptobyte.String(data)
	 105  	var version uint16
	 106  	var revision uint8
	 107  	return s.ReadUint16(&version) &&
	 108  		version == VersionTLS13 &&
	 109  		s.ReadUint8(&revision) &&
	 110  		revision == 0 &&
	 111  		s.ReadUint16(&m.cipherSuite) &&
	 112  		readUint64(&s, &m.createdAt) &&
	 113  		readUint8LengthPrefixed(&s, &m.resumptionSecret) &&
	 114  		len(m.resumptionSecret) != 0 &&
	 115  		unmarshalCertificate(&s, &m.certificate) &&
	 116  		s.Empty()
	 117  }
	 118  
	 119  func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
	 120  	if len(c.ticketKeys) == 0 {
	 121  		return nil, errors.New("tls: internal error: session ticket keys unavailable")
	 122  	}
	 123  
	 124  	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
	 125  	keyName := encrypted[:ticketKeyNameLen]
	 126  	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
	 127  	macBytes := encrypted[len(encrypted)-sha256.Size:]
	 128  
	 129  	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
	 130  		return nil, err
	 131  	}
	 132  	key := c.ticketKeys[0]
	 133  	copy(keyName, key.keyName[:])
	 134  	block, err := aes.NewCipher(key.aesKey[:])
	 135  	if err != nil {
	 136  		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
	 137  	}
	 138  	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state)
	 139  
	 140  	mac := hmac.New(sha256.New, key.hmacKey[:])
	 141  	mac.Write(encrypted[:len(encrypted)-sha256.Size])
	 142  	mac.Sum(macBytes[:0])
	 143  
	 144  	return encrypted, nil
	 145  }
	 146  
	 147  func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) {
	 148  	if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
	 149  		return nil, false
	 150  	}
	 151  
	 152  	keyName := encrypted[:ticketKeyNameLen]
	 153  	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
	 154  	macBytes := encrypted[len(encrypted)-sha256.Size:]
	 155  	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
	 156  
	 157  	keyIndex := -1
	 158  	for i, candidateKey := range c.ticketKeys {
	 159  		if bytes.Equal(keyName, candidateKey.keyName[:]) {
	 160  			keyIndex = i
	 161  			break
	 162  		}
	 163  	}
	 164  	if keyIndex == -1 {
	 165  		return nil, false
	 166  	}
	 167  	key := &c.ticketKeys[keyIndex]
	 168  
	 169  	mac := hmac.New(sha256.New, key.hmacKey[:])
	 170  	mac.Write(encrypted[:len(encrypted)-sha256.Size])
	 171  	expected := mac.Sum(nil)
	 172  
	 173  	if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
	 174  		return nil, false
	 175  	}
	 176  
	 177  	block, err := aes.NewCipher(key.aesKey[:])
	 178  	if err != nil {
	 179  		return nil, false
	 180  	}
	 181  	plaintext = make([]byte, len(ciphertext))
	 182  	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
	 183  
	 184  	return plaintext, keyIndex > 0
	 185  }
	 186  

View as plain text