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
//! Defines the [PdfSignature] struct, exposing functionality related to a single
//! digital signature in a `PdfSignatures` collection.
use crate::bindgen::FPDF_SIGNATURE;
use crate::bindings::PdfiumLibraryBindings;
use crate::utils::mem::create_byte_buffer;
use crate::utils::utf16le::get_string_from_pdfium_utf16le_bytes;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};
/// A single digital signature in a `PdfDocument`.
pub struct PdfSignature<'a> {
handle: FPDF_SIGNATURE,
bindings: &'a dyn PdfiumLibraryBindings,
}
impl<'a> PdfSignature<'a> {
#[inline]
pub(crate) fn from_pdfium(
handle: FPDF_SIGNATURE,
bindings: &'a dyn PdfiumLibraryBindings,
) -> Self {
PdfSignature { handle, bindings }
}
/// Returns the [PdfiumLibraryBindings] used by this [PdfSignature].
#[inline]
pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
self.bindings
}
/// Returns the raw byte data for this [PdfSignature].
///
/// For public key signatures, the byte data is either a DER-encoded PKCS#1 binary or
/// a DER-encoded PKCS#7 binary.
pub fn bytes(&self) -> Vec<u8> {
// Retrieving the byte data from Pdfium is a two-step operation. First, we call
// FPDFSignatureObj_GetContents() with a null buffer; this will retrieve the length of
// the reason text in bytes. If the length is zero, then there is no reason associated
// with this signature.
// If the length is non-zero, then we reserve a byte buffer of the given
// length and call FPDFSignatureObj_GetContents() again with a pointer to the buffer;
// this will write the reason text to the buffer in UTF16-LE format.
let buffer_length =
self.bindings()
.FPDFSignatureObj_GetContents(self.handle, std::ptr::null_mut(), 0);
if buffer_length == 0 {
// The signature is empty.
return Vec::new();
}
let mut buffer = create_byte_buffer(buffer_length as usize);
let result = self.bindings().FPDFSignatureObj_GetContents(
self.handle,
buffer.as_mut_ptr() as *mut c_void,
buffer_length,
);
assert_eq!(result, buffer_length);
buffer
}
/// Returns the reason for the signing, if any, as a plain text description provided by the
/// creator of this [PdfSignature].
pub fn reason(&self) -> Option<String> {
// Retrieving the reason from Pdfium is a two-step operation. First, we call
// FPDFSignatureObj_GetReason() with a null buffer; this will retrieve the length of
// the reason text in bytes. If the length is zero, then there is no reason associated
// with this signature.
// If the length is non-zero, then we reserve a byte buffer of the given
// length and call FPDFSignatureObj_GetReason() again with a pointer to the buffer;
// this will write the reason text to the buffer in UTF16-LE format.
let buffer_length =
self.bindings()
.FPDFSignatureObj_GetReason(self.handle, std::ptr::null_mut(), 0);
if buffer_length == 0 {
// There is no reason given for this signature.
return None;
}
let mut buffer = create_byte_buffer(buffer_length as usize);
let result = self.bindings().FPDFSignatureObj_GetReason(
self.handle,
buffer.as_mut_ptr() as *mut c_void,
buffer_length,
);
assert_eq!(result, buffer_length);
get_string_from_pdfium_utf16le_bytes(buffer)
}
/// Returns the date, if any, in plain text format as specified by the creator of this [PdfSignature].
/// The format of the returned value is expected to be D:YYYYMMDDHHMMSS+XX'YY', with precision
/// to the second and including timezone information.
///
/// This value should only be used if the date of signing is not encoded into the digital signature itself.
pub fn signing_date(&self) -> Option<String> {
// Retrieving the signing date from Pdfium is a two-step operation. First, we call
// FPDFSignatureObj_GetTime() with a null buffer; this will retrieve the length of
// the timestamp in bytes. If the length is zero, then there is no timestamp associated
// with this signature.
// If the length is non-zero, then we reserve a byte buffer of the given
// length and call FPDFSignatureObj_GetTime() again with a pointer to the buffer;
// this will write the timestamp to the buffer as an array of 7-bit ASCII characters.
let buffer_length =
self.bindings()
.FPDFSignatureObj_GetTime(self.handle, std::ptr::null_mut(), 0);
if buffer_length == 0 {
// There is no timestamp given for this signature.
return None;
}
let mut buffer = create_byte_buffer(buffer_length as usize);
let result = self.bindings().FPDFSignatureObj_GetTime(
self.handle,
buffer.as_mut_ptr() as *mut c_char,
buffer_length,
);
assert_eq!(result, buffer_length);
if let Ok(result) = CString::from_vec_with_nul(buffer) {
result.into_string().ok()
} else {
None
}
}
}