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
//! 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>) -> Option<SignatureBlockFormat1<'a>> {
if self.format() != 1 {
return None;
}
let signature = self
.signature_block_offset()
.resolve::<SignatureBlockFormat1>(data)
.ok()?;
// The inner block has to agree with the record's own length field.
// Where they disagree there is no saying which one to believe, so the
// block is not readable.
(self.length() == u32::try_from(signature.compute_len()).ok()?).then_some(signature)
}
}
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};
/// 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);
assert!(record.signature_block(data).is_none());
}
// 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];
// The inner length requires more bytes than the outer length
// prescribes, so the block cannot be read.
assert!(record.signature_block(data).is_none());
}
}