1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! The [DSIG](https://learn.microsoft.com/en-us/typography/opentype/spec/dsig) table
include!("../../generated/generated_dsig.rs");
impl SignatureRecord {
/// The signature block enclosed within this record.
///
/// The `data` argument should be retrieved from the parent table
/// By calling its `offset_data` method.
///
/// Only format 1 is recognised and read successfully.
pub fn signature_block<'a>(
&self,
data: FontData<'a>,
) -> Result<SignatureBlockFormat1<'a>, ReadError> {
match self.format() {
1 => {
let signature = self
.signature_block_offset()
.resolve::<SignatureBlockFormat1>(data)?;
// Check that the inner block's size matches our length field.
let actual_len =
u32::try_from(signature.compute_len()).map_err(|_| ReadError::OutOfBounds)?;
if self.length() == actual_len {
Ok(signature)
} else {
Err(ReadError::MalformedData("ambiguous DSIG signature length"))
}
}
unknown => Err(ReadError::InvalidFormat(unknown.into())),
}
}
}
impl SignatureBlockFormat1<'_> {
/// Return the exact byte length of this table.
fn compute_len(&self) -> usize {
// This format is contiguous, and includes no trailing data.
self.min_byte_range().len()
}
}
#[cfg(test)]
mod tests {
use font_test_data::bebuffer::BeBuffer;
use super::{Dsig, PermissionFlags};
use crate::{FontData, FontRead, ReadError};
/// An empty, dummy DSIG, as inserted by fonttools.
/// See <https://github.com/fonttools/fonttools/blob/ec716f11851f8d5a04e3f535b53219d97001482a/Lib/fontTools/fontBuilder.py#L823-L833>.
#[test]
fn test_empty() {
let buf = BeBuffer::new()
.push(0x1u32) // version
.push(0x0u16) // numSignatures
.push(0x0u16); // flags
let dsig = Dsig::read(FontData::new(buf.data())).unwrap();
assert_eq!(dsig.version(), 1);
assert_eq!(dsig.signature_records().len(), 0);
assert_eq!(dsig.flags(), PermissionFlags::empty());
}
// A DSIG with a single entry. For ease-of-testing, we use 0xDEADBEEF
// instead of a full PKCS#7 packet, as it would not be this crate's
// responsibility to validate it anyway.
#[test]
fn test_beef() {
let buf = BeBuffer::new()
.push(0x1_u32) // DsigHeader.version
.push(0x1_u16) // DsigHeader.numSignatures
.push(0x1_u16) // DsigHeader.flags
.push(0x1_u32) // SignatureRecord.format
.push(0xC_u32) // SignatureRecord.length
.push(0x14_u32) // SignatureRecord.signatureBlockOffset
.push(0x0_u16) // SignatureBlockFormat1.reserved1
.push(0x0_u16) // SignatureBlockFormat1.reserved2
.push(0x4_u32) // SignatureBlockFormat1.signatureLength
.push(0xDEADBEEF_u32); // SignatureBlockFormat1.signature
let data = FontData::new(buf.data());
let dsig = Dsig::read(data).unwrap();
assert_eq!(dsig.version(), 1);
assert_eq!(dsig.signature_records().len(), 1);
assert_eq!(dsig.flags(), PermissionFlags::CANNOT_BE_RESIGNED);
let record = dsig.signature_records()[0];
assert_eq!(record.format(), 1);
let block = record.signature_block(data).unwrap();
assert_eq!(block.signature(), &[0xDE, 0xAD, 0xBE, 0xEF]);
}
// A DSIG with a single entry, but in a format we do not recognise; this
// should fail to read.
#[test]
fn test_unknown_format() {
let buf = BeBuffer::new()
.push(0x1_u32) // DsigHeader.version
.push(0x1_u16) // DsigHeader.numSignatures
.push(0x1_u16) // DsigHeader.flags
.push(0x2_u32) // SignatureRecord.format, BUT AN UNRECOGNISED ONE
.push(0xC_u32) // SignatureRecord.length
.push(0x14_u32) // SignatureRecord.signatureBlockOffset
.push(0x0_u16) // SignatureBlockFormat1.reserved1
.push(0x0_u16) // SignatureBlockFormat1.reserved2
.push(0x4_u32) // SignatureBlockFormat1.signatureLength
.push(0xDEADBEEF_u32); // SignatureBlockFormat1.signature
let data = FontData::new(buf.data());
// Load the first record.
let dsig = Dsig::read(data).unwrap();
assert_eq!(dsig.signature_records().len(), 1);
let record = dsig.signature_records()[0];
// Assert that it is the unknown format '2', and that it fails to be read.
assert_eq!(record.format(), 2);
let block_attempt = record.signature_block(data);
assert_eq!(block_attempt.err(), Some(ReadError::InvalidFormat(2)));
}
// A DSIG with a single entry, whose inner block has a different length to
// that which the outer record's length field prescribes; this is ambiguous,
// and so should fail to read.
#[test]
fn test_lying_length() {
let buf = BeBuffer::new()
.push(0x1_u32) // DsigHeader.version
.push(0x1_u16) // DsigHeader.numSignatures
.push(0x1_u16) // DsigHeader.flags
.push(0x1_u32) // SignatureRecord.format
.push(0xB_u32) // SignatureRecord.length, BUT ONE LESS THAN THE INNER LENGTH REQUIRES
.push(0x14_u32) // SignatureRecord.signatureBlockOffset
.push(0x0_u16) // SignatureBlockFormat1.reserved1
.push(0x0_u16) // SignatureBlockFormat1.reserved2
.push(0x4_u32) // SignatureBlockFormat1.signatureLength
.push(0xDEADBEEF_u32); // SignatureBlockFormat1.signature
let data = FontData::new(buf.data());
// Load the first record.
let dsig = Dsig::read(data).unwrap();
assert_eq!(dsig.signature_records().len(), 1);
let record = dsig.signature_records()[0];
// Assert that we yield an error, because the inner length requires more
// bytes than the outer length prescribes.
let block_attempt = record.signature_block(data);
assert_eq!(
block_attempt.err(),
Some(ReadError::MalformedData("ambiguous DSIG signature length"))
);
}
}