dockerfiles/anylink/dtls-2.0.9/pkg/crypto/prf/prf.go

225 lines
7.1 KiB
Go

// Package prf implements TLS 1.2 Pseudorandom functions
package prf
import ( //nolint:gci
ellipticStdlib "crypto/elliptic"
"crypto/hmac"
"encoding/binary"
"errors"
"fmt"
"hash"
"math"
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
"github.com/pion/dtls/v2/pkg/protocol"
"golang.org/x/crypto/curve25519"
)
const (
masterSecretLabel = "master secret"
extendedMasterSecretLabel = "extended master secret"
keyExpansionLabel = "key expansion"
verifyDataClientLabel = "client finished"
verifyDataServerLabel = "server finished"
)
// HashFunc allows callers to decide what hash is used in PRF
type HashFunc func() hash.Hash
// EncryptionKeys is all the state needed for a TLS CipherSuite
type EncryptionKeys struct {
MasterSecret []byte
ClientMACKey []byte
ServerMACKey []byte
ClientWriteKey []byte
ServerWriteKey []byte
ClientWriteIV []byte
ServerWriteIV []byte
}
var errInvalidNamedCurve = &protocol.FatalError{Err: errors.New("invalid named curve")} //nolint:goerr113
func (e *EncryptionKeys) String() string {
return fmt.Sprintf(`encryptionKeys:
- masterSecret: %#v
- clientMACKey: %#v
- serverMACKey: %#v
- clientWriteKey: %#v
- serverWriteKey: %#v
- clientWriteIV: %#v
- serverWriteIV: %#v
`,
e.MasterSecret,
e.ClientMACKey,
e.ServerMACKey,
e.ClientWriteKey,
e.ServerWriteKey,
e.ClientWriteIV,
e.ServerWriteIV)
}
// PSKPreMasterSecret generates the PSK Premaster Secret
// The premaster secret is formed as follows: if the PSK is N octets
// long, concatenate a uint16 with the value N, N zero octets, a second
// uint16 with the value N, and the PSK itself.
//
// https://tools.ietf.org/html/rfc4279#section-2
func PSKPreMasterSecret(psk []byte) []byte {
pskLen := uint16(len(psk))
out := append(make([]byte, 2+pskLen+2), psk...)
binary.BigEndian.PutUint16(out, pskLen)
binary.BigEndian.PutUint16(out[2+pskLen:], pskLen)
return out
}
// PreMasterSecret implements TLS 1.2 Premaster Secret generation given a keypair and a curve
func PreMasterSecret(publicKey, privateKey []byte, curve elliptic.Curve) ([]byte, error) {
switch curve {
case elliptic.X25519:
return curve25519.X25519(privateKey, publicKey)
case elliptic.P256:
return ellipticCurvePreMasterSecret(publicKey, privateKey, ellipticStdlib.P256(), ellipticStdlib.P256())
case elliptic.P384:
return ellipticCurvePreMasterSecret(publicKey, privateKey, ellipticStdlib.P384(), ellipticStdlib.P384())
default:
return nil, errInvalidNamedCurve
}
}
func ellipticCurvePreMasterSecret(publicKey, privateKey []byte, c1, c2 ellipticStdlib.Curve) ([]byte, error) {
x, y := ellipticStdlib.Unmarshal(c1, publicKey)
if x == nil || y == nil {
return nil, errInvalidNamedCurve
}
result, _ := c2.ScalarMult(x, y, privateKey)
preMasterSecret := make([]byte, (c2.Params().BitSize+7)>>3)
resultBytes := result.Bytes()
copy(preMasterSecret[len(preMasterSecret)-len(resultBytes):], resultBytes)
return preMasterSecret, nil
}
// PHash is PRF is the SHA-256 hash function is used for all cipher suites
// defined in this TLS 1.2 document and in TLS documents published prior to this
// document when TLS 1.2 is negotiated. New cipher suites MUST explicitly
// specify a PRF and, in general, SHOULD use the TLS PRF with SHA-256 or a
// stronger standard hash function.
//
// P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
// HMAC_hash(secret, A(2) + seed) +
// HMAC_hash(secret, A(3) + seed) + ...
//
// A() is defined as:
//
// A(0) = seed
// A(i) = HMAC_hash(secret, A(i-1))
//
// P_hash can be iterated as many times as necessary to produce the
// required quantity of data. For example, if P_SHA256 is being used to
// create 80 bytes of data, it will have to be iterated three times
// (through A(3)), creating 96 bytes of output data; the last 16 bytes
// of the final iteration will then be discarded, leaving 80 bytes of
// output data.
//
// https://tools.ietf.org/html/rfc4346w
func PHash(secret, seed []byte, requestedLength int, h HashFunc) ([]byte, error) {
hmacSHA256 := func(key, data []byte) ([]byte, error) {
mac := hmac.New(h, key)
if _, err := mac.Write(data); err != nil {
return nil, err
}
return mac.Sum(nil), nil
}
var err error
lastRound := seed
out := []byte{}
iterations := int(math.Ceil(float64(requestedLength) / float64(h().Size())))
for i := 0; i < iterations; i++ {
lastRound, err = hmacSHA256(secret, lastRound)
if err != nil {
return nil, err
}
withSecret, err := hmacSHA256(secret, append(lastRound, seed...))
if err != nil {
return nil, err
}
out = append(out, withSecret...)
}
return out[:requestedLength], nil
}
// ExtendedMasterSecret generates a Extended MasterSecret as defined in
// https://tools.ietf.org/html/rfc7627
func ExtendedMasterSecret(preMasterSecret, sessionHash []byte, h HashFunc) ([]byte, error) {
seed := append([]byte(extendedMasterSecretLabel), sessionHash...)
return PHash(preMasterSecret, seed, 48, h)
}
// MasterSecret generates a TLS 1.2 MasterSecret
func MasterSecret(preMasterSecret, clientRandom, serverRandom []byte, h HashFunc) ([]byte, error) {
seed := append(append([]byte(masterSecretLabel), clientRandom...), serverRandom...)
return PHash(preMasterSecret, seed, 48, h)
}
// GenerateEncryptionKeys is the final step TLS 1.2 PRF. Given all state generated so far generates
// the final keys need for encryption
func GenerateEncryptionKeys(masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int, h HashFunc) (*EncryptionKeys, error) {
seed := append(append([]byte(keyExpansionLabel), serverRandom...), clientRandom...)
keyMaterial, err := PHash(masterSecret, seed, (2*macLen)+(2*keyLen)+(2*ivLen), h)
if err != nil {
return nil, err
}
clientMACKey := keyMaterial[:macLen]
keyMaterial = keyMaterial[macLen:]
serverMACKey := keyMaterial[:macLen]
keyMaterial = keyMaterial[macLen:]
clientWriteKey := keyMaterial[:keyLen]
keyMaterial = keyMaterial[keyLen:]
serverWriteKey := keyMaterial[:keyLen]
keyMaterial = keyMaterial[keyLen:]
clientWriteIV := keyMaterial[:ivLen]
keyMaterial = keyMaterial[ivLen:]
serverWriteIV := keyMaterial[:ivLen]
return &EncryptionKeys{
MasterSecret: masterSecret,
ClientMACKey: clientMACKey,
ServerMACKey: serverMACKey,
ClientWriteKey: clientWriteKey,
ServerWriteKey: serverWriteKey,
ClientWriteIV: clientWriteIV,
ServerWriteIV: serverWriteIV,
}, nil
}
func prfVerifyData(masterSecret, handshakeBodies []byte, label string, hashFunc HashFunc) ([]byte, error) {
h := hashFunc()
if _, err := h.Write(handshakeBodies); err != nil {
return nil, err
}
seed := append([]byte(label), h.Sum(nil)...)
return PHash(masterSecret, seed, 12, hashFunc)
}
// VerifyDataClient is caled on the Client Side to either verify or generate the VerifyData message
func VerifyDataClient(masterSecret, handshakeBodies []byte, h HashFunc) ([]byte, error) {
return prfVerifyData(masterSecret, handshakeBodies, verifyDataClientLabel, h)
}
// VerifyDataServer is caled on the Server Side to either verify or generate the VerifyData message
func VerifyDataServer(masterSecret, handshakeBodies []byte, h HashFunc) ([]byte, error) {
return prfVerifyData(masterSecret, handshakeBodies, verifyDataServerLabel, h)
}