// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

// Package prf implements TLS 1.2 Pseudorandom functions
package prf import ( //nolint:gci ellipticStdlib ) 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 ( *EncryptionKeys) () string { return fmt.Sprintf(`encryptionKeys: - masterSecret: %#v - clientMACKey: %#v - serverMACKey: %#v - clientWriteKey: %#v - serverWriteKey: %#v - clientWriteIV: %#v - serverWriteIV: %#v `, .MasterSecret, .ClientMACKey, .ServerMACKey, .ClientWriteKey, .ServerWriteKey, .ClientWriteIV, .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 ( []byte) []byte { := uint16(len()) //nolint:gosec // G115 := append(make([]byte, 2++2), ...) binary.BigEndian.PutUint16(, ) binary.BigEndian.PutUint16([2+:], ) return } // EcdhePSKPreMasterSecret implements TLS 1.2 Premaster Secret generation given a psk, a keypair and a curve // // https://datatracker.ietf.org/doc/html/rfc5489#section-2 func (, , []byte, elliptic.Curve) ([]byte, error) { , := PreMasterSecret(, , ) if != nil { return nil, } := make([]byte, 2+len()+2+len()) // write preMasterSecret length := 0 binary.BigEndian.PutUint16([:], uint16(len())) //nolint:gosec // G115 += 2 // write preMasterSecret copy([:], ) += len() // write psk length binary.BigEndian.PutUint16([:], uint16(len())) //nolint:gosec // G115 += 2 // write psk copy([:], ) return , nil } // PreMasterSecret implements TLS 1.2 Premaster Secret generation given a keypair and a curve. func (, []byte, elliptic.Curve) ([]byte, error) { switch { case elliptic.X25519: return curve25519.X25519(, ) case elliptic.P256: return ellipticCurvePreMasterSecret(, , ellipticStdlib.P256(), ellipticStdlib.P256()) case elliptic.P384: return ellipticCurvePreMasterSecret(, , ellipticStdlib.P384(), ellipticStdlib.P384()) default: return nil, errInvalidNamedCurve } } func ellipticCurvePreMasterSecret(, []byte, , ellipticStdlib.Curve) ([]byte, error) { , := ellipticStdlib.Unmarshal(, ) if == nil || == nil { return nil, errInvalidNamedCurve } , := .ScalarMult(, , ) := make([]byte, (.Params().BitSize+7)>>3) := .Bytes() copy([len()-len():], ) return , 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 (, []byte, int, HashFunc) ([]byte, error) { := func(, []byte) ([]byte, error) { := hmac.New(, ) if , := .Write(); != nil { return nil, } return .Sum(nil), nil } var error := := []byte{} := int(math.Ceil(float64() / float64(().Size()))) for := 0; < ; ++ { , = (, ) if != nil { return nil, } , := (, append(, ...)) if != nil { return nil, } = append(, ...) } return [:], nil } // ExtendedMasterSecret generates a Extended MasterSecret as defined in // https://tools.ietf.org/html/rfc7627 func (, []byte, HashFunc) ([]byte, error) { := append([]byte(extendedMasterSecretLabel), ...) return PHash(, , 48, ) } // MasterSecret generates a TLS 1.2 MasterSecret. func (, , []byte, HashFunc) ([]byte, error) { := append(append([]byte(masterSecretLabel), ...), ...) return PHash(, , 48, ) } // GenerateEncryptionKeys is the final step TLS 1.2 PRF. Given all state generated so far generates // the final keys need for encryption. func ( , , []byte, , , int, HashFunc, ) (*EncryptionKeys, error) { := append(append([]byte(keyExpansionLabel), ...), ...) , := PHash(, , (2*)+(2*)+(2*), ) if != nil { return nil, } := [:] = [:] := [:] = [:] := [:] = [:] := [:] = [:] := [:] = [:] := [:] return &EncryptionKeys{ MasterSecret: , ClientMACKey: , ServerMACKey: , ClientWriteKey: , ServerWriteKey: , ClientWriteIV: , ServerWriteIV: , }, nil } func prfVerifyData(, []byte, string, HashFunc) ([]byte, error) { := () if , := .Write(); != nil { return nil, } := append([]byte(), .Sum(nil)...) return PHash(, , 12, ) } // VerifyDataClient is caled on the Client Side to either verify or generate the VerifyData message. func (, []byte, HashFunc) ([]byte, error) { return prfVerifyData(, , verifyDataClientLabel, ) } // VerifyDataServer is caled on the Server Side to either verify or generate the VerifyData message. func (, []byte, HashFunc) ([]byte, error) { return prfVerifyData(, , verifyDataServerLabel, ) }