Skip to content

Commit 44989ab

Browse files
xnorpxalgesten
andauthored
Stop advertising unsupported RSA signatures in DTLS 1.2
* Stop advertising unsupported RSA signatures * Fix record parsing Clippy warnings * Size signature algorithm vectors to supported set --------- Co-authored-by: Martin Algesten <[email protected]>
1 parent a6cecf0 commit 44989ab

7 files changed

Lines changed: 118 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
* Stop advertising unsupported RSA signatures in DTLS 1.2 CertificateRequest
4+
35
# 0.7.1
46

57
* Add `Dtls::is_closing()` and `Dtls::is_closed()` shutdown predicates #155

src/dtls12/incoming.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,13 @@ impl Records {
9090

9191
// This is the ONLY copy: packet -> record buffer
9292
let record_slice = &packet[..record_end];
93-
match Record::parse(record_slice, decrypt, cs) {
94-
Ok(record) => {
95-
if let Some(record) = record {
96-
if parsed_records.try_push(record).is_err() {
97-
return Err(InternalError::too_many_records());
98-
}
99-
} else {
100-
trace!("Discarding replayed rec");
101-
}
93+
let record = Record::parse(record_slice, decrypt, cs)?;
94+
if let Some(record) = record {
95+
if parsed_records.try_push(record).is_err() {
96+
return Err(InternalError::too_many_records());
10297
}
103-
Err(e) => return Err(e),
98+
} else {
99+
trace!("Discarding replayed rec");
104100
}
105101

106102
packet = &packet[record_end..];

src/dtls12/message/certificate_request.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ mod test {
118118
use super::*;
119119
use crate::buffer::Buf;
120120

121-
// Test message with supported values:
121+
// Test message with recognized values:
122122
// - Certificate type: 0x40 (ECDSA_SIGN)
123123
// - Signature algorithms: SHA256/ECDSA (0x04, 0x03), SHA256/RSA (0x04, 0x01)
124124
const MESSAGE: &[u8] = &[
@@ -135,15 +135,34 @@ mod test {
135135
];
136136

137137
#[test]
138-
fn roundtrip() {
138+
fn filters_unsupported_rsa_signature_algorithm() {
139139
// Parse the message with base_offset 0
140140
let (rest, parsed) = CertificateRequest::parse(MESSAGE, 0).unwrap();
141141
assert!(rest.is_empty());
142+
assert_eq!(parsed.supported_signature_algorithms.len(), 1);
143+
assert_eq!(
144+
parsed.supported_signature_algorithms[0],
145+
SignatureAndHashAlgorithm::new(
146+
super::super::HashAlgorithm::SHA256,
147+
super::super::SignatureAlgorithm::ECDSA,
148+
)
149+
);
142150

143-
// Serialize and compare to MESSAGE
151+
// Serialization must not re-advertise the filtered RSA algorithm.
144152
let mut serialized = Buf::new();
145153
parsed.serialize(MESSAGE, &mut serialized);
146-
assert_eq!(&*serialized, MESSAGE);
154+
let expected = [
155+
0x01, // Certificate types length (1 byte)
156+
0x40, // Certificate type: ECDSA_SIGN
157+
0x00, 0x02, // Signature algorithms length (2 bytes = 1 algorithm)
158+
0x04, 0x03, // SHA256/ECDSA
159+
0x00, 0x0C, // Certificate authorities length
160+
0x00, 0x04, // Distinguished name 1 length
161+
0x01, 0x02, 0x03, 0x04, // Distinguished name 1 data
162+
0x00, 0x04, // Distinguished name 2 length
163+
0x05, 0x06, 0x07, 0x08, // Distinguished name 2 data
164+
];
165+
assert_eq!(&*serialized, expected);
147166
}
148167

149168
#[test]

src/dtls12/message/extensions/signature_algorithms.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,33 @@ mod tests {
101101

102102
let (_, parsed) = SignatureAlgorithmsExtension::parse(&serialized).unwrap();
103103

104-
assert_eq!(parsed.supported_signature_algorithms, algorithms);
104+
assert_eq!(parsed.supported_signature_algorithms.len(), 1);
105+
assert_eq!(
106+
parsed.supported_signature_algorithms[0],
107+
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA256, SignatureAlgorithm::ECDSA,)
108+
);
109+
}
110+
111+
#[test]
112+
fn default_does_not_advertise_rsa() {
113+
let extension = SignatureAlgorithmsExtension::default();
114+
115+
assert!(
116+
extension
117+
.supported_signature_algorithms
118+
.iter()
119+
.all(|algorithm| algorithm.signature != SignatureAlgorithm::RSA)
120+
);
121+
}
122+
123+
#[test]
124+
fn capacity_matches_supported() {
125+
let extension = SignatureAlgorithmsExtension::default();
126+
127+
assert_eq!(
128+
extension.supported_signature_algorithms.capacity(),
129+
SignatureAndHashAlgorithm::supported().len()
130+
);
105131
}
106132

107133
#[test]

src/dtls12/message/mod.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -335,19 +335,24 @@ impl SignatureAndHashAlgorithm {
335335
Ok((input, SignatureAndHashAlgorithm::from_u16(value)))
336336
}
337337

338-
/// All recognized signature+hash combinations (same as `supported()`).
338+
/// All recognized signature+hash combinations.
339339
#[allow(dead_code)]
340340
pub const fn all() -> &'static [SignatureAndHashAlgorithm; 4] {
341-
Self::supported()
341+
const ALL: &[SignatureAndHashAlgorithm; 4] = &[
342+
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA256, SignatureAlgorithm::ECDSA),
343+
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA384, SignatureAlgorithm::ECDSA),
344+
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA256, SignatureAlgorithm::RSA),
345+
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA384, SignatureAlgorithm::RSA),
346+
];
347+
348+
ALL
342349
}
343350

344351
/// Supported signature+hash combinations.
345-
pub const fn supported() -> &'static [SignatureAndHashAlgorithm; 4] {
346-
const SUPPORTED: &[SignatureAndHashAlgorithm; 4] = &[
352+
pub const fn supported() -> &'static [SignatureAndHashAlgorithm; 2] {
353+
const SUPPORTED: &[SignatureAndHashAlgorithm; 2] = &[
347354
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA256, SignatureAlgorithm::ECDSA),
348355
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA384, SignatureAlgorithm::ECDSA),
349-
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA256, SignatureAlgorithm::RSA),
350-
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA384, SignatureAlgorithm::RSA),
351356
];
352357

353358
SUPPORTED
@@ -363,6 +368,16 @@ impl SignatureAndHashAlgorithm {
363368
mod tests {
364369
use super::*;
365370

371+
#[test]
372+
fn rsa_signature_algorithms_are_recognized_but_not_supported() {
373+
let rsa_sha256 =
374+
SignatureAndHashAlgorithm::new(HashAlgorithm::SHA256, SignatureAlgorithm::RSA);
375+
376+
assert!(SignatureAndHashAlgorithm::all().contains(&rsa_sha256));
377+
assert!(!rsa_sha256.is_supported());
378+
assert_eq!(SignatureAndHashAlgorithm::supported().len(), 2);
379+
}
380+
366381
#[test]
367382
fn dtls12_cipher_suite_newtype_shape() {
368383
assert_eq!(std::mem::size_of::<Dtls12CipherSuite>(), 2);

src/dtls12/server.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1395,7 +1395,7 @@ fn select_ske_signature_algorithm(
13951395
fn select_certificate_request_sig_algs(
13961396
client_algs: Option<&SignatureAndHashAlgorithmVec>,
13971397
) -> SignatureAndHashAlgorithmVec {
1398-
// Our supported set (RSA/ECDSA with SHA256/384)
1398+
// Only select algorithms supported by dimpl's signature verifiers.
13991399
let ours = SignatureAndHashAlgorithm::supported();
14001400

14011401
// Build intersection preserving client preference order
@@ -1467,4 +1467,36 @@ mod tests {
14671467

14681468
assert_eq!(selected, None);
14691469
}
1470+
1471+
#[test]
1472+
fn certificate_request_does_not_select_rsa_signatures() {
1473+
let mut client = SignatureAndHashAlgorithmVec::new();
1474+
client.push(SignatureAndHashAlgorithm::new(
1475+
HashAlgorithm::SHA256,
1476+
SignatureAlgorithm::ECDSA,
1477+
));
1478+
client.push(SignatureAndHashAlgorithm::new(
1479+
HashAlgorithm::SHA256,
1480+
SignatureAlgorithm::RSA,
1481+
));
1482+
1483+
let selected = select_certificate_request_sig_algs(Some(&client));
1484+
1485+
assert_eq!(selected.len(), 1);
1486+
assert_eq!(selected[0].signature, SignatureAlgorithm::ECDSA);
1487+
assert_eq!(selected[0].hash, HashAlgorithm::SHA256);
1488+
}
1489+
1490+
#[test]
1491+
fn certificate_request_rejects_rsa_only_signatures() {
1492+
let mut client = SignatureAndHashAlgorithmVec::new();
1493+
client.push(SignatureAndHashAlgorithm::new(
1494+
HashAlgorithm::SHA256,
1495+
SignatureAlgorithm::RSA,
1496+
));
1497+
1498+
let selected = select_certificate_request_sig_algs(Some(&client));
1499+
1500+
assert!(selected.is_empty());
1501+
}
14701502
}

src/dtls13/incoming.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,13 @@ impl Records {
129129

130130
// This is the ONLY copy: packet -> record buffer
131131
let record_slice = &packet[..record_end];
132-
match Record::parse(record_slice, decrypt, cs) {
133-
Ok(record) => {
134-
if let Some(record) = record {
135-
if parsed_records.try_push(record).is_err() {
136-
return Err(InternalError::too_many_records());
137-
}
138-
} else {
139-
trace!("Discarding replayed rec");
140-
}
132+
let record = Record::parse(record_slice, decrypt, cs)?;
133+
if let Some(record) = record {
134+
if parsed_records.try_push(record).is_err() {
135+
return Err(InternalError::too_many_records());
141136
}
142-
Err(e) => return Err(e),
137+
} else {
138+
trace!("Discarding replayed rec");
143139
}
144140

145141
packet = &packet[record_end..];

0 commit comments

Comments
 (0)