Skip to content

Commit 1c7521e

Browse files
authored
fix: Fix PER encoding of empty octet strings missing the length determinant (#393)
1 parent 84e117d commit 1c7521e

File tree

3 files changed

+327
-3
lines changed

3 files changed

+327
-3
lines changed

src/per/enc.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -613,8 +613,8 @@ impl<const RCL: usize, const ECL: usize> Encoder<RCL, ECL> {
613613
self.encode_length(buffer, value.len(), <_>::default(), |range| {
614614
Ok(BitString::from_slice(&value[range]))
615615
})?;
616-
} else if 0 == size.constraint.effective_value(value.len()).into_inner() {
617-
// NO-OP
616+
} else if Some(0) == size.constraint.range() {
617+
// ITU-T X.691 (02/2021) §11.9.3.3: If "n" is zero there shall be no further addition to the field-list.
618618
} else if size.constraint.range() == Some(1) && size.constraint.as_start() <= Some(&2) {
619619
// ITU-T X.691 (02/2021) §17 NOTE: Octet strings of fixed length less than or equal to two octets are not octet-aligned.
620620
// All other octet strings are octet-aligned in the ALIGNED variant.

src/uper.rs

+195
Original file line numberDiff line numberDiff line change
@@ -1044,4 +1044,199 @@ mod tests {
10441044
&[0b11000000, 0x20, 0x20, 0x60, 0x20, 0x40, 0x60, 0x20, 0x80, 0x60, 0x20, 0x40, 0x60]
10451045
);
10461046
}
1047+
1048+
/// Tests that unaligned OctetStrings are encoded and decoded correctly (UPER).
1049+
#[test]
1050+
fn test_unaligned_sequence_with_octet_string() {
1051+
use crate as rasn;
1052+
#[derive(AsnType, Clone, Debug, Default, Decode, Encode, PartialEq)]
1053+
#[rasn(automatic_tags)]
1054+
struct Unaligned {
1055+
#[rasn(value("0..=7"))]
1056+
pub offset_bits: u8,
1057+
#[rasn(size("0..=255"))]
1058+
pub the_string: OctetString,
1059+
}
1060+
/// Describes the encodings of a given string (first array in a tuple) into its
1061+
/// UPER representation (second array in a tuple).
1062+
const UPER_UNALIGNED_CASES: &[(&[u8], &[u8])] = &[
1063+
(&[], &[0xe0, 0x00]), // The minimum encoding contains 3 + 8 bits.
1064+
(&[0x00; 1], &[0xe0, 0x20, 0x00]),
1065+
(&[0xF0; 1], &[0xe0, 0x3e, 0x00]),
1066+
(&[0xFF; 1], &[0xe0, 0x3f, 0xe0]),
1067+
(&[0x00; 4], &[0xe0, 0x80, 0x00, 0x00, 0x00, 0x00]),
1068+
(&[0xFF; 4], &[0xe0, 0x9f, 0xff, 0xff, 0xff, 0xe0]),
1069+
(
1070+
&[0x00; 10],
1071+
&[
1072+
0xe1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1073+
],
1074+
),
1075+
(
1076+
&[0xFF; 10],
1077+
&[
1078+
0xe1, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
1079+
],
1080+
),
1081+
(
1082+
&[0x00; 100],
1083+
&[
1084+
0xec, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1085+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1086+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1087+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1088+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1089+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1090+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1091+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1092+
],
1093+
),
1094+
(
1095+
&[0x00; 127],
1096+
&[
1097+
0xef, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1098+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1099+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1100+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1101+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1102+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1103+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1104+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1105+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1106+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1107+
],
1108+
),
1109+
(
1110+
&[0x00; 128],
1111+
&[
1112+
0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1113+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1114+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1115+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1116+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1117+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1118+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1119+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1120+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1121+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1122+
],
1123+
),
1124+
(
1125+
&[0x00; 200],
1126+
&[
1127+
0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1128+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1129+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1130+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1131+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1132+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1133+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1134+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1135+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1136+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1137+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1138+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1139+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1140+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1141+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1142+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1143+
],
1144+
),
1145+
(
1146+
&[0x00; 255],
1147+
&[
1148+
0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1149+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1150+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1151+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1152+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1153+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1154+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1155+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1156+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1157+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1158+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1159+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1160+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1161+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1162+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1163+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1164+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1165+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1166+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1167+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1168+
],
1169+
),
1170+
];
1171+
for (case, expected) in UPER_UNALIGNED_CASES {
1172+
round_trip!(
1173+
uper,
1174+
Unaligned,
1175+
Unaligned {
1176+
offset_bits: 7,
1177+
the_string: OctetString::from_static(case)
1178+
},
1179+
expected
1180+
);
1181+
}
1182+
}
1183+
1184+
#[test]
1185+
fn test_encoding_of_zero_size_octet_string() {
1186+
use crate as rasn;
1187+
1188+
#[derive(AsnType, Clone, Debug, Default, Decode, Encode, PartialEq)]
1189+
#[rasn(automatic_tags)]
1190+
struct Unaligned {
1191+
#[rasn(value("0..=7"))]
1192+
pub offset_bits: u8,
1193+
#[rasn(size("0..=255"))]
1194+
pub the_string: OctetString,
1195+
}
1196+
1197+
round_trip!(
1198+
uper,
1199+
Unaligned,
1200+
Unaligned {
1201+
offset_bits: 7,
1202+
the_string: OctetString::from_static(&[])
1203+
},
1204+
&[0b11100000, 0b00000000]
1205+
);
1206+
1207+
#[derive(AsnType, Clone, Debug, Default, Decode, Encode, PartialEq)]
1208+
#[rasn(automatic_tags)]
1209+
struct UnalignedZeroLength {
1210+
#[rasn(value("0..=7"))]
1211+
pub offset_bits: u8,
1212+
#[rasn(size("0"))]
1213+
pub the_string: OctetString,
1214+
}
1215+
1216+
round_trip!(
1217+
uper,
1218+
UnalignedZeroLength,
1219+
UnalignedZeroLength {
1220+
offset_bits: 7,
1221+
the_string: OctetString::from_static(&[])
1222+
},
1223+
&[0b11100000]
1224+
);
1225+
1226+
#[derive(AsnType, Clone, Debug, Default, Decode, Encode, PartialEq)]
1227+
#[rasn(automatic_tags)]
1228+
struct AlignedZeroLength {
1229+
#[rasn(size("0"))]
1230+
pub the_string: OctetString,
1231+
}
1232+
1233+
round_trip!(
1234+
uper,
1235+
AlignedZeroLength,
1236+
AlignedZeroLength {
1237+
the_string: OctetString::from_static(&[])
1238+
},
1239+
&[]
1240+
);
1241+
}
10471242
}

tests/strings.rs

+130-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bitvec::prelude::*;
22
use rasn::prelude::*;
3-
use rasn::{ber, jer, oer, uper};
3+
use rasn::{aper, ber, jer, oer, uper};
44

55
#[derive(AsnType, Decode, Encode, Debug, Clone, PartialEq)]
66
#[rasn(automatic_tags)]
@@ -327,3 +327,132 @@ fn test_jer_octetstring_dec() {
327327
}
328328
}
329329
}
330+
331+
// Tests that OctetStrings are encoded and decoded correctly (APER, UPER).
332+
const BYTE_ARRAYS: &[&[u8]] = &[
333+
&[],
334+
&[0x00; 1],
335+
&[0x00; 2],
336+
&[0x0F; 1],
337+
&[0xFF; 1],
338+
&[0xFF; 2],
339+
&[0x00; 10],
340+
&[0x00; 100],
341+
&[0x00; 128],
342+
&[0x00; 200],
343+
&[0x01, 0x23],
344+
&[0xAB, 0xCD],
345+
&[0xAB, 0xCD, 0xEF],
346+
&[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF],
347+
&[0x00; 255],
348+
&[0x0F; 255],
349+
&[0xFF; 255],
350+
&[0x00; 256],
351+
&[0x0F; 256],
352+
&[0xFF; 256],
353+
&[0x00; 16383],
354+
&[0x0F; 16383],
355+
&[0xFF; 16383],
356+
];
357+
358+
#[test]
359+
fn test_per_encode_octet_string() {
360+
for case in BYTE_ARRAYS {
361+
let length = case.len(); // number of bytes
362+
let mut buf_expected: Vec<u8> = Vec::new();
363+
if length < 128 {
364+
// X.691, 11.9.a)
365+
buf_expected.push(length as u8);
366+
} else if length < 16384 {
367+
// X.691, 11.9.b)
368+
let length = (length as u16).to_be_bytes();
369+
buf_expected.push(0b10000000 | length[0]);
370+
buf_expected.push(length[1]);
371+
} else {
372+
// X.691, 11.9.c)
373+
todo!("implement chunk generation");
374+
}
375+
buf_expected.extend_from_slice(case);
376+
377+
let bytes = OctetString::copy_from_slice(case);
378+
assert_eq!(buf_expected, aper::encode::<OctetString>(&bytes).unwrap());
379+
assert_eq!(buf_expected, uper::encode::<OctetString>(&bytes).unwrap());
380+
381+
assert_eq!(*case, aper::decode::<OctetString>(&buf_expected).unwrap());
382+
assert_eq!(*case, uper::decode::<OctetString>(&buf_expected).unwrap());
383+
}
384+
}
385+
386+
// Tests that UTF8Strings are encoded and decoded correctly (APER, UPER).
387+
const UTF8_STRINGS: &[&str] = &[
388+
"",
389+
"Hello World!",
390+
"Hello World! 🌍",
391+
"こんにちは世界!",
392+
"你好世界!",
393+
"안녕하세요!",
394+
"مرحبا بالعالم!",
395+
"હેલો વિશ્વ!",
396+
"привіт світ!",
397+
" ",
398+
"!",
399+
"0",
400+
" 0",
401+
"0 ",
402+
"0!",
403+
" ",
404+
"000",
405+
"Œ",
406+
"ŒŒ",
407+
"ŒŒŒ",
408+
"ABCDEFG",
409+
" ABCDEF",
410+
"åäö",
411+
"\0",
412+
"\n",
413+
"\r\nASN.1",
414+
"\u{0000}",
415+
"\u{0001}",
416+
"\u{FFFF}",
417+
"\u{0123}",
418+
"\u{30}",
419+
"\\u0030",
420+
"\\u202E\\u0030\\u0030",
421+
"⣐⡄",
422+
"😎",
423+
"🙈🙉🙊",
424+
"👭👩🏻‍🤝‍👨🏾🧑🏿‍🤝‍🧑🏼",
425+
];
426+
427+
#[test]
428+
fn test_per_encode_utf8_string() {
429+
for case in UTF8_STRINGS {
430+
let case = case.to_string();
431+
// The X.691 spec, chapter 11.9, says determinant should be the number
432+
// of characters, but for UTF-8 this is a non-trivial operation and
433+
// dependant on the supported Unicode release. Actual implementations
434+
// seem to interpret the spec as "number of octets" instead - which is
435+
// reasonable (see `asn1tools` for example).
436+
let length = case.len(); // number of bytes
437+
let mut buf_expected: Vec<u8> = Vec::new();
438+
if length < 128 {
439+
// X.691, 11.9.a)
440+
buf_expected.push(length as u8);
441+
} else if length < 16384 {
442+
// X.691, 11.9.b)
443+
let length = length.to_le_bytes();
444+
buf_expected.push(0b10000000 | length[1]);
445+
buf_expected.push(length[0]);
446+
} else {
447+
// X.691, 11.9.c)
448+
todo!("implement chunk generation");
449+
}
450+
buf_expected.extend_from_slice(case.as_bytes());
451+
452+
assert_eq!(buf_expected, aper::encode::<Utf8String>(&case).unwrap());
453+
assert_eq!(buf_expected, uper::encode::<Utf8String>(&case).unwrap());
454+
455+
assert_eq!(case, aper::decode::<Utf8String>(&buf_expected).unwrap());
456+
assert_eq!(case, uper::decode::<Utf8String>(&buf_expected).unwrap());
457+
}
458+
}

0 commit comments

Comments
 (0)