diff --git a/Sources/SwiftNetwork/QUIC/Protector.swift b/Sources/SwiftNetwork/QUIC/Protector.swift index 649f5cb..fde7fd7 100644 --- a/Sources/SwiftNetwork/QUIC/Protector.swift +++ b/Sources/SwiftNetwork/QUIC/Protector.swift @@ -647,12 +647,22 @@ struct Protector: ~Copyable, PrefixedLoggable { deriveInitialSecrets(destinationCID: destinationCID) } - private func encode(label: String, secretLength: Int) -> [UInt8] { + /// Encodes the HKDF label for `label` and passes it to `body`. + /// + /// The encoding only has to last for one expansion, so it is built in an inline array rather than on the heap. + private func withEncodedLabel( + _ label: String, + secretLength: Int, + _ body: (UnsafeRawBufferPointer) -> Result + ) -> Result { let quicLabel = "tls13 " let labelLength = quicLabel.utf8.count + label.utf8.count + // TLS caps a label at 255 bytes (RFC 8446 Section 7.1), so the encoding is at most 259: 2 bytes of length, + // a 1-byte label length, the label, and a 1-byte length for the empty context. + precondition(labelLength <= 255, "HKDF label is longer than TLS allows") // 2 is for the length, 1 byte prefix for each label, 1 byte for context let totalLength = 2 + 1 + labelLength + 1 - var result = [UInt8](repeating: 0, count: totalLength) + var result = InlineArray<259, UInt8>(repeating: 0) var index = 0 // Encode the length of the secret @@ -662,13 +672,19 @@ struct Protector: ~Copyable, PrefixedLoggable { index += 1 result[index] = UInt8(labelLength) index += 1 - result.replaceSubrange(index.. SymmetricKey { - let encodedLabel = encode(label: label, secretLength: outputSecretLength) - return HKDF.expand( - pseudoRandomKey: inputSecret, - info: encodedLabel, - outputByteCount: outputSecretLength - ) + withEncodedLabel(label, secretLength: outputSecretLength) { encodedLabel in + HKDF.expand( + pseudoRandomKey: inputSecret, + info: encodedLabel, + outputByteCount: outputSecretLength + ) + } } private func deriveWithSHA384( @@ -689,12 +706,13 @@ struct Protector: ~Copyable, PrefixedLoggable { label: String, outputSecretLength: Int ) -> SymmetricKey { - let encodedLabel = encode(label: label, secretLength: outputSecretLength) - return HKDF.expand( - pseudoRandomKey: inputSecret, - info: encodedLabel, - outputByteCount: outputSecretLength - ) + withEncodedLabel(label, secretLength: outputSecretLength) { encodedLabel in + HKDF.expand( + pseudoRandomKey: inputSecret, + info: encodedLabel, + outputByteCount: outputSecretLength + ) + } } mutating func deriveInitialSecrets(destinationCID: QUICConnectionID) {