blob: 71d99a25c53331f3b6fe7ca287a5c76d0a59aa25 [file] [log] [blame]
// Copyright (c) 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_THIRD_PARTY_QUIC_CORE_CRYPTO_QUIC_TLS_ADAPTER_H_
#define NET_THIRD_PARTY_QUIC_CORE_CRYPTO_QUIC_TLS_ADAPTER_H_
#include "net/third_party/quic/core/crypto/crypto_message_parser.h"
#include "net/third_party/quic/core/quic_error_codes.h"
#include "net/third_party/quic/core/quic_types.h"
#include "net/third_party/quic/platform/api/quic_export.h"
#include "net/third_party/quic/platform/api/quic_string.h"
#include "net/third_party/quic/platform/api/quic_string_piece.h"
#include "third_party/boringssl/src/include/openssl/bio.h"
namespace quic {
// QuicTlsAdapter provides an implementation of CryptoMessageParser that takes
// incoming messages and provides them to be read in a BIO (used by the TLS
// stack to read incoming messages). Messages written to the BIO by the TLS
// stack are provided to the QuicTlsAdapter's consumer through the
// OnDataReceived method of the consumer's implementation of
// QuicTlsAdapter::Visitor.
//
// QuicTlsAdapter also provides an implementation of the BIO interface,
// openssl's abstraction used by the TLS stack for I/O. The BIO interface
// provides BIO_read, BIO_write, and BIO_flush methods, with an API very similar
// to Berkeley sockets. This is a non-blocking interface - if data is not
// available for the BIO consumer to read with BIO_read, it returns 0 bytes of
// data, and the BIO consumer must handle waiting for more data and only calling
// BIO_read once data is available to read. With a QuicTlsAdapter, the signal
// that data is available to read is provided by
// QuicTlsAdapter::Visitor::OnDataAvailableForBIO.
//
// In effect, the QuicTlsAdapter moves messages between the QuicCryptoStream and
// the TLS stack. On one end, the QuicTlsAdapter implements CryptoMessageParser
// to take incoming messages and make them available to be read through the BIO,
// and on the other end, it takes messages written to the BIO and once the BIO
// flushes them, sends them out to the QuicStream via the
// QuicTlsAdapter::Visitor.
//
// Data flows from a QuicCryptoStream to the TLS stack like so:
// 1. QuicCryptoStream::OnDataAvailable is called (by QuicStream) when data is
// available on the stream.
// 2. OnDataAvailable calls CryptoMessageParser::ProcessInput; in the case of a
// TLS crypto stream, this is QuicTlsAdapter::ProcessInput.
// 3. ProcessInput saves the data to QuicTlsAdapter's read buffer, and signals
// that data is available to read by calling
// QuicTlsAdapter::Visitor::OnDataAvailableForBIO.
// 4. TlsHandshaker (which implements QuicTlsAdapter::Visitor) receives the
// OnDataAvailableForBIO, and has the TLS stack continue its handshake.
// 5. The TLS stack calls BIO_read to read handshake messages, and this call is
// made on a BIO backed by QuicTlsAdapter.
// 6. BIO_read calls QuicTlsAdapter::BIOReadWrapper, which calls
// QuicTlsAdapter::Read (on the appropriate instance) which provides the
// data from the read buffer written to by QuicTlsAdapter::ProcessInput.
//
// Data flows from the TLS stack to the QUIC crypto stream like so:
// 1. The TLS stack makes multiple calls to BIO_write as it generates handshake
// messages. Via QuicTlsAdapter::BIOWriteWrapper and QuicTlsAdapter::Write,
// this data gets appended to the QuicTlsAdapter's write buffer.
// 2. Once the TLS stack has written a flight of handshake messages, it calls
// BIO_flush. This, via QuicTlsAdapter::BIOCtrlWrapper and
// QuicTlsAdapter::Flush, signals to QuicTlsAdapter's Visitor that data has
// been received.
// 3. QuicTlsAdapter::Flush calls
// QuicTlsAdapter::Visitor::OnDataReceivedFromBIO with the contents of the
// write buffer.
// 4. TlsHandshaker receives the data from OnDataReceivedFromBIO, and writes it
// to the QUIC crypto stream.
class QUIC_EXPORT QuicTlsAdapter : public CryptoMessageParser {
public:
// QuicTlsAdapter::Visitor is notified whenever data is received (in either
// direction). When data is read from the QUIC crypto stream,
// Visitor::OnDataAvailableForBIO is called so that the Visitor can continue
// reading from the BIO. (E.g. in the case of a TlsHandshaker as the Visitor,
// it would continue the TLS handshake, which uses a BIO for I/O.) When data
// is written to a QuicTlsAdapter's BIO interface and then flushed,
// Visitor::OnDataReceivedFromBIO is called to provide the Visitor with the
// data to write to the QUIC crypto stream.
class QUIC_EXPORT Visitor {
public:
virtual ~Visitor() {}
// OnDataAvailableForBIO is called when QuicTlsAdapter has received data
// (via ProcessInput) that is now available to be read by the BIO.
virtual void OnDataAvailableForBIO() = 0;
// OnDataReceivedFromBIO is called when data is written to the BIO. For
// example, when the TLS stack writes messages to the BIO and then flushes
// them, the resulting data will be made available to the Visitor via this
// method, so that the Visitor can write the messages to the QuicStream. The
// stringpiece |data| is only valid during the execution of this function;
// implementations must consume all of |data|.
virtual void OnDataReceivedFromBIO(const QuicStringPiece& data) = 0;
};
// Constructs a QuicTlsAdapter that will notify |visitor| when data is
// available in either direction. The provided Visitor must outlive the
// QuicTlsAdapter.
explicit QuicTlsAdapter(Visitor* visitor);
~QuicTlsAdapter() override;
QuicErrorCode error() const override;
const QuicString& error_detail() const override;
bool ProcessInput(QuicStringPiece input, EncryptionLevel level) override;
size_t InputBytesRemaining() const override;
BIO* bio() { return bio_.get(); }
private:
// The following methods, Read, Write, and Flush, are used to implement the
// BIO.
// Read copies up to |len| bytes from |read_buffer_| into |out|. It returns
// the number of bytes copied, zero on EOF, or a negative number on error.
int Read(char* out, int len);
// Write appends |len| bytes from |in| to |write_buffer_|. It returns |len|,
// or a negative number on error.
int Write(const char* in, int len);
// Flush calls Visitor::OnDataReceivedFromBIO with the data in
// |write_buffer_| and then empties the buffer.
void Flush();
// Used by the static BIO*Wrapper methods to get the QuicTlsAdapter instance
// to call Read/Write/Flush on.
static QuicTlsAdapter* GetAdapter(BIO* bio);
// Functions used to build a BIO_METHOD vtable. BIOReadWrapper calls Read,
// BIOWriteWrapper calls Write, and BIOCtrlWrapper calls Flush if |cmd| is
// |BIO_CTRL_FLUSH|.
static int BIOReadWrapper(BIO* bio, char* out, int len);
static int BIOWriteWrapper(BIO* bio, const char* in, int len);
// BIOCtrlWrapper has the type it does so it can be used as the |ctrl| field
// in a BIO_METHOD struct, hence the use of long as an argument and return
// type.
// NOLINTNEXTLINE
static long BIOCtrlWrapper(BIO* bio, int cmd, long larg, void* parg);
static const BIO_METHOD kBIOMethod;
// Visitor to call when QuicTlsAdapter receives data (in either direction).
Visitor* visitor_;
bssl::UniquePtr<BIO> bio_;
// Buffer of data received from ProcessInput waiting to be read by the BIO.
QuicString read_buffer_;
// Buffer of data received from the BIO waiting to be handed off to
// Visitor::OnDataReceivedFromBIO.
QuicString write_buffer_;
QuicString error_detail_;
};
} // namespace quic
#endif // NET_THIRD_PARTY_QUIC_CORE_CRYPTO_QUIC_TLS_ADAPTER_H_