Skip to content

Commit 8f7a302

Browse files
committed
Merge branch 'main' into sidetrail-fix
2 parents 582b942 + 4220a4d commit 8f7a302

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2944
-149
lines changed

api/s2n.h

+80
Original file line numberDiff line numberDiff line change
@@ -1812,6 +1812,86 @@ S2N_API extern int s2n_connection_prefer_throughput(struct s2n_connection *conn)
18121812
*/
18131813
S2N_API extern int s2n_connection_prefer_low_latency(struct s2n_connection *conn);
18141814

1815+
/**
1816+
* Configure the connection to reduce potentially expensive calls to recv.
1817+
*
1818+
* If this setting is disabled, s2n-tls will call read twice for every TLS record,
1819+
* which can be expensive but ensures that s2n-tls will always attempt to read the
1820+
* exact number of bytes it requires. If this setting is enabled, s2n-tls will
1821+
* instead reduce the number of calls to read by attempting to read as much data
1822+
* as possible in each read call, storing the extra in the existing IO buffers.
1823+
* This may cause it to request more data than will ever actually be available.
1824+
*
1825+
* There is no additional memory cost of enabling this setting. It reuses the
1826+
* existing IO buffers.
1827+
*
1828+
* This setting is disabled by default. Depending on how your application detects
1829+
* data available for reading, buffering reads may break your event loop.
1830+
* In particular, note that:
1831+
*
1832+
* 1. File descriptor reads or calls to your custom s2n_recv_cb may request more
1833+
* data than is available. Reads must return partial data when available rather
1834+
* than blocking until all requested data is available.
1835+
*
1836+
* 2. s2n_negotiate may read and buffer application data records.
1837+
* You must call s2n_recv at least once after negotiation to ensure that you
1838+
* handle any buffered data.
1839+
*
1840+
* 3. s2n_recv may read and buffer more records than it parses and decrypts.
1841+
* You must call s2n_recv until it reports S2N_ERR_T_BLOCKED, rather than just
1842+
* until it reports S2N_SUCCESS.
1843+
*
1844+
* 4. s2n_peek reports available decrypted data. It does not report any data
1845+
* buffered by this feature. However, s2n_peek_buffered does report data
1846+
* buffered by this feature.
1847+
*
1848+
* 5. s2n_connection_release_buffers will not release the input buffer if it
1849+
* contains buffered data.
1850+
*
1851+
* For example: if your event loop uses `poll`, you will receive a POLLIN event
1852+
* for your read file descriptor when new data is available. When you call s2n_recv
1853+
* to read that data, s2n-tls reads one or more TLS records from the file descriptor.
1854+
* If you stop calling s2n_recv before it reports S2N_ERR_T_BLOCKED, some of those
1855+
* records may remain in s2n-tls's read buffer. If you read part of a record,
1856+
* s2n_peek will report the remainder of that record as available. But if you don't
1857+
* read any of a record, it remains encrypted and is not reported by s2n_peek, but
1858+
* is still reported by s2n_peek_buffered. And because the data is buffered in s2n-tls
1859+
* instead of in the file descriptor, another call to `poll` will NOT report any
1860+
* more data available. Your application may hang waiting for more data.
1861+
*
1862+
* @warning This feature cannot be enabled for a connection that will enable kTLS for receiving.
1863+
*
1864+
* @warning This feature may work with blocking IO, if used carefully. Your blocking
1865+
* IO must support partial reads (so MSG_WAITALL cannot be used). You will either
1866+
* need to know exactly how much data your peer is sending, or will need to use
1867+
* `s2n_peek` and `s2n_peek_buffered` rather than relying on S2N_ERR_T_BLOCKED
1868+
* as noted in #3 above.
1869+
*
1870+
* @param conn The connection object being updated
1871+
* @param enabled Set to `true` to enable, `false` to disable.
1872+
* @returns S2N_SUCCESS on success. S2N_FAILURE on failure
1873+
*/
1874+
S2N_API extern int s2n_connection_set_recv_buffering(struct s2n_connection *conn, bool enabled);
1875+
1876+
/**
1877+
* Reports how many bytes of unprocessed TLS records are buffered due to the optimization
1878+
* enabled by `s2n_connection_set_recv_buffering`.
1879+
*
1880+
* `s2n_peek_buffered` is not a replacement for `s2n_peek`.
1881+
* While `s2n_peek` reports application data that is ready for the application
1882+
* to read with no additional processing, `s2n_peek_buffered` reports raw TLS
1883+
* records that still need to be parsed and likely decrypted. Those records may
1884+
* contain application data, but they may also only contain TLS control messages.
1885+
*
1886+
* If an application needs to determine whether there is any data left to handle
1887+
* (for example, before calling `poll` to wait on the read file descriptor) then
1888+
* that application must check both `s2n_peek` and `s2n_peek_buffered`.
1889+
*
1890+
* @param conn A pointer to the s2n_connection object
1891+
* @returns The number of buffered encrypted bytes
1892+
*/
1893+
S2N_API extern uint32_t s2n_peek_buffered(struct s2n_connection *conn);
1894+
18151895
/**
18161896
* Configure the connection to free IO buffers when they are not currently in use.
18171897
*

api/unstable/ktls.h

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
* The TLS kernel module currently doesn't support renegotiation.
3939
* - By default, you must negotiate TLS1.2. See s2n_config_ktls_enable_tls13
4040
* for the requirements to also support TLS1.3.
41+
* - You must not use s2n_connection_set_recv_buffering
4142
*/
4243

4344
/**

api/unstable/renegotiate.h

+2
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ S2N_API int s2n_config_set_renegotiate_request_cb(struct s2n_config *config, s2n
110110
*
111111
* @note This method MUST be called before s2n_renegotiate.
112112
* @note Calling this method on a server connection will fail. s2n-tls servers do not support renegotiation.
113+
* @note This method will fail if the connection has indicated that it will be serialized with
114+
* `s2n_config_set_serialized_connection_version()`.
113115
*
114116
* @param conn A pointer to the connection object.
115117
* @returns S2N_SUCCESS on success, S2N_FAILURE on error.

bindings/rust/s2n-tls-sys/build.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn env<N: AsRef<str>>(name: N) -> String {
1919

2020
fn option_env<N: AsRef<str>>(name: N) -> Option<String> {
2121
let name = name.as_ref();
22-
eprintln!("cargo:rerun-if-env-changed={}", name);
22+
println!("cargo:rerun-if-env-changed={}", name);
2323
std::env::var(name).ok()
2424
}
2525

@@ -194,7 +194,7 @@ impl Default for Libcrypto {
194194
if let Some(version) = version.strip_suffix("_INCLUDE") {
195195
let version = version.to_string();
196196

197-
eprintln!("cargo:rerun-if-env-changed={}", name);
197+
println!("cargo:rerun-if-env-changed={}", name);
198198

199199
let include = value;
200200
let root = env(format!("DEP_AWS_LC_{version}_ROOT"));

bindings/rust/s2n-tls-sys/templates/Cargo.template

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "s2n-tls-sys"
33
description = "A C99 implementation of the TLS/SSL protocols"
4-
version = "0.2.0"
4+
version = "0.2.2"
55
authors = ["AWS s2n"]
66
edition = "2021"
77
rust-version = "1.63.0"

bindings/rust/s2n-tls-tokio/Cargo.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "s2n-tls-tokio"
33
description = "An implementation of TLS streams for Tokio built on top of s2n-tls"
4-
version = "0.2.0"
4+
version = "0.2.2"
55
authors = ["AWS s2n"]
66
edition = "2021"
77
rust-version = "1.63.0"
@@ -15,7 +15,7 @@ default = []
1515
errno = { version = "0.3" }
1616
libc = { version = "0.2" }
1717
pin-project-lite = { version = "0.2" }
18-
s2n-tls = { version = "=0.2.0", path = "../s2n-tls" }
18+
s2n-tls = { version = "=0.2.2", path = "../s2n-tls" }
1919
tokio = { version = "1", features = ["net", "time"] }
2020

2121
[dev-dependencies]

bindings/rust/s2n-tls/Cargo.toml

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "s2n-tls"
33
description = "A C99 implementation of the TLS/SSL protocols"
4-
version = "0.2.0"
4+
version = "0.2.2"
55
authors = ["AWS s2n"]
66
edition = "2021"
77
rust-version = "1.63.0"
@@ -11,6 +11,7 @@ license = "Apache-2.0"
1111
[features]
1212
default = []
1313
unstable-fingerprint = ["s2n-tls-sys/unstable-fingerprint"]
14+
unstable-ktls = ["s2n-tls-sys/unstable-ktls"]
1415
quic = ["s2n-tls-sys/quic"]
1516
pq = ["s2n-tls-sys/pq"]
1617
testing = ["bytes"]
@@ -19,7 +20,7 @@ testing = ["bytes"]
1920
bytes = { version = "1", optional = true }
2021
errno = { version = "0.3" }
2122
libc = "0.2"
22-
s2n-tls-sys = { version = "=0.2.0", path = "../s2n-tls-sys", features = ["internal"] }
23+
s2n-tls-sys = { version = "=0.2.2", path = "../s2n-tls-sys", features = ["internal"] }
2324
pin-project-lite = "0.2"
2425
hex = "0.4"
2526

bindings/rust/s2n-tls/src/connection.rs

+49
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,15 @@ macro_rules! static_const_str {
3636
};
3737
}
3838

39+
#[non_exhaustive]
40+
#[derive(Debug, PartialEq)]
41+
/// s2n-tls only tracks up to u8::MAX (255) key updates. If any of the fields show
42+
/// 255 updates, then more than 255 updates may have occurred.
43+
pub struct KeyUpdateCount {
44+
pub send_key_updates: u8,
45+
pub recv_key_updates: u8,
46+
}
47+
3948
pub struct Connection {
4049
connection: NonNull<s2n_connection>,
4150
}
@@ -267,6 +276,46 @@ impl Connection {
267276
Ok(self)
268277
}
269278

279+
/// Signals the connection to do a key_update at the next possible opportunity.
280+
/// Note that the resulting key update message will not be sent until `send` is
281+
/// called on the connection.
282+
///
283+
/// `peer_request` indicates if a key update should also be requested
284+
/// of the peer. When set to `KeyUpdateNotRequested`, then only the sending
285+
/// key of the connection will be updated. If set to `KeyUpdateRequested`, then
286+
/// the sending key of conn will be updated AND the peer will be requested to
287+
/// update their sending key. Note that s2n-tls currently only supports
288+
/// `peer_request` being set to `KeyUpdateNotRequested` and will return an error
289+
/// if any other value is used.
290+
pub fn request_key_update(&mut self, peer_request: PeerKeyUpdate) -> Result<&mut Self, Error> {
291+
unsafe {
292+
s2n_connection_request_key_update(self.connection.as_ptr(), peer_request.into())
293+
.into_result()
294+
}?;
295+
Ok(self)
296+
}
297+
298+
/// Reports the number of times sending and receiving keys have been updated.
299+
///
300+
/// This only applies to TLS1.3. Earlier versions do not support key updates.
301+
#[cfg(feature = "unstable-ktls")]
302+
pub fn key_update_counts(&self) -> Result<KeyUpdateCount, Error> {
303+
let mut send_key_updates = 0;
304+
let mut recv_key_updates = 0;
305+
unsafe {
306+
s2n_connection_get_key_update_counts(
307+
self.connection.as_ptr(),
308+
&mut send_key_updates,
309+
&mut recv_key_updates,
310+
)
311+
.into_result()?;
312+
}
313+
Ok(KeyUpdateCount {
314+
send_key_updates,
315+
recv_key_updates,
316+
})
317+
}
318+
270319
/// sets the application protocol preferences on an s2n_connection object.
271320
///
272321
/// protocols is a list in order of preference, with most preferred protocol first, and of

bindings/rust/s2n-tls/src/enums.rs

+16
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,19 @@ impl TryFrom<s2n_tls_hash_algorithm::Type> for HashAlgorithm {
177177
Ok(version)
178178
}
179179
}
180+
181+
#[non_exhaustive]
182+
#[derive(Debug, PartialEq, Copy, Clone)]
183+
pub enum PeerKeyUpdate {
184+
KeyUpdateNotRequested,
185+
KeyUpdatedRequested,
186+
}
187+
188+
impl From<PeerKeyUpdate> for s2n_peer_key_update::Type {
189+
fn from(input: PeerKeyUpdate) -> s2n_peer_key_update::Type {
190+
match input {
191+
PeerKeyUpdate::KeyUpdateNotRequested => s2n_peer_key_update::KEY_UPDATE_NOT_REQUESTED,
192+
PeerKeyUpdate::KeyUpdatedRequested => s2n_peer_key_update::KEY_UPDATE_REQUESTED,
193+
}
194+
}
195+
}

bindings/rust/s2n-tls/src/testing/s2n_tls.rs

+36
Original file line numberDiff line numberDiff line change
@@ -925,4 +925,40 @@ mod tests {
925925

926926
Ok(())
927927
}
928+
929+
#[cfg(feature = "unstable-ktls")]
930+
#[test]
931+
fn key_updates() -> Result<(), Error> {
932+
use crate::{connection::KeyUpdateCount, enums::PeerKeyUpdate};
933+
934+
let empty_key_updates = KeyUpdateCount {
935+
recv_key_updates: 0,
936+
send_key_updates: 0,
937+
};
938+
939+
let pair = tls_pair(build_config(&security::DEFAULT_TLS13)?);
940+
let mut pair = poll_tls_pair(pair);
941+
942+
// there haven't been any key updates at the start of the connection
943+
let client_updates = pair.client.0.connection.as_ref().key_update_counts()?;
944+
assert_eq!(client_updates, empty_key_updates);
945+
let server_updates = pair.server.0.connection.as_ref().key_update_counts()?;
946+
assert_eq!(server_updates, empty_key_updates);
947+
948+
pair.server
949+
.0
950+
.connection
951+
.as_mut()
952+
.request_key_update(PeerKeyUpdate::KeyUpdateNotRequested)?;
953+
assert!(pair.poll_send(Mode::Server, &[0]).is_ready());
954+
955+
// the server send key has been updated
956+
let client_updates = pair.client.0.connection.as_ref().key_update_counts()?;
957+
assert_eq!(client_updates, empty_key_updates);
958+
let server_updates = pair.server.0.connection.as_ref().key_update_counts()?;
959+
assert_eq!(server_updates.recv_key_updates, 0);
960+
assert_eq!(server_updates.send_key_updates, 1);
961+
962+
Ok(())
963+
}
928964
}

docs/usage-guide/topics/ch06-security-policies.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ The following chart maps the security policy version to protocol version and cip
1616
| version | TLS1.0 | TLS1.1 | TLS1.2 | TLS1.3 | AES-CBC | AES-GCM | CHACHAPOLY | 3DES | RC4 | DHE | ECDHE | RSA kx |
1717
|---------------|--------|--------|--------|--------|---------|---------|------------|------|-----|-----|-------|--------|
1818
| 20230317 | | | X | X | X | X | | | | | X | |
19+
| 20240331 | | | X | | X | X | | | | | X | |
1920
| default | X | X | X | | X | X | X | | | | X | X |
2021
| default_tls13 | X | X | X | X | X | X | X | | | | X | X |
2122
| default_fips | | | X | | X | X | | | | X | X | |
@@ -42,7 +43,7 @@ The following chart maps the security policy version to protocol version and cip
4243
The "default", "default_tls13", and "default_fips" versions are special in that they will be updated with future s2n-tls changes and ciphersuites and protocol versions may be added and removed, or their internal order of preference might change. Numbered versions are fixed and will never change.
4344
In general, customers prefer to use numbered versions for production use cases to prevent impact from library updates.
4445

45-
"20230317" is a FIPS compliant policy. It offers more limited but more secure options than "default". It only supports TLS1.2 and TLS1.3. Consider this policy if you plan to enable FIPS mode or don't need or want to support less secure legacy options like TLS1.1 or SHA1.
46+
"20230317" offers more limited but more secure options than the default policies. Consider it if you don't need or want to support less secure legacy options like TLS1.1 or SHA1. It is also FIPS compliant and supports TLS1.3. If you need a version of this policy that doesn't support TLS1.3, choose "20240331" instead.
4647

4748
"20160411" follows the same general preference order as "default". The main difference is it has a CBC cipher suite at the top. This is to accommodate certain Java clients that have poor GCM implementations. Users of s2n-tls who have found GCM to be hurting performance for their clients should consider this version.
4849

error/s2n_errno.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,10 @@ static const char *no_such_error = "Internal s2n error";
307307
ERR_ENTRY(S2N_ERR_KTLS_RENEG, "kTLS does not support secure renegotiation") \
308308
ERR_ENTRY(S2N_ERR_KTLS_KEYUPDATE, "Received KeyUpdate from peer, but kernel does not support updating tls keys") \
309309
ERR_ENTRY(S2N_ERR_KTLS_KEY_LIMIT, "Reached key encryption limit, but kernel does not support updating tls keys") \
310-
ERR_ENTRY(S2N_ERR_UNEXPECTED_CERT_REQUEST, "Client does not support mutual authentication") \
310+
ERR_ENTRY(S2N_ERR_UNEXPECTED_CERT_REQUEST, "Client forbids mutual authentication, but server requested a cert") \
311+
ERR_ENTRY(S2N_ERR_MISSING_CERT_REQUEST, "Client requires mutual authentication, but server did not request a cert") \
312+
ERR_ENTRY(S2N_ERR_MISSING_CLIENT_CERT, "Server requires client certificate") \
313+
ERR_ENTRY(S2N_INVALID_SERIALIZED_CONNECTION, "Serialized connection is invalid"); \
311314
/* clang-format on */
312315

313316
#define ERR_STR_CASE(ERR, str) \

error/s2n_errno.h

+3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ typedef enum {
7272
S2N_ERR_DECRYPT,
7373
S2N_ERR_BAD_MESSAGE,
7474
S2N_ERR_UNEXPECTED_CERT_REQUEST,
75+
S2N_ERR_MISSING_CERT_REQUEST,
76+
S2N_ERR_MISSING_CLIENT_CERT,
7577
S2N_ERR_KEY_INIT,
7678
S2N_ERR_KEY_DESTROY,
7779
S2N_ERR_DH_SERIALIZING,
@@ -325,6 +327,7 @@ typedef enum {
325327
S2N_ERR_ATOMIC,
326328
S2N_ERR_KTLS_KEY_LIMIT,
327329
S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT,
330+
S2N_INVALID_SERIALIZED_CONNECTION,
328331
S2N_ERR_T_USAGE_END,
329332
} s2n_error;
330333

stuffer/s2n_stuffer.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ int s2n_stuffer_wipe_n(struct s2n_stuffer *stuffer, const uint32_t size)
215215

216216
bool s2n_stuffer_is_consumed(struct s2n_stuffer *stuffer)
217217
{
218-
return stuffer && (stuffer->read_cursor == stuffer->write_cursor);
218+
return stuffer && (stuffer->read_cursor == stuffer->write_cursor) && !stuffer->tainted;
219219
}
220220

221221
int s2n_stuffer_wipe(struct s2n_stuffer *stuffer)

tests/cbmc/proofs/s2n_stuffer_is_consumed/s2n_stuffer_is_consumed_harness.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,13 @@ void s2n_stuffer_is_consumed_harness()
3333
save_byte_from_blob(&stuffer->blob, &old_byte_from_stuffer);
3434

3535
/* Operation under verification. */
36-
if (s2n_stuffer_is_consumed(stuffer)) {
37-
assert(stuffer->read_cursor == old_stuffer.write_cursor);
36+
bool result = s2n_stuffer_is_consumed(stuffer);
37+
if (old_stuffer.read_cursor != old_stuffer.write_cursor) {
38+
assert(result == false);
39+
} else if (old_stuffer.tainted) {
40+
assert(result == false);
3841
} else {
39-
assert(stuffer->read_cursor != old_stuffer.write_cursor);
42+
assert(result == true);
4043
}
4144

4245
/* Post-conditions. */

0 commit comments

Comments
 (0)