pdfium_render/pdf/document/signature.rs
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 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
//! 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::error::{PdfiumError, PdfiumInternalError};
use crate::utils::mem::create_byte_buffer;
use crate::utils::utf16le::get_string_from_pdfium_utf16le_bytes;
use std::ffi::{c_uint, CString};
use std::os::raw::{c_char, c_void};
/// The modification detection permission (MDP) applicable to a single digital signature
/// in a `PdfDocument`.
///
/// For more information on MDP, refer to "DocMDP" in Section 8.7.1 on page 731 of
/// The PDF Reference, Sixth Edition. The permission levels in this enumeration
/// correspond to those listed in table 8.104 on page 733.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum PdfSignatureModificationDetectionPermission {
/// MDP access permission level 1: no changes to the document are permitted;
/// any change to the document invalidates the signature.
Mdp1,
/// MDP access permission level 2: permitted changes are filling in forms,
/// instantiating page templates, and signing; other changes invalidate the signature.
Mdp2,
/// MDP access permission level 3: permitted changes are the same as for level 2,
/// as well as annotation creation, deletion, and modification; other changes
/// invalidate the signature.
Mdp3,
}
impl PdfSignatureModificationDetectionPermission {
#[inline]
pub(crate) fn from_pdfium(raw: c_uint) -> Result<Self, PdfiumError> {
match raw {
0 => Err(PdfiumError::PdfiumLibraryInternalError(
PdfiumInternalError::Unknown,
)),
1 => Ok(PdfSignatureModificationDetectionPermission::Mdp1),
2 => Ok(PdfSignatureModificationDetectionPermission::Mdp2),
3 => Ok(PdfSignatureModificationDetectionPermission::Mdp3),
_ => Err(PdfiumError::UnknownPdfSignatureModificationDetectionPermissionLevel),
}
}
}
/// 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 timezone information included.
///
/// This value should only be used if the date of signing is not available in the
/// PKCS#7 digital signature.
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
}
}
/// Returns the modification detection permission (MDP) applicable to this [PdfSignature],
/// if available.
///
/// For more information on MDP, refer to "DocMDP" in Section 8.7.1 on page 731 of
/// The PDF Reference, Sixth Edition.
pub fn modification_detection_permission(
&self,
) -> Result<PdfSignatureModificationDetectionPermission, PdfiumError> {
PdfSignatureModificationDetectionPermission::from_pdfium(
self.bindings
.FPDFSignatureObj_GetDocMDPPermission(self.handle),
)
}
}