mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-14 06:42:20 +00:00
fix(sign): every signature's VRI entry shares the store's evidence arrays instead of copying them (#7038)
This commit is contained in:
1 parent
b0607f5cd3
commit
b167422b2e
2 files changed
+22
-10
No files matched your search
+15
-10
@@ -69,12 +69,17 @@ pub fn embed(doc: &Document, evidence: &Evidence) -> Result<Vec<u8>, SignError>
|
||||
let mut dss = Dict::new();
|
||||
dss.set(b"Type".to_vec(), Object::name("DSS"));
|
||||
dss.set(b"Filter".to_vec(), Object::name("Adobe.PPKLite"));
|
||||
dss.set(b"Certs".to_vec(), Object::Ref(doc.add(Object::Array(cert_refs.clone()))));
|
||||
if !ocsp_refs.is_empty() {
|
||||
dss.set(b"OCSPs".to_vec(), Object::Ref(doc.add(Object::Array(ocsp_refs.clone()))));
|
||||
// Each list is one indirect array the store and every signature's VRI entry point to, so the
|
||||
// output does not grow with signatures times evidence.
|
||||
let cert_list = Object::Ref(doc.add(Object::Array(cert_refs)));
|
||||
let ocsp_list = (!ocsp_refs.is_empty()).then(|| Object::Ref(doc.add(Object::Array(ocsp_refs))));
|
||||
let crl_list = (!crl_refs.is_empty()).then(|| Object::Ref(doc.add(Object::Array(crl_refs))));
|
||||
dss.set(b"Certs".to_vec(), cert_list.clone());
|
||||
if let Some(l) = &ocsp_list {
|
||||
dss.set(b"OCSPs".to_vec(), l.clone());
|
||||
}
|
||||
if !crl_refs.is_empty() {
|
||||
dss.set(b"CRLs".to_vec(), Object::Ref(doc.add(Object::Array(crl_refs.clone()))));
|
||||
if let Some(l) = &crl_list {
|
||||
dss.set(b"CRLs".to_vec(), l.clone());
|
||||
}
|
||||
// Keep any existing /VRI entries, then cover every signature in the file.
|
||||
let mut vri =
|
||||
@@ -82,12 +87,12 @@ pub fn embed(doc: &Document, evidence: &Evidence) -> Result<Vec<u8>, SignError>
|
||||
for contents in crate::pdf::signature_contents(&doc) {
|
||||
let mut e = Dict::new();
|
||||
e.set(b"Type".to_vec(), Object::name("VRI"));
|
||||
e.set(b"Cert".to_vec(), Object::Array(cert_refs.clone()));
|
||||
if !ocsp_refs.is_empty() {
|
||||
e.set(b"OCSP".to_vec(), Object::Array(ocsp_refs.clone()));
|
||||
e.set(b"Cert".to_vec(), cert_list.clone());
|
||||
if let Some(l) = &ocsp_list {
|
||||
e.set(b"OCSP".to_vec(), l.clone());
|
||||
}
|
||||
if !crl_refs.is_empty() {
|
||||
e.set(b"CRL".to_vec(), Object::Array(crl_refs.clone()));
|
||||
if let Some(l) = &crl_list {
|
||||
e.set(b"CRL".to_vec(), l.clone());
|
||||
}
|
||||
vri.set(vri_key(&contents).into_bytes(), Object::Dict(e));
|
||||
}
|
||||
|
||||
@@ -1050,6 +1050,13 @@ fn embedding_ltv_evidence_adds_a_dss_and_keeps_signatures_valid() {
|
||||
doc.get(root).as_dict().unwrap().get(b"DSS").map(|d| doc.resolve(d)).and_then(|d| d.as_dict().cloned()).unwrap();
|
||||
assert_eq!(dss_dict.name(b"Type"), Some(b"DSS".as_slice()));
|
||||
assert!(dss_dict.contains(b"Certs") && dss_dict.contains(b"OCSPs") && dss_dict.contains(b"CRLs") && dss_dict.contains(b"VRI"));
|
||||
// A signature's /VRI entry points at the store's arrays instead of holding its own copy of each.
|
||||
let vri = dss_dict.get(b"VRI").map(|v| doc.resolve(v)).and_then(|v| v.as_dict().cloned()).unwrap();
|
||||
let entry = vri.iter().next().and_then(|(_, e)| e.as_dict().cloned()).unwrap();
|
||||
for (vri_key, dss_key) in [(&b"Cert"[..], &b"Certs"[..]), (b"OCSP", b"OCSPs"), (b"CRL", b"CRLs")] {
|
||||
assert!(matches!(entry.get(vri_key), Some(pdfcraft_cos::Object::Ref(_))));
|
||||
assert_eq!(entry.get(vri_key), dss_dict.get(dss_key));
|
||||
}
|
||||
// The earlier signature still validates; the DSS counts as a permitted change.
|
||||
let s = signatures(&doc, <v, &TrustStore::default()).into_iter().find(|s| s.signed && !s.doc_timestamp).unwrap();
|
||||
assert_eq!(s.status, Status::Unknown);
|
||||
|
||||
Reference in new issue
Block a user