xref: /freebsd/crypto/openssl/doc/designs/quic-design/record-layer.md (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre ProncheryDesign Problem: Abstract Record Layer
2*e7be843bSPierre Pronchery=====================================
3*e7be843bSPierre Pronchery
4*e7be843bSPierre ProncheryThis document covers the design of an abstract record layer for use in (D)TLS.
5*e7be843bSPierre ProncheryThe QUIC record layer is handled separately.
6*e7be843bSPierre Pronchery
7*e7be843bSPierre ProncheryA record within this document refers to a packet of data. It will typically
8*e7be843bSPierre Proncherycontain some header data and some payload data, and will often be
9*e7be843bSPierre Proncherycryptographically protected. A record may or may not have a one-to-one
10*e7be843bSPierre Proncherycorrespondence with network packets, depending on the implementation details of
11*e7be843bSPierre Proncheryan individual record layer.
12*e7be843bSPierre Pronchery
13*e7be843bSPierre ProncheryThe term record comes directly from the TLS and DTLS specifications.
14*e7be843bSPierre Pronchery
15*e7be843bSPierre ProncheryLibssl supports a number of different types of record layer, and record layer
16*e7be843bSPierre Proncheryvariants:
17*e7be843bSPierre Pronchery
18*e7be843bSPierre Pronchery- Standard TLS record layer
19*e7be843bSPierre Pronchery- Standard DTLS record layer
20*e7be843bSPierre Pronchery- Kernel TLS record layer
21*e7be843bSPierre Pronchery
22*e7be843bSPierre ProncheryWithin the TLS record layer there are options to handle "multiblock" and
23*e7be843bSPierre Pronchery"pipelining" which are different approaches for supporting the reading or
24*e7be843bSPierre Proncherywriting of multiple records at the same time. All record layer variants also
25*e7be843bSPierre Proncheryhave to be able to handle different protocol versions.
26*e7be843bSPierre Pronchery
27*e7be843bSPierre ProncheryThese different record layer implementations, variants and protocol versions
28*e7be843bSPierre Proncheryhave each been added at different times and over many years. The result is that
29*e7be843bSPierre Proncheryeach took slightly different approaches for achieving the goals that were
30*e7be843bSPierre Proncheryappropriate at the time and the integration points where they were added were
31*e7be843bSPierre Proncheryspread throughout the code.
32*e7be843bSPierre Pronchery
33*e7be843bSPierre ProncheryThe introduction of QUIC support will see the implementation of a new record
34*e7be843bSPierre Proncherylayer, i.e. the QUIC-TLS record layer. This refers to the "inner" TLS
35*e7be843bSPierre Proncheryimplementation used by QUIC. Records here will be in the form of QUIC CRYPTO
36*e7be843bSPierre Proncheryframes.
37*e7be843bSPierre Pronchery
38*e7be843bSPierre ProncheryRequirements
39*e7be843bSPierre Pronchery------------
40*e7be843bSPierre Pronchery
41*e7be843bSPierre ProncheryThe technical requirements
42*e7be843bSPierre Pronchery[document](https://github.com/openssl/openssl/blob/master/doc/designs/quic-design/quic-requirements.md)
43*e7be843bSPierre Proncherylists these requirements that are relevant to the record layer:
44*e7be843bSPierre Pronchery
45*e7be843bSPierre Pronchery* The current libssl record layer includes support for TLS, DTLS and KTLS. QUIC
46*e7be843bSPierre Pronchery  will introduce another variant and there may be more over time. The OMC
47*e7be843bSPierre Pronchery  requires a pluggable record layer interface to be implemented to enable this
48*e7be843bSPierre Pronchery  to be less intrusive, more maintainable, and to harmonize the existing record
49*e7be843bSPierre Pronchery  layer interactions between TLS, DTLS, KTLS and the planned QUIC protocols. The
50*e7be843bSPierre Pronchery  pluggable record layer interface will be internal only for MVP and be public
51*e7be843bSPierre Pronchery  in a future release.
52*e7be843bSPierre Pronchery
53*e7be843bSPierre Pronchery* The minimum viable product (MVP) for the next release is a pluggable record
54*e7be843bSPierre Pronchery  layer interface and a single stream QUIC client in the form of s_client that
55*e7be843bSPierre Pronchery  does not require significant API changes. In the MVP, interoperability should
56*e7be843bSPierre Pronchery  be prioritized over strict standards compliance.
57*e7be843bSPierre Pronchery
58*e7be843bSPierre Pronchery* Once we have a fully functional QUIC implementation (in a subsequent release),
59*e7be843bSPierre Pronchery  it should be possible for external libraries to be able to use the pluggable
60*e7be843bSPierre Pronchery  record layer interface and it should offer a stable ABI (via a provider).
61*e7be843bSPierre Pronchery
62*e7be843bSPierre ProncheryThe MVP requirements are:
63*e7be843bSPierre Pronchery
64*e7be843bSPierre Pronchery* a pluggable record layer (not public for MVP)
65*e7be843bSPierre Pronchery
66*e7be843bSPierre ProncheryCandidate Solutions that were considered
67*e7be843bSPierre Pronchery----------------------------------------
68*e7be843bSPierre Pronchery
69*e7be843bSPierre ProncheryThis section outlines two different solution approaches that were considered for
70*e7be843bSPierre Proncherythe abstract record layer
71*e7be843bSPierre Pronchery
72*e7be843bSPierre Pronchery### Use a METHOD based approach
73*e7be843bSPierre Pronchery
74*e7be843bSPierre ProncheryA METHOD based approach is simply a structure containing function pointers. It
75*e7be843bSPierre Proncheryis a common pattern in the OpenSSL codebase. Different strategies for
76*e7be843bSPierre Proncheryimplementing a METHOD can be employed, but these differences are hidden from
77*e7be843bSPierre Proncherythe caller of the METHOD.
78*e7be843bSPierre Pronchery
79*e7be843bSPierre ProncheryIn this solution we would seek to implement a different METHOD for each of the
80*e7be843bSPierre Proncherytypes of record layer that we support, i.e. there would be one for the standard
81*e7be843bSPierre ProncheryTLS record layer, one for the standard DTLS record layer, one for kernel TLS and
82*e7be843bSPierre Proncheryone for QUIC-TLS.
83*e7be843bSPierre Pronchery
84*e7be843bSPierre ProncheryIn the MVP the METHOD approach would be private. However, once it has
85*e7be843bSPierre Proncherystabilised, it would be straight forward to supply public functions to enable
86*e7be843bSPierre Proncheryend user applications to construct their own METHODs.
87*e7be843bSPierre Pronchery
88*e7be843bSPierre ProncheryThis option is simpler to implement than the alternative of having a provider
89*e7be843bSPierre Proncherybased approach. However it could be used as a "stepping stone" for that, i.e.
90*e7be843bSPierre Proncherythe MVP could implement a METHOD based approach, and subsequent releases could
91*e7be843bSPierre Proncheryconvert the METHODs into fully fetchable algorithms.
92*e7be843bSPierre Pronchery
93*e7be843bSPierre ProncheryPros:
94*e7be843bSPierre Pronchery
95*e7be843bSPierre Pronchery* Simple approach that has been used historically in OpenSSL
96*e7be843bSPierre Pronchery* Could be used as the basis for the final public solution
97*e7be843bSPierre Pronchery* Could also be used as the basis for a fetchable solution in a subsequent
98*e7be843bSPierre Pronchery  release
99*e7be843bSPierre Pronchery* If this option is later converted to a fetchable solution then much of the
100*e7be843bSPierre Pronchery  effort involved in making the record layer fetchable can be deferred to a
101*e7be843bSPierre Pronchery  later release
102*e7be843bSPierre Pronchery
103*e7be843bSPierre ProncheryCons:
104*e7be843bSPierre Pronchery
105*e7be843bSPierre Pronchery* Not consistent with the provider based approach we used for extensibility in
106*e7be843bSPierre Pronchery  3.0
107*e7be843bSPierre Pronchery* If this option is implemented and later converted to a fetchable solution then
108*e7be843bSPierre Pronchery  some rework might be required
109*e7be843bSPierre Pronchery
110*e7be843bSPierre Pronchery### Use a provider based approach
111*e7be843bSPierre Pronchery
112*e7be843bSPierre ProncheryThis approach is very similar to the alternative METHOD based approach. The
113*e7be843bSPierre Proncherymain difference is that the record layer implementations would be held in
114*e7be843bSPierre Proncheryproviders and "fetched" in much the same way that cryptographic algorithms are
115*e7be843bSPierre Proncheryfetched in OpenSSL 3.0.
116*e7be843bSPierre Pronchery
117*e7be843bSPierre ProncheryThis approach is more consistent with the approach adopted for extensibility in
118*e7be843bSPierre Pronchery3.0. METHODS are being deprecated with providers being used extensively.
119*e7be843bSPierre Pronchery
120*e7be843bSPierre ProncheryComplex objects (e.g. an `SSL` object) cannot be passed across the
121*e7be843bSPierre Proncherylibssl/provider boundary. This imposes some restrictions on the design of the
122*e7be843bSPierre Proncheryfunctions that can be implemented. Additionally implementing the infrastructure
123*e7be843bSPierre Proncheryfor a new fetchable operation is more involved than a METHOD based approach.
124*e7be843bSPierre Pronchery
125*e7be843bSPierre ProncheryPros:
126*e7be843bSPierre Pronchery
127*e7be843bSPierre Pronchery* Consistent with the extensibility solution used in 3.0
128*e7be843bSPierre Pronchery* If this option is implemented immediately in the MVP then it would avoid later
129*e7be843bSPierre Pronchery  rework if adopted in a subsequent release
130*e7be843bSPierre Pronchery
131*e7be843bSPierre ProncheryCons:
132*e7be843bSPierre Pronchery
133*e7be843bSPierre Pronchery* More complicated to implement than the simple METHOD based approach
134*e7be843bSPierre Pronchery* Cannot pass complex objects across the provider boundary
135*e7be843bSPierre Pronchery
136*e7be843bSPierre Pronchery### Selected solution
137*e7be843bSPierre Pronchery
138*e7be843bSPierre ProncheryThe METHOD based approach has been selected for MVP, with the expectation that
139*e7be843bSPierre Proncherysubsequent releases will convert it to a full provider based solution accessible
140*e7be843bSPierre Proncheryto third party applications.
141*e7be843bSPierre Pronchery
142*e7be843bSPierre ProncherySolution Description: The METHOD based approach
143*e7be843bSPierre Pronchery-----------------------------------------------
144*e7be843bSPierre Pronchery
145*e7be843bSPierre ProncheryThis section focuses on the selected approach of using METHODs and further
146*e7be843bSPierre Proncheryelaborates on how the design works.
147*e7be843bSPierre Pronchery
148*e7be843bSPierre ProncheryA proposed internal record method API is given in
149*e7be843bSPierre Pronchery[Appendix A](#appendix-a-the-internal-record-method-api).
150*e7be843bSPierre Pronchery
151*e7be843bSPierre ProncheryAn `OSSL_RECORD_METHOD` represents the implementation of a particular type of
152*e7be843bSPierre Proncheryrecord layer. It contains a set of function pointers to represent the various
153*e7be843bSPierre Proncheryactions that can be performed by a record layer.
154*e7be843bSPierre Pronchery
155*e7be843bSPierre ProncheryAn `OSSL_RECORD_LAYER` object represents a specific instantiation of a
156*e7be843bSPierre Proncheryparticular `OSSL_RECORD_METHOD`. It contains the state used by that
157*e7be843bSPierre Pronchery`OSSL_RECORD_METHOD` for a specific connection (i.e. `SSL` object). Any `SSL`
158*e7be843bSPierre Proncheryobject will have at least 2 `OSSL_RECORD_LAYER` objects associated with it - one
159*e7be843bSPierre Proncheryfor reading and one for writing. In some cases there may be more than 2 - for
160*e7be843bSPierre Proncheryexample in DTLS it may be necessary to retransmit records from a previous epoch.
161*e7be843bSPierre ProncheryThere will be different `OSSL_RECORD_LAYER` objects for different protection
162*e7be843bSPierre Proncherylevels or epochs. It may be that different `OSSL_RECORD_METHOD`s are used for
163*e7be843bSPierre Proncherydifferent protection levels. For example a connection might start using the
164*e7be843bSPierre Proncherystandard TLS record layer during the handshake, and later transition to using
165*e7be843bSPierre Proncherythe kernel TLS record layer once the handshake is complete.
166*e7be843bSPierre Pronchery
167*e7be843bSPierre ProncheryA new `OSSL_RECORD_LAYER` is created by calling the `new` function of the
168*e7be843bSPierre Proncheryassociated `OSSL_RECORD_METHOD`, and freed by calling the `free` function. The
169*e7be843bSPierre Proncheryparameters to the `new` function also supply all of the cryptographic state
170*e7be843bSPierre Pronchery(e.g. keys, ivs, symmetric encryption algorithms, hash algorithm etc) used by
171*e7be843bSPierre Proncherythe record layer. The internal structure details of an `OSSL_RECORD_LAYER` are
172*e7be843bSPierre Proncheryentirely hidden to the rest of libssl and can be specific to the given
173*e7be843bSPierre Pronchery`OSSL_RECORD_METHOD`. In practice the standard internal TLS, DTLS and KTLS
174*e7be843bSPierre Pronchery`OSSL_RECORD_METHOD`s all use a common `OSSL_RECORD_LAYER` structure. However
175*e7be843bSPierre Proncherythe QUIC-TLS implementation is likely to use a different structure layout.
176*e7be843bSPierre Pronchery
177*e7be843bSPierre ProncheryAll of the header and payload data for a single record will be represented by an
178*e7be843bSPierre Pronchery`OSSL_RECORD_TEMPLATE` structure when writing. Libssl will construct a set of
179*e7be843bSPierre Proncherytemplates for records to be written out and pass them to the "write" record
180*e7be843bSPierre Proncherylayer. In most cases only a single record is ever written out at one time,
181*e7be843bSPierre Proncheryhowever there are some cases (such as when using the "pipelining" or
182*e7be843bSPierre Pronchery"multibuffer" optimisations) that multiple records can be written in one go.
183*e7be843bSPierre Pronchery
184*e7be843bSPierre ProncheryIt is the record layer's responsibility to know whether it can support multiple
185*e7be843bSPierre Proncheryrecords in one go or not. It is libssl's responsibility to split the payload
186*e7be843bSPierre Proncherydata into `OSSL_RECORD_TEMPLATE` objects. Libssl will call the record layer's
187*e7be843bSPierre Pronchery`get_max_records()` function to determine how many records a given payload
188*e7be843bSPierre Proncheryshould be split into. If that value is more than one, then libssl will construct
189*e7be843bSPierre Pronchery(up to) that number of `OSSL_RECORD_TEMPLATE`s and pass the whole set to the
190*e7be843bSPierre Proncheryrecord layer's `write_records()` function.
191*e7be843bSPierre Pronchery
192*e7be843bSPierre ProncheryThe implementation of the `write_records` function must construct the
193*e7be843bSPierre Proncheryappropriate number of records, apply protection to them as required and then
194*e7be843bSPierre Proncherywrite them out to the underlying transport layer BIO. In the event that not
195*e7be843bSPierre Proncheryall the data can be transmitted at the current time (e.g. because the underlying
196*e7be843bSPierre Proncherytransport has indicated a retry), then the `write_records` function will return
197*e7be843bSPierre Proncherya "retry" response. It is permissible for the data to be partially sent, but
198*e7be843bSPierre Proncherythis is still considered a "retry" until all of the data is sent.
199*e7be843bSPierre Pronchery
200*e7be843bSPierre ProncheryOn a success or retry response libssl may free its buffers immediately. The
201*e7be843bSPierre Pronchery`OSSL_RECORD_LAYER` object will have to buffer any untransmitted data until it
202*e7be843bSPierre Proncheryis eventually sent.
203*e7be843bSPierre Pronchery
204*e7be843bSPierre ProncheryIf a "retry" occurs, then libssl will subsequently call `retry_write_records`
205*e7be843bSPierre Proncheryand continue to do so until a success return value is received. Libssl will
206*e7be843bSPierre Proncherynever call `write_records` a second time until a previous call to
207*e7be843bSPierre Pronchery`write_records` or `retry_write_records` has indicated success.
208*e7be843bSPierre Pronchery
209*e7be843bSPierre ProncheryLibssl will read records by calling the `read_record` function. The
210*e7be843bSPierre Pronchery`OSSL_RECORD_LAYER` may read multiple records in one go and buffer them, but the
211*e7be843bSPierre Pronchery`read_record` function only ever returns one record at a time. The
212*e7be843bSPierre Pronchery`OSSL_RECORD_LAYER` object owns the buffers for the record that has been read
213*e7be843bSPierre Proncheryand supplies a pointer into that buffer back to libssl for the payload data, as
214*e7be843bSPierre Proncherywell as other information about the record such as its length and the type of
215*e7be843bSPierre Proncherydata contained in it. Each record has an associated opaque handle `rechandle`.
216*e7be843bSPierre ProncheryThe record data must remain buffered by the `OSSL_RECORD_LAYER` until it has
217*e7be843bSPierre Proncherybeen released via a call to `release_record()`.
218*e7be843bSPierre Pronchery
219*e7be843bSPierre ProncheryA record layer implementation supplies various functions to enable libssl to
220*e7be843bSPierre Proncheryquery the current state. In particular:
221*e7be843bSPierre Pronchery
222*e7be843bSPierre Pronchery`unprocessed_read_pending()`: to query whether there is data buffered that has
223*e7be843bSPierre Proncheryalready been read from the underlying BIO, but not yet processed.
224*e7be843bSPierre Pronchery
225*e7be843bSPierre Pronchery`processed_read_pending()`: to query whether there is data buffered that has
226*e7be843bSPierre Proncherybeen read from the underlying BIO and has been processed. The data is not
227*e7be843bSPierre Proncherynecessarily application data.
228*e7be843bSPierre Pronchery
229*e7be843bSPierre Pronchery`app_data_pending()`: to query the amount of processed application data that is
230*e7be843bSPierre Proncherybuffered and available for immediate read.
231*e7be843bSPierre Pronchery
232*e7be843bSPierre Pronchery`get_alert_code()`: to query the alert code that should be used in the event
233*e7be843bSPierre Proncherythat a previous attempt to read or write records failed.
234*e7be843bSPierre Pronchery
235*e7be843bSPierre Pronchery`get_state()`: to obtain a printable string to describe the current state of the
236*e7be843bSPierre Proncheryrecord layer.
237*e7be843bSPierre Pronchery
238*e7be843bSPierre Pronchery`get_compression()`: to obtain information about the compression method
239*e7be843bSPierre Proncherycurrently being used by the record layer.
240*e7be843bSPierre Pronchery
241*e7be843bSPierre Pronchery`get_max_record_overhead()`: to obtain the maximum amount of bytes the record
242*e7be843bSPierre Proncherylayer will add to the payload bytes before transmission. This does not include
243*e7be843bSPierre Proncheryany expansion that might occur during compression. Currently this is only
244*e7be843bSPierre Proncheryimplemented for DTLS.
245*e7be843bSPierre Pronchery
246*e7be843bSPierre ProncheryIn addition, libssl will tell the record layer about various events that might
247*e7be843bSPierre Proncheryoccur that are relevant to the record layer's operation:
248*e7be843bSPierre Pronchery
249*e7be843bSPierre Pronchery`set1_bio()`: called if the underlying BIO being used by the record layer has
250*e7be843bSPierre Proncherybeen changed.
251*e7be843bSPierre Pronchery
252*e7be843bSPierre Pronchery`set_protocol_version()`: called during protocol version negotiation when a
253*e7be843bSPierre Proncheryspecific protocol version has been selected.
254*e7be843bSPierre Pronchery
255*e7be843bSPierre Pronchery`set_plain_alerts()`: to indicate that receiving unencrypted alerts is allowed
256*e7be843bSPierre Proncheryin the current context, even if normally we would expect to receive encrypted
257*e7be843bSPierre Proncherydata. This is only relevant for TLSv1.3.
258*e7be843bSPierre Pronchery
259*e7be843bSPierre Pronchery`set_first_handshake()`: called at the beginning and end of the first handshake
260*e7be843bSPierre Proncheryfor any given (D)TLS connection.
261*e7be843bSPierre Pronchery
262*e7be843bSPierre Pronchery`set_max_pipelines()`: called to configure the maximum number of pipelines of
263*e7be843bSPierre Proncherydata that the record layer should process in one go. By default this is 1.
264*e7be843bSPierre Pronchery
265*e7be843bSPierre Pronchery`set_in_init()`: called by libssl to tell the record layer whether we are
266*e7be843bSPierre Proncherycurrently `in_init` or not. Defaults to "true".
267*e7be843bSPierre Pronchery
268*e7be843bSPierre Pronchery`set_options()`: called by libssl in the event that the current set of options
269*e7be843bSPierre Proncheryto use has been updated.
270*e7be843bSPierre Pronchery
271*e7be843bSPierre Pronchery`set_max_frag_len()`: called by libssl to set the maximum allowed fragment
272*e7be843bSPierre Proncherylength that is in force at the moment. This might be the result of user
273*e7be843bSPierre Proncheryconfiguration, or it may be negotiated during the handshake.
274*e7be843bSPierre Pronchery
275*e7be843bSPierre Pronchery`increment_sequence_ctr()`: force the record layer to increment its sequence
276*e7be843bSPierre Proncherycounter. In most cases the record layer will entirely manage its own sequence
277*e7be843bSPierre Proncherycounters. However in the DTLSv1_listen() corner case, libssl needs to initialise
278*e7be843bSPierre Proncherythe record layer with an incremented sequence counter.
279*e7be843bSPierre Pronchery
280*e7be843bSPierre Pronchery`alloc_buffers()`: called by libssl to request that the record layer allocate
281*e7be843bSPierre Proncheryits buffers. This is a hint only and the record layer is expected to manage its
282*e7be843bSPierre Proncheryown buffer allocation and freeing.
283*e7be843bSPierre Pronchery
284*e7be843bSPierre Pronchery`free_buffers()`: called by libssl to request that the record layer free its
285*e7be843bSPierre Proncherybuffers. This is a hint only and the record layer is expected to manage its own
286*e7be843bSPierre Proncherybuffer allocation and freeing.
287*e7be843bSPierre Pronchery
288*e7be843bSPierre ProncheryAppendix A: The internal record method API
289*e7be843bSPierre Pronchery------------------------------------------
290*e7be843bSPierre Pronchery
291*e7be843bSPierre ProncheryThe internal recordmethod.h header file for the record method API:
292*e7be843bSPierre Pronchery
293*e7be843bSPierre Pronchery```` C
294*e7be843bSPierre Pronchery/*
295*e7be843bSPierre Pronchery * We use the term "record" here to refer to a packet of data. Records are
296*e7be843bSPierre Pronchery * typically protected via a cipher and MAC, or an AEAD cipher (although not
297*e7be843bSPierre Pronchery * always). This usage of the term record is consistent with the TLS concept.
298*e7be843bSPierre Pronchery * In QUIC the term "record" is not used but it is analogous to the QUIC term
299*e7be843bSPierre Pronchery * "packet". The interface in this file applies to all protocols that protect
300*e7be843bSPierre Pronchery * records/packets of data, i.e. (D)TLS and QUIC. The term record is used to
301*e7be843bSPierre Pronchery * refer to both contexts.
302*e7be843bSPierre Pronchery */
303*e7be843bSPierre Pronchery
304*e7be843bSPierre Pronchery/*
305*e7be843bSPierre Pronchery * An OSSL_RECORD_METHOD is a protocol specific method which provides the
306*e7be843bSPierre Pronchery * functions for reading and writing records for that protocol. Which
307*e7be843bSPierre Pronchery * OSSL_RECORD_METHOD to use for a given protocol is defined by the SSL_METHOD.
308*e7be843bSPierre Pronchery */
309*e7be843bSPierre Proncherytypedef struct ossl_record_method_st OSSL_RECORD_METHOD;
310*e7be843bSPierre Pronchery
311*e7be843bSPierre Pronchery/*
312*e7be843bSPierre Pronchery * An OSSL_RECORD_LAYER is just an externally defined opaque pointer created by
313*e7be843bSPierre Pronchery * the method
314*e7be843bSPierre Pronchery */
315*e7be843bSPierre Proncherytypedef struct ossl_record_layer_st OSSL_RECORD_LAYER;
316*e7be843bSPierre Pronchery
317*e7be843bSPierre Pronchery
318*e7be843bSPierre Pronchery# define OSSL_RECORD_ROLE_CLIENT 0
319*e7be843bSPierre Pronchery# define OSSL_RECORD_ROLE_SERVER 1
320*e7be843bSPierre Pronchery
321*e7be843bSPierre Pronchery# define OSSL_RECORD_DIRECTION_READ  0
322*e7be843bSPierre Pronchery# define OSSL_RECORD_DIRECTION_WRITE 1
323*e7be843bSPierre Pronchery
324*e7be843bSPierre Pronchery/*
325*e7be843bSPierre Pronchery * Protection level. For <= TLSv1.2 only "NONE" and "APPLICATION" are used.
326*e7be843bSPierre Pronchery */
327*e7be843bSPierre Pronchery# define OSSL_RECORD_PROTECTION_LEVEL_NONE        0
328*e7be843bSPierre Pronchery# define OSSL_RECORD_PROTECTION_LEVEL_EARLY       1
329*e7be843bSPierre Pronchery# define OSSL_RECORD_PROTECTION_LEVEL_HANDSHAKE   2
330*e7be843bSPierre Pronchery# define OSSL_RECORD_PROTECTION_LEVEL_APPLICATION 3
331*e7be843bSPierre Pronchery
332*e7be843bSPierre Pronchery# define OSSL_RECORD_RETURN_SUCCESS           1
333*e7be843bSPierre Pronchery# define OSSL_RECORD_RETURN_RETRY             0
334*e7be843bSPierre Pronchery# define OSSL_RECORD_RETURN_NON_FATAL_ERR    -1
335*e7be843bSPierre Pronchery# define OSSL_RECORD_RETURN_FATAL            -2
336*e7be843bSPierre Pronchery# define OSSL_RECORD_RETURN_EOF              -3
337*e7be843bSPierre Pronchery
338*e7be843bSPierre Pronchery/*
339*e7be843bSPierre Pronchery * Template for creating a record. A record consists of the |type| of data it
340*e7be843bSPierre Pronchery * will contain (e.g. alert, handshake, application data, etc) along with a
341*e7be843bSPierre Pronchery * buffer of payload data in |buf| of length |buflen|.
342*e7be843bSPierre Pronchery */
343*e7be843bSPierre Proncherystruct ossl_record_template_st {
344*e7be843bSPierre Pronchery    int type;
345*e7be843bSPierre Pronchery    unsigned int version;
346*e7be843bSPierre Pronchery    const unsigned char *buf;
347*e7be843bSPierre Pronchery    size_t buflen;
348*e7be843bSPierre Pronchery};
349*e7be843bSPierre Pronchery
350*e7be843bSPierre Proncherytypedef struct ossl_record_template_st OSSL_RECORD_TEMPLATE;
351*e7be843bSPierre Pronchery
352*e7be843bSPierre Pronchery/*
353*e7be843bSPierre Pronchery * Rather than a "method" approach, we could make this fetchable - Should we?
354*e7be843bSPierre Pronchery * There could be some complexity in finding suitable record layer implementations
355*e7be843bSPierre Pronchery * e.g. we need to find one that matches the negotiated protocol, cipher,
356*e7be843bSPierre Pronchery * extensions, etc. The selection_cb approach given above doesn't work so well
357*e7be843bSPierre Pronchery * if unknown third party providers with OSSL_RECORD_METHOD implementations are
358*e7be843bSPierre Pronchery * loaded.
359*e7be843bSPierre Pronchery */
360*e7be843bSPierre Pronchery
361*e7be843bSPierre Pronchery/*
362*e7be843bSPierre Pronchery * If this becomes public API then we will need functions to create and
363*e7be843bSPierre Pronchery * free an OSSL_RECORD_METHOD, as well as functions to get/set the various
364*e7be843bSPierre Pronchery * function pointers....unless we make it fetchable.
365*e7be843bSPierre Pronchery */
366*e7be843bSPierre Proncherystruct ossl_record_method_st {
367*e7be843bSPierre Pronchery    /*
368*e7be843bSPierre Pronchery     * Create a new OSSL_RECORD_LAYER object for handling the protocol version
369*e7be843bSPierre Pronchery     * set by |vers|. |role| is 0 for client and 1 for server. |direction|
370*e7be843bSPierre Pronchery     * indicates either read or write. |level| is the protection level as
371*e7be843bSPierre Pronchery     * described above. |settings| are mandatory settings that will cause the
372*e7be843bSPierre Pronchery     * new() call to fail if they are not understood (for example to require
373*e7be843bSPierre Pronchery     * Encrypt-Then-Mac support). |options| are optional settings that will not
374*e7be843bSPierre Pronchery     * cause the new() call to fail if they are not understood (for example
375*e7be843bSPierre Pronchery     * whether to use "read ahead" or not).
376*e7be843bSPierre Pronchery     *
377*e7be843bSPierre Pronchery     * The BIO in |transport| is the BIO for the underlying transport layer.
378*e7be843bSPierre Pronchery     * Where the direction is "read", then this BIO will only ever be used for
379*e7be843bSPierre Pronchery     * reading data. Where the direction is "write", then this BIO will only
380*e7be843bSPierre Pronchery     * every be used for writing data.
381*e7be843bSPierre Pronchery     *
382*e7be843bSPierre Pronchery     * An SSL object will always have at least 2 OSSL_RECORD_LAYER objects in
383*e7be843bSPierre Pronchery     * force at any one time (one for reading and one for writing). In some
384*e7be843bSPierre Pronchery     * protocols more than 2 might be used (e.g. in DTLS for retransmitting
385*e7be843bSPierre Pronchery     * messages from an earlier epoch).
386*e7be843bSPierre Pronchery     *
387*e7be843bSPierre Pronchery     * The created OSSL_RECORD_LAYER object is stored in *ret on success (or
388*e7be843bSPierre Pronchery     * NULL otherwise). The return value will be one of
389*e7be843bSPierre Pronchery     * OSSL_RECORD_RETURN_SUCCESS, OSSL_RECORD_RETURN_FATAL or
390*e7be843bSPierre Pronchery     * OSSL_RECORD_RETURN_NON_FATAL. A non-fatal return means that creation of
391*e7be843bSPierre Pronchery     * the record layer has failed because it is unsuitable, but an alternative
392*e7be843bSPierre Pronchery     * record layer can be tried instead.
393*e7be843bSPierre Pronchery     */
394*e7be843bSPierre Pronchery
395*e7be843bSPierre Pronchery    /*
396*e7be843bSPierre Pronchery     * If we eventually make this fetchable then we will need to use something
397*e7be843bSPierre Pronchery     * other than EVP_CIPHER. Also mactype would not be a NID, but a string. For
398*e7be843bSPierre Pronchery     * now though, this works.
399*e7be843bSPierre Pronchery     */
400*e7be843bSPierre Pronchery    int (*new_record_layer)(OSSL_LIB_CTX *libctx,
401*e7be843bSPierre Pronchery                            const char *propq, int vers,
402*e7be843bSPierre Pronchery                            int role, int direction,
403*e7be843bSPierre Pronchery                            int level,
404*e7be843bSPierre Pronchery                            uint16_t epoch,
405*e7be843bSPierre Pronchery                            unsigned char *key,
406*e7be843bSPierre Pronchery                            size_t keylen,
407*e7be843bSPierre Pronchery                            unsigned char *iv,
408*e7be843bSPierre Pronchery                            size_t ivlen,
409*e7be843bSPierre Pronchery                            unsigned char *mackey,
410*e7be843bSPierre Pronchery                            size_t mackeylen,
411*e7be843bSPierre Pronchery                            const EVP_CIPHER *ciph,
412*e7be843bSPierre Pronchery                            size_t taglen,
413*e7be843bSPierre Pronchery                            int mactype,
414*e7be843bSPierre Pronchery                            const EVP_MD *md,
415*e7be843bSPierre Pronchery                            COMP_METHOD *comp,
416*e7be843bSPierre Pronchery                            BIO *prev,
417*e7be843bSPierre Pronchery                            BIO *transport,
418*e7be843bSPierre Pronchery                            BIO *next,
419*e7be843bSPierre Pronchery                            BIO_ADDR *local,
420*e7be843bSPierre Pronchery                            BIO_ADDR *peer,
421*e7be843bSPierre Pronchery                            const OSSL_PARAM *settings,
422*e7be843bSPierre Pronchery                            const OSSL_PARAM *options,
423*e7be843bSPierre Pronchery                            const OSSL_DISPATCH *fns,
424*e7be843bSPierre Pronchery                            void *cbarg,
425*e7be843bSPierre Pronchery                            OSSL_RECORD_LAYER **ret);
426*e7be843bSPierre Pronchery    int (*free)(OSSL_RECORD_LAYER *rl);
427*e7be843bSPierre Pronchery
428*e7be843bSPierre Pronchery    int (*reset)(OSSL_RECORD_LAYER *rl); /* Is this needed? */
429*e7be843bSPierre Pronchery
430*e7be843bSPierre Pronchery    /* Returns 1 if we have unprocessed data buffered or 0 otherwise */
431*e7be843bSPierre Pronchery    int (*unprocessed_read_pending)(OSSL_RECORD_LAYER *rl);
432*e7be843bSPierre Pronchery
433*e7be843bSPierre Pronchery    /*
434*e7be843bSPierre Pronchery     * Returns 1 if we have processed data buffered that can be read or 0 otherwise
435*e7be843bSPierre Pronchery     * - not necessarily app data
436*e7be843bSPierre Pronchery     */
437*e7be843bSPierre Pronchery    int (*processed_read_pending)(OSSL_RECORD_LAYER *rl);
438*e7be843bSPierre Pronchery
439*e7be843bSPierre Pronchery    /*
440*e7be843bSPierre Pronchery     * The amount of processed app data that is internally buffered and
441*e7be843bSPierre Pronchery     * available to read
442*e7be843bSPierre Pronchery     */
443*e7be843bSPierre Pronchery    size_t (*app_data_pending)(OSSL_RECORD_LAYER *rl);
444*e7be843bSPierre Pronchery
445*e7be843bSPierre Pronchery    /*
446*e7be843bSPierre Pronchery     * Find out the maximum number of records that the record layer is prepared
447*e7be843bSPierre Pronchery     * to process in a single call to write_records. It is the caller's
448*e7be843bSPierre Pronchery     * responsibility to ensure that no call to write_records exceeds this
449*e7be843bSPierre Pronchery     * number of records. |type| is the type of the records that the caller
450*e7be843bSPierre Pronchery     * wants to write, and |len| is the total amount of data that it wants
451*e7be843bSPierre Pronchery     * to send. |maxfrag| is the maximum allowed fragment size based on user
452*e7be843bSPierre Pronchery     * configuration, or TLS parameter negotiation. |*preffrag| contains on
453*e7be843bSPierre Pronchery     * entry the default fragment size that will actually be used based on user
454*e7be843bSPierre Pronchery     * configuration. This will always be less than or equal to |maxfrag|. On
455*e7be843bSPierre Pronchery     * exit the record layer may update this to an alternative fragment size to
456*e7be843bSPierre Pronchery     * be used. This must always be less than or equal to |maxfrag|.
457*e7be843bSPierre Pronchery     */
458*e7be843bSPierre Pronchery    size_t (*get_max_records)(OSSL_RECORD_LAYER *rl, uint8_t type, size_t len,
459*e7be843bSPierre Pronchery                              size_t maxfrag, size_t *preffrag);
460*e7be843bSPierre Pronchery
461*e7be843bSPierre Pronchery    /*
462*e7be843bSPierre Pronchery     * Write |numtempl| records from the array of record templates pointed to
463*e7be843bSPierre Pronchery     * by |templates|. Each record should be no longer than the value returned
464*e7be843bSPierre Pronchery     * by get_max_record_len(), and there should be no more records than the
465*e7be843bSPierre Pronchery     * value returned by get_max_records().
466*e7be843bSPierre Pronchery     * Where possible the caller will attempt to ensure that all records are the
467*e7be843bSPierre Pronchery     * same length, except the last record. This may not always be possible so
468*e7be843bSPierre Pronchery     * the record method implementation should not rely on this being the case.
469*e7be843bSPierre Pronchery     * In the event of a retry the caller should call retry_write_records()
470*e7be843bSPierre Pronchery     * to try again. No more calls to write_records() should be attempted until
471*e7be843bSPierre Pronchery     * retry_write_records() returns success.
472*e7be843bSPierre Pronchery     * Buffers allocated for the record templates can be freed immediately after
473*e7be843bSPierre Pronchery     * write_records() returns - even in the case a retry.
474*e7be843bSPierre Pronchery     * The record templates represent the plaintext payload. The encrypted
475*e7be843bSPierre Pronchery     * output is written to the |transport| BIO.
476*e7be843bSPierre Pronchery     * Returns:
477*e7be843bSPierre Pronchery     *  1 on success
478*e7be843bSPierre Pronchery     *  0 on retry
479*e7be843bSPierre Pronchery     * -1 on failure
480*e7be843bSPierre Pronchery     */
481*e7be843bSPierre Pronchery    int (*write_records)(OSSL_RECORD_LAYER *rl, OSSL_RECORD_TEMPLATE *templates,
482*e7be843bSPierre Pronchery                         size_t numtempl);
483*e7be843bSPierre Pronchery
484*e7be843bSPierre Pronchery    /*
485*e7be843bSPierre Pronchery     * Retry a previous call to write_records. The caller should continue to
486*e7be843bSPierre Pronchery     * call this until the function returns with success or failure. After
487*e7be843bSPierre Pronchery     * each retry more of the data may have been incrementally sent.
488*e7be843bSPierre Pronchery     * Returns:
489*e7be843bSPierre Pronchery     *  1 on success
490*e7be843bSPierre Pronchery     *  0 on retry
491*e7be843bSPierre Pronchery     * -1 on failure
492*e7be843bSPierre Pronchery     */
493*e7be843bSPierre Pronchery    int (*retry_write_records)(OSSL_RECORD_LAYER *rl);
494*e7be843bSPierre Pronchery
495*e7be843bSPierre Pronchery    /*
496*e7be843bSPierre Pronchery     * Read a record and return the record layer version and record type in
497*e7be843bSPierre Pronchery     * the |rversion| and |type| parameters. |*data| is set to point to a
498*e7be843bSPierre Pronchery     * record layer buffer containing the record payload data and |*datalen|
499*e7be843bSPierre Pronchery     * is filled in with the length of that data. The |epoch| and |seq_num|
500*e7be843bSPierre Pronchery     * values are only used if DTLS has been negotiated. In that case they are
501*e7be843bSPierre Pronchery     * filled in with the epoch and sequence number from the record.
502*e7be843bSPierre Pronchery     * An opaque record layer handle for the record is returned in |*rechandle|
503*e7be843bSPierre Pronchery     * which is used in a subsequent call to |release_record|. The buffer must
504*e7be843bSPierre Pronchery     * remain available until release_record is called.
505*e7be843bSPierre Pronchery     *
506*e7be843bSPierre Pronchery     * Internally the OSSL_RECORD_METHOD the implementation may read/process
507*e7be843bSPierre Pronchery     * multiple records in one go and buffer them.
508*e7be843bSPierre Pronchery     */
509*e7be843bSPierre Pronchery    int (*read_record)(OSSL_RECORD_LAYER *rl, void **rechandle, int *rversion,
510*e7be843bSPierre Pronchery                      uint8_t *type, unsigned char **data, size_t *datalen,
511*e7be843bSPierre Pronchery                      uint16_t *epoch, unsigned char *seq_num);
512*e7be843bSPierre Pronchery    /*
513*e7be843bSPierre Pronchery     * Release a buffer associated with a record previously read with
514*e7be843bSPierre Pronchery     * read_record. Records are guaranteed to be released in the order that they
515*e7be843bSPierre Pronchery     * are read.
516*e7be843bSPierre Pronchery     */
517*e7be843bSPierre Pronchery    int (*release_record)(OSSL_RECORD_LAYER *rl, void *rechandle);
518*e7be843bSPierre Pronchery
519*e7be843bSPierre Pronchery    /*
520*e7be843bSPierre Pronchery     * In the event that a fatal error is returned from the functions above then
521*e7be843bSPierre Pronchery     * get_alert_code() can be called to obtain a more details identifier for
522*e7be843bSPierre Pronchery     * the error. In (D)TLS this is the alert description code.
523*e7be843bSPierre Pronchery     */
524*e7be843bSPierre Pronchery    int (*get_alert_code)(OSSL_RECORD_LAYER *rl);
525*e7be843bSPierre Pronchery
526*e7be843bSPierre Pronchery    /*
527*e7be843bSPierre Pronchery     * Update the transport BIO from the one originally set in the
528*e7be843bSPierre Pronchery     * new_record_layer call
529*e7be843bSPierre Pronchery     */
530*e7be843bSPierre Pronchery    int (*set1_bio)(OSSL_RECORD_LAYER *rl, BIO *bio);
531*e7be843bSPierre Pronchery
532*e7be843bSPierre Pronchery    /* Called when protocol negotiation selects a protocol version to use */
533*e7be843bSPierre Pronchery    int (*set_protocol_version)(OSSL_RECORD_LAYER *rl, int version);
534*e7be843bSPierre Pronchery
535*e7be843bSPierre Pronchery    /*
536*e7be843bSPierre Pronchery     * Whether we are allowed to receive unencrypted alerts, even if we might
537*e7be843bSPierre Pronchery     * otherwise expect encrypted records. Ignored by protocol versions where
538*e7be843bSPierre Pronchery     * this isn't relevant
539*e7be843bSPierre Pronchery     */
540*e7be843bSPierre Pronchery    void (*set_plain_alerts)(OSSL_RECORD_LAYER *rl, int allow);
541*e7be843bSPierre Pronchery
542*e7be843bSPierre Pronchery    /*
543*e7be843bSPierre Pronchery     * Called immediately after creation of the record layer if we are in a
544*e7be843bSPierre Pronchery     * first handshake. Also called at the end of the first handshake
545*e7be843bSPierre Pronchery     */
546*e7be843bSPierre Pronchery    void (*set_first_handshake)(OSSL_RECORD_LAYER *rl, int first);
547*e7be843bSPierre Pronchery
548*e7be843bSPierre Pronchery    /*
549*e7be843bSPierre Pronchery     * Set the maximum number of pipelines that the record layer should process.
550*e7be843bSPierre Pronchery     * The default is 1.
551*e7be843bSPierre Pronchery     */
552*e7be843bSPierre Pronchery    void (*set_max_pipelines)(OSSL_RECORD_LAYER *rl, size_t max_pipelines);
553*e7be843bSPierre Pronchery
554*e7be843bSPierre Pronchery    /*
555*e7be843bSPierre Pronchery     * Called to tell the record layer whether we are currently "in init" or
556*e7be843bSPierre Pronchery     * not. Default at creation of the record layer is "yes".
557*e7be843bSPierre Pronchery     */
558*e7be843bSPierre Pronchery    void (*set_in_init)(OSSL_RECORD_LAYER *rl, int in_init);
559*e7be843bSPierre Pronchery
560*e7be843bSPierre Pronchery    /*
561*e7be843bSPierre Pronchery     * Get a short or long human readable description of the record layer state
562*e7be843bSPierre Pronchery     */
563*e7be843bSPierre Pronchery    void (*get_state)(OSSL_RECORD_LAYER *rl, const char **shortstr,
564*e7be843bSPierre Pronchery                      const char **longstr);
565*e7be843bSPierre Pronchery
566*e7be843bSPierre Pronchery    /*
567*e7be843bSPierre Pronchery     * Set new options or modify ones that were originally specified in the
568*e7be843bSPierre Pronchery     * new_record_layer call.
569*e7be843bSPierre Pronchery     */
570*e7be843bSPierre Pronchery    int (*set_options)(OSSL_RECORD_LAYER *rl, const OSSL_PARAM *options);
571*e7be843bSPierre Pronchery
572*e7be843bSPierre Pronchery    const COMP_METHOD *(*get_compression)(OSSL_RECORD_LAYER *rl);
573*e7be843bSPierre Pronchery
574*e7be843bSPierre Pronchery    /*
575*e7be843bSPierre Pronchery     * Set the maximum fragment length to be used for the record layer. This
576*e7be843bSPierre Pronchery     * will override any previous value supplied for the "max_frag_len"
577*e7be843bSPierre Pronchery     * setting during construction of the record layer.
578*e7be843bSPierre Pronchery     */
579*e7be843bSPierre Pronchery    void (*set_max_frag_len)(OSSL_RECORD_LAYER *rl, size_t max_frag_len);
580*e7be843bSPierre Pronchery
581*e7be843bSPierre Pronchery    /*
582*e7be843bSPierre Pronchery     * The maximum expansion in bytes that the record layer might add while
583*e7be843bSPierre Pronchery     * writing a record
584*e7be843bSPierre Pronchery     */
585*e7be843bSPierre Pronchery    size_t (*get_max_record_overhead)(OSSL_RECORD_LAYER *rl);
586*e7be843bSPierre Pronchery
587*e7be843bSPierre Pronchery    /*
588*e7be843bSPierre Pronchery     * Increment the record sequence number
589*e7be843bSPierre Pronchery     */
590*e7be843bSPierre Pronchery    int (*increment_sequence_ctr)(OSSL_RECORD_LAYER *rl);
591*e7be843bSPierre Pronchery
592*e7be843bSPierre Pronchery    /*
593*e7be843bSPierre Pronchery     * Allocate read or write buffers. Does nothing if already allocated.
594*e7be843bSPierre Pronchery     * Assumes default buffer length and 1 pipeline.
595*e7be843bSPierre Pronchery     */
596*e7be843bSPierre Pronchery    int (*alloc_buffers)(OSSL_RECORD_LAYER *rl);
597*e7be843bSPierre Pronchery
598*e7be843bSPierre Pronchery    /*
599*e7be843bSPierre Pronchery     * Free read or write buffers. Fails if there is pending read or write
600*e7be843bSPierre Pronchery     * data. Buffers are automatically reallocated on next read/write.
601*e7be843bSPierre Pronchery     */
602*e7be843bSPierre Pronchery    int (*free_buffers)(OSSL_RECORD_LAYER *rl);
603*e7be843bSPierre Pronchery};
604*e7be843bSPierre Pronchery````
605