github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/qtls-go1-16/key_schedule.go (about)

     1  // Copyright 2018 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 qtls
     6  
     7  import (
     8  	"crypto"
     9  	"crypto/elliptic"
    10  	"crypto/hmac"
    11  	"errors"
    12  	"hash"
    13  	"io"
    14  	"math/big"
    15  
    16  	"golang.org/x/crypto/cryptobyte"
    17  	"golang.org/x/crypto/curve25519"
    18  	"golang.org/x/crypto/hkdf"
    19  )
    20  
    21  // This file contains the functions necessary to compute the TLS 1.3 key
    22  // schedule. See RFC 8446, Section 7.
    23  
    24  const (
    25  	resumptionBinderLabel         = "res binder"
    26  	clientHandshakeTrafficLabel   = "c hs traffic"
    27  	serverHandshakeTrafficLabel   = "s hs traffic"
    28  	clientApplicationTrafficLabel = "c ap traffic"
    29  	serverApplicationTrafficLabel = "s ap traffic"
    30  	exporterLabel                 = "exp master"
    31  	resumptionLabel               = "res master"
    32  	trafficUpdateLabel            = "traffic upd"
    33  )
    34  
    35  // HkdfExtract generates a pseudorandom key for use with Expand from an input secret and an optional independent salt.
    36  func HkdfExtract(hash crypto.Hash, newSecret, currentSecret []byte) []byte {
    37  	if newSecret == nil {
    38  		newSecret = make([]byte, hash.Size())
    39  	}
    40  	return hkdf.Extract(hash.New, newSecret, currentSecret)
    41  }
    42  
    43  // HkdfExpandLabel HKDF expands a label
    44  func HkdfExpandLabel(hash crypto.Hash, secret, hashValue []byte, label string, L int) []byte {
    45  	return hkdfExpandLabel(hash, secret, hashValue, label, L)
    46  }
    47  
    48  func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte {
    49  	var hkdfLabel cryptobyte.Builder
    50  	hkdfLabel.AddUint16(uint16(length))
    51  	hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
    52  		b.AddBytes([]byte("tls13 "))
    53  		b.AddBytes([]byte(label))
    54  	})
    55  	hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
    56  		b.AddBytes(context)
    57  	})
    58  	out := make([]byte, length)
    59  	n, err := hkdf.Expand(hash.New, secret, hkdfLabel.BytesOrPanic()).Read(out)
    60  	if err != nil || n != length {
    61  		panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
    62  	}
    63  	return out
    64  }
    65  
    66  // expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
    67  func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte {
    68  	return hkdfExpandLabel(c.hash, secret, context, label, length)
    69  }
    70  
    71  // deriveSecret implements Derive-Secret from RFC 8446, Section 7.1.
    72  func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte {
    73  	if transcript == nil {
    74  		transcript = c.hash.New()
    75  	}
    76  	return c.expandLabel(secret, label, transcript.Sum(nil), c.hash.Size())
    77  }
    78  
    79  // extract implements HKDF-Extract with the cipher suite hash.
    80  func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte {
    81  	return HkdfExtract(c.hash, newSecret, currentSecret)
    82  }
    83  
    84  // nextTrafficSecret generates the next traffic secret, given the current one,
    85  // according to RFC 8446, Section 7.2.
    86  func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte {
    87  	return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size())
    88  }
    89  
    90  // trafficKey generates traffic keys according to RFC 8446, Section 7.3.
    91  func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
    92  	key = c.expandLabel(trafficSecret, "key", nil, c.keyLen)
    93  	iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength)
    94  	return
    95  }
    96  
    97  // finishedHash generates the Finished verify_data or PskBinderEntry according
    98  // to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey
    99  // selection.
   100  func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte {
   101  	finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size())
   102  	verifyData := hmac.New(c.hash.New, finishedKey)
   103  	verifyData.Write(transcript.Sum(nil))
   104  	return verifyData.Sum(nil)
   105  }
   106  
   107  // exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to
   108  // RFC 8446, Section 7.5.
   109  func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) {
   110  	expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript)
   111  	return func(label string, context []byte, length int) ([]byte, error) {
   112  		secret := c.deriveSecret(expMasterSecret, label, nil)
   113  		h := c.hash.New()
   114  		h.Write(context)
   115  		return c.expandLabel(secret, "exporter", h.Sum(nil), length), nil
   116  	}
   117  }
   118  
   119  // ecdheParameters implements Diffie-Hellman with either NIST curves or X25519,
   120  // according to RFC 8446, Section 4.2.8.2.
   121  type ecdheParameters interface {
   122  	CurveID() CurveID
   123  	PublicKey() []byte
   124  	SharedKey(peerPublicKey []byte) []byte
   125  }
   126  
   127  func generateECDHEParameters(rand io.Reader, curveID CurveID) (ecdheParameters, error) {
   128  	if curveID == X25519 {
   129  		privateKey := make([]byte, curve25519.ScalarSize)
   130  		if _, err := io.ReadFull(rand, privateKey); err != nil {
   131  			return nil, err
   132  		}
   133  		publicKey, err := curve25519.X25519(privateKey, curve25519.Basepoint)
   134  		if err != nil {
   135  			return nil, err
   136  		}
   137  		return &x25519Parameters{privateKey: privateKey, publicKey: publicKey}, nil
   138  	}
   139  
   140  	curve, ok := curveForCurveID(curveID)
   141  	if !ok {
   142  		return nil, errors.New("tls: internal error: unsupported curve")
   143  	}
   144  
   145  	p := &nistParameters{curveID: curveID}
   146  	var err error
   147  	p.privateKey, p.x, p.y, err = elliptic.GenerateKey(curve, rand)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	return p, nil
   152  }
   153  
   154  func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
   155  	switch id {
   156  	case CurveP256:
   157  		return elliptic.P256(), true
   158  	case CurveP384:
   159  		return elliptic.P384(), true
   160  	case CurveP521:
   161  		return elliptic.P521(), true
   162  	default:
   163  		return nil, false
   164  	}
   165  }
   166  
   167  type nistParameters struct {
   168  	privateKey []byte
   169  	x, y       *big.Int // public key
   170  	curveID    CurveID
   171  }
   172  
   173  func (p *nistParameters) CurveID() CurveID {
   174  	return p.curveID
   175  }
   176  
   177  func (p *nistParameters) PublicKey() []byte {
   178  	curve, _ := curveForCurveID(p.curveID)
   179  	return elliptic.Marshal(curve, p.x, p.y)
   180  }
   181  
   182  func (p *nistParameters) SharedKey(peerPublicKey []byte) []byte {
   183  	curve, _ := curveForCurveID(p.curveID)
   184  	// Unmarshal also checks whether the given point is on the curve.
   185  	x, y := elliptic.Unmarshal(curve, peerPublicKey)
   186  	if x == nil {
   187  		return nil
   188  	}
   189  
   190  	xShared, _ := curve.ScalarMult(x, y, p.privateKey)
   191  	sharedKey := make([]byte, (curve.Params().BitSize+7)/8)
   192  	return xShared.FillBytes(sharedKey)
   193  }
   194  
   195  type x25519Parameters struct {
   196  	privateKey []byte
   197  	publicKey  []byte
   198  }
   199  
   200  func (p *x25519Parameters) CurveID() CurveID {
   201  	return X25519
   202  }
   203  
   204  func (p *x25519Parameters) PublicKey() []byte {
   205  	return p.publicKey[:]
   206  }
   207  
   208  func (p *x25519Parameters) SharedKey(peerPublicKey []byte) []byte {
   209  	sharedKey, err := curve25519.X25519(p.privateKey, peerPublicKey)
   210  	if err != nil {
   211  		return nil
   212  	}
   213  	return sharedKey
   214  }