2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 10:58:58 +00:00

Implement --disable-signatures (fixes #1015)

This commit is contained in:
Jay Berkenbilt 2023-12-23 08:44:42 -05:00
parent 3d33a3a1e3
commit 909a0b3f3a
14 changed files with 103 additions and 40 deletions

View File

@ -1,3 +1,10 @@
2023-12-23 Jay Berkenbilt <ejb@ql.org>
* Add QPDFAcroFormDocumentHelper::disableDigitalSignatures and the
--disable-signatures command-line argument. This disables any
digital signature fields, leaving their visual representations
intact.
2023-12-22 Jay Berkenbilt <ejb@ql.org> 2023-12-22 Jay Berkenbilt <ejb@ql.org>
* Generate a more complete qpdf "man page" from the same source as * Generate a more complete qpdf "man page" from the same source as

View File

@ -557,6 +557,7 @@ class QPDFJob
bool linearize{false}; bool linearize{false};
bool decrypt{false}; bool decrypt{false};
bool remove_restrictions{false}; bool remove_restrictions{false};
bool disable_signatures{false};
int split_pages{0}; int split_pages{0};
bool progress{false}; bool progress{false};
std::function<void(int)> progress_handler{nullptr}; std::function<void(int)> progress_handler{nullptr};

View File

@ -11,6 +11,7 @@ QPDF_DLL Config* checkLinearization();
QPDF_DLL Config* coalesceContents(); QPDF_DLL Config* coalesceContents();
QPDF_DLL Config* decrypt(); QPDF_DLL Config* decrypt();
QPDF_DLL Config* deterministicId(); QPDF_DLL Config* deterministicId();
QPDF_DLL Config* disableSignatures();
QPDF_DLL Config* externalizeInlineImages(); QPDF_DLL Config* externalizeInlineImages();
QPDF_DLL Config* filteredStreamData(); QPDF_DLL Config* filteredStreamData();
QPDF_DLL Config* flattenRotation(); QPDF_DLL Config* flattenRotation();

View File

@ -4,17 +4,17 @@ generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a
include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4
include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42
include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5
include/qpdf/auto_job_c_main.hh dbfc221d1533120d1aa9c361d8d2483dea5fcb1c0fd95144d98d305e64ed32a6 include/qpdf/auto_job_c_main.hh 36b5ff48ae0dca67415efececa4470cda45364b10d0905e7de9971a2af1795ea
include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec
include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1
job.yml 4f89fc7b622df897d30d403d8035aa36fc7de8d8c43042c736e0300d904cb05c job.yml 3c030ce21138967b8a6768b386c0d3bfab9ef41cafbb6ec52f30a81194a7421d
libqpdf/qpdf/auto_job_decl.hh 9c6f701c29f3f764d620186bed92685a2edf2e4d11e4f4532862c05470cfc4d2 libqpdf/qpdf/auto_job_decl.hh 9c6f701c29f3f764d620186bed92685a2edf2e4d11e4f4532862c05470cfc4d2
libqpdf/qpdf/auto_job_help.hh bbd37ac0e8b3e38892a328ca08829d6e71c31ea3ab6c1a91b5f6983018695ef9 libqpdf/qpdf/auto_job_help.hh 57ea412972105bf302b78b88ae2d6abfc93cae6f5ff99a55e78f860db9354643
libqpdf/qpdf/auto_job_init.hh b4c2b3724fba61f1206fd3bae81951636852592f67a63ef9539839c2c5995065 libqpdf/qpdf/auto_job_init.hh 4413804cc784f288245039af053bfe74bc2755e994308220d1939e452011e5a5
libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297 libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297
libqpdf/qpdf/auto_job_json_init.hh f5acb9aa103131cb68dec0e12c4d237a6459bdb49b24773c24f0c2724a462b8f libqpdf/qpdf/auto_job_json_init.hh 7682e1e3bc465a3818036e1831aaf205478cc2e47ba5abe483d37c037b6bcf56
libqpdf/qpdf/auto_job_schema.hh b53c006fec2e75b1b73588d242d49a32f7d3db820b1541de106c5d4c27fbb4d9 libqpdf/qpdf/auto_job_schema.hh 039ee828cf91ece434f0c57706aecc40798e5537308737e01efc8f61eb20685f
manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
manual/cli.rst 7bbeb2f234ca3d095c069f52e4a3c5e42a525b5ef6231955d036a6313eaffcd2 manual/cli.rst 97aa745b37ef9824ae4cd159577f65b94935bbc545250c9065ed7d65670c68eb
manual/qpdf.1 745cb32c1772e6d84ef962aca7a439ee045226ae547330778a4a3ba3cd8d25df manual/qpdf.1 e4ffa50a6ed735860a92571d33319a2b5e6aa73cacba1bb73f80bf209be7c040
manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b

View File

@ -104,6 +104,7 @@ options:
- copy-attachments-from - copy-attachments-from
- decrypt - decrypt
- deterministic-id - deterministic-id
- disable-signatures
- empty - empty
- encrypt - encrypt
- externalize-inline-images - externalize-inline-images
@ -319,6 +320,7 @@ json:
decode-level: decode-level:
decrypt: decrypt:
deterministic-id: deterministic-id:
disable-signatures:
static-aes-iv: static-aes-iv:
static-id: static-id:
no-original-object-ids: no-original-object-ids:

View File

@ -2129,6 +2129,10 @@ QPDFJob::handleTransformations(QPDF& pdf)
if (m->remove_restrictions) { if (m->remove_restrictions) {
pdf.removeSecurityRestrictions(); pdf.removeSecurityRestrictions();
} }
if (m->disable_signatures) {
make_afdh();
afdh->disableDigitalSignatures();
}
if (m->externalize_inline_images || (m->optimize_images && (!m->keep_inline_images))) { if (m->externalize_inline_images || (m->optimize_images && (!m->keep_inline_images))) {
for (auto& ph: dh.getAllPages()) { for (auto& ph: dh.getAllPages()) {
ph.externalizeInlineImages(m->ii_min_bytes); ph.externalizeInlineImages(m->ii_min_bytes);

View File

@ -144,6 +144,13 @@ QPDFJob::Config::deterministicId()
return this; return this;
} }
QPDFJob::Config*
QPDFJob::Config::disableSignatures()
{
o.m->disable_signatures = true;
return this;
}
QPDFJob::Config* QPDFJob::Config*
QPDFJob::Config::encryptionFilePassword(std::string const& parameter) QPDFJob::Config::encryptionFilePassword(std::string const& parameter)
{ {

View File

@ -157,9 +157,15 @@ encrypted. Normally qpdf preserves whatever encryption was
present on the input file. This option overrides that behavior. present on the input file. This option overrides that behavior.
)"); )");
ap.addOptionHelp("--remove-restrictions", "transformation", "remove security restrictions from input file", R"(Remove restrictions associated with digitally signed PDF files. ap.addOptionHelp("--remove-restrictions", "transformation", "remove security restrictions from input file", R"(Remove restrictions associated with digitally signed PDF files.
This may be combined with --decrypt to allow free editing of This may be combined with --decrypt and --disable-signatures to
previously signed/encrypted files. This option invalidates the allow free editing of previously signed/encrypted files. This
signature but leaves its visual appearance intact. option invalidates the signature but leaves its visual
appearance intact. See also --disable-signatures.
)");
ap.addOptionHelp("--disable-signatures", "transformation", "disable digital signature fields", R"(Remove all digital signature fields from a file. The appearance
of the digital signature, if any, will remain on the page, but
it will no longer be a signature field. See also
--remove-restrictions.
)"); )");
ap.addOptionHelp("--copy-encryption", "transformation", "copy another file's encryption details", R"(--copy-encryption=file ap.addOptionHelp("--copy-encryption", "transformation", "copy another file's encryption details", R"(--copy-encryption=file
@ -167,14 +173,14 @@ Copy encryption details from the specified file instead of
preserving the input file's encryption. Use --encryption-file-password preserving the input file's encryption. Use --encryption-file-password
to specify the encryption file's password. to specify the encryption file's password.
)"); )");
}
static void add_help_3(QPDFArgParser& ap)
{
ap.addOptionHelp("--encryption-file-password", "transformation", "supply password for --copy-encryption", R"(--encryption-file-password=password ap.addOptionHelp("--encryption-file-password", "transformation", "supply password for --copy-encryption", R"(--encryption-file-password=password
If the file named in --copy-encryption requires a password, use If the file named in --copy-encryption requires a password, use
this option to supply the password. this option to supply the password.
)"); )");
}
static void add_help_3(QPDFArgParser& ap)
{
ap.addOptionHelp("--qdf", "transformation", "enable viewing PDF code in a text editor", R"(Create a PDF file suitable for viewing in a text editor and even ap.addOptionHelp("--qdf", "transformation", "enable viewing PDF code in a text editor", R"(Create a PDF file suitable for viewing in a text editor and even
editing. This is for editing the PDF code, not the page contents. editing. This is for editing the PDF code, not the page contents.
All streams that can be uncompressed are uncompressed, and All streams that can be uncompressed are uncompressed, and
@ -284,6 +290,9 @@ Force the output PDF file's PDF version header to be the specified
value, even if the file uses features that may not be available value, even if the file uses features that may not be available
in that version. in that version.
)"); )");
}
static void add_help_4(QPDFArgParser& ap)
{
ap.addHelpTopic("page-ranges", "page range syntax", R"(A full description of the page range syntax, with examples, can be ap.addHelpTopic("page-ranges", "page range syntax", R"(A full description of the page range syntax, with examples, can be
found in the manual. Summary: found in the manual. Summary:
@ -297,9 +306,6 @@ resulting set of pages, where :odd starts with the first page and
:even starts with the second page. These are odd and even pages :even starts with the second page. These are odd and even pages
from the resulting set, not based on the original page numbers. from the resulting set, not based on the original page numbers.
)"); )");
}
static void add_help_4(QPDFArgParser& ap)
{
ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of
the PDF, causing the PDF to render differently from the original. the PDF, causing the PDF to render differently from the original.
)"); )");
@ -475,13 +481,13 @@ ap.addOptionHelp("--user-password", "encryption", "specify user password", R"(--
Set the user password of the encrypted file. Set the user password of the encrypted file.
)"); )");
}
static void add_help_5(QPDFArgParser& ap)
{
ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password
Set the owner password of the encrypted file. Set the owner password of the encrypted file.
)"); )");
}
static void add_help_5(QPDFArgParser& ap)
{
ap.addOptionHelp("--bits", "encryption", "specify encryption key length", R"(--bits={48|128|256} ap.addOptionHelp("--bits", "encryption", "specify encryption key length", R"(--bits={48|128|256}
Specify the encryption key length. For best security, always use Specify the encryption key length. For best security, always use
@ -653,15 +659,15 @@ the destination pages. See qpdf --help=page-ranges for help
with the page range syntax. The page range may be omitted with the page range syntax. The page range may be omitted
if --repeat is used. if --repeat is used.
)"); )");
}
static void add_help_6(QPDFArgParser& ap)
{
ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range
Specify pages from the overlay/underlay that are repeated after Specify pages from the overlay/underlay that are repeated after
"from" pages have been exhausted. See qpdf --help=page-ranges "from" pages have been exhausted. See qpdf --help=page-ranges
for help with the page range syntax. for help with the page range syntax.
)"); )");
}
static void add_help_6(QPDFArgParser& ap)
{
ap.addHelpTopic("attachments", "work with embedded files", R"(It is possible to list, add, or delete embedded files (also known ap.addHelpTopic("attachments", "work with embedded files", R"(It is possible to list, add, or delete embedded files (also known
as attachments) and to copy attachments from other files. See help as attachments) and to copy attachments from other files. See help
on individual options for details. Run qpdf --help=add-attachment on individual options for details. Run qpdf --help=add-attachment
@ -770,6 +776,9 @@ ap.addOptionHelp("--requires-password", "inspection", "silently test a file's pa
2: the file is not encrypted 2: the file is not encrypted
3: the file is encrypted, and correct password (if any) has been supplied 3: the file is encrypted, and correct password (if any) has been supplied
)"); )");
}
static void add_help_7(QPDFArgParser& ap)
{
ap.addOptionHelp("--check", "inspection", "partially check whether PDF is valid", R"(Check the structure of the PDF file as well as a number of other ap.addOptionHelp("--check", "inspection", "partially check whether PDF is valid", R"(Check the structure of the PDF file as well as a number of other
aspects of the file, and write information about the file to aspects of the file, and write information about the file to
standard output. Note that qpdf does not perform any validation standard output. Note that qpdf does not perform any validation
@ -777,9 +786,6 @@ of the actual PDF page content or semantic correctness of the
PDF file. It merely checks that the PDF file is syntactically PDF file. It merely checks that the PDF file is syntactically
valid. See also qpdf --help=exit-status. valid. See also qpdf --help=exit-status.
)"); )");
}
static void add_help_7(QPDFArgParser& ap)
{
ap.addOptionHelp("--show-encryption", "inspection", "information about encrypted files", R"(Show document encryption parameters. Also show the document's ap.addOptionHelp("--show-encryption", "inspection", "information about encrypted files", R"(Show document encryption parameters. Also show the document's
user password if the owner password is given and the file was user password if the owner password is given and the file was
encrypted using older encryption formats that allow user encrypted using older encryption formats that allow user
@ -860,6 +866,9 @@ This option is repeatable. If given, only specified objects will
be shown in the "objects" key of the JSON output. Otherwise, all be shown in the "objects" key of the JSON output. Otherwise, all
objects will be shown. objects will be shown.
)"); )");
}
static void add_help_8(QPDFArgParser& ap)
{
ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file} ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file}
When used with --json, this option controls whether streams in When used with --json, this option controls whether streams in
@ -871,9 +880,6 @@ object number. The prefix can be overridden with
when --json-output is specified, in which case the default is when --json-output is specified, in which case the default is
"inline". "inline".
)"); )");
}
static void add_help_8(QPDFArgParser& ap)
{
ap.addOptionHelp("--json-stream-prefix", "json", "prefix for json stream data files", R"(--json-stream-prefix=file-prefix ap.addOptionHelp("--json-stream-prefix", "json", "prefix for json stream data files", R"(--json-stream-prefix=file-prefix
When used with --json-stream-data=file, --json-stream-data=file-prefix When used with --json-stream-data=file, --json-stream-data=file-prefix

View File

@ -43,6 +43,7 @@ this->ap.addBare("coalesce-contents", [this](){c_main->coalesceContents();});
this->ap.addBare("copy-attachments-from", b(&ArgParser::argCopyAttachmentsFrom)); this->ap.addBare("copy-attachments-from", b(&ArgParser::argCopyAttachmentsFrom));
this->ap.addBare("decrypt", [this](){c_main->decrypt();}); this->ap.addBare("decrypt", [this](){c_main->decrypt();});
this->ap.addBare("deterministic-id", [this](){c_main->deterministicId();}); this->ap.addBare("deterministic-id", [this](){c_main->deterministicId();});
this->ap.addBare("disable-signatures", [this](){c_main->disableSignatures();});
this->ap.addBare("empty", b(&ArgParser::argEmpty)); this->ap.addBare("empty", b(&ArgParser::argEmpty));
this->ap.addBare("encrypt", b(&ArgParser::argEncrypt)); this->ap.addBare("encrypt", b(&ArgParser::argEncrypt));
this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInlineImages();}); this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInlineImages();});

View File

@ -71,6 +71,9 @@ popHandler(); // key: decrypt
pushKey("deterministicId"); pushKey("deterministicId");
addBare([this]() { c_main->deterministicId(); }); addBare([this]() { c_main->deterministicId(); });
popHandler(); // key: deterministicId popHandler(); // key: deterministicId
pushKey("disableSignatures");
addBare([this]() { c_main->disableSignatures(); });
popHandler(); // key: disableSignatures
pushKey("staticAesIv"); pushKey("staticAesIv");
addBare([this]() { c_main->staticAesIv(); }); addBare([this]() { c_main->staticAesIv(); });
popHandler(); // key: staticAesIv popHandler(); // key: staticAesIv

View File

@ -16,6 +16,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({
"decodeLevel": "control which streams to uncompress", "decodeLevel": "control which streams to uncompress",
"decrypt": "remove encryption from input file", "decrypt": "remove encryption from input file",
"deterministicId": "generate ID deterministically", "deterministicId": "generate ID deterministically",
"disableSignatures": "disable digital signature fields",
"staticAesIv": "use a fixed AES vector", "staticAesIv": "use a fixed AES vector",
"staticId": "use a fixed document ID", "staticId": "use a fixed document ID",
"noOriginalObjectIds": "omit original object IDs in qdf", "noOriginalObjectIds": "omit original object IDs in qdf",

View File

@ -736,22 +736,40 @@ Related Options
whatever encryption was present on the input file. This whatever encryption was present on the input file. This
functionality is not intended to be used for bypassing copyright functionality is not intended to be used for bypassing copyright
restrictions or other restrictions placed on files by their restrictions or other restrictions placed on files by their
producers. See also :qpdf:ref:`--copy-encryption` and producers. See also :qpdf:ref:`--copy-encryption`,
:qpdf:ref:`--remove-restrictions`. :qpdf:ref:`--remove-restrictions`, and
:qpdf:ref:`--disable-signatures`.
.. qpdf:option:: --remove-restrictions .. qpdf:option:: --remove-restrictions
.. help: remove security restrictions from input file .. help: remove security restrictions from input file
Remove restrictions associated with digitally signed PDF files. Remove restrictions associated with digitally signed PDF files.
This may be combined with --decrypt to allow free editing of This may be combined with --decrypt and --disable-signatures to
previously signed/encrypted files. This option invalidates the allow free editing of previously signed/encrypted files. This
signature but leaves its visual appearance intact. option invalidates the signature but leaves its visual
appearance intact. See also --disable-signatures.
Remove security restrictions associated with digitally signed PDF Remove security restrictions associated with digitally signed PDF
files. This may be combined with :qpdf:ref:--decrypt: to allow files. This may be combined with :qpdf:ref:`--decrypt` and
free editing of previously signed/encrypted files. This option :qpdf:ref:`--disable-signatures` to allow free editing of
invalidates the signature but leaves its visual appearance intact. previously signed/encrypted files. This option invalidates the
signature but leaves its visual appearance intact. See also
:qpdf:ref:`--disable-signatures`.
.. qpdf:option:: --disable-signatures
.. help: disable digital signature fields
Remove all digital signature fields from a file. The appearance
of the digital signature, if any, will remain on the page, but
it will no longer be a signature field. See also
--remove-restrictions.
Remove all digital signature fields from a file. The appearance
of the digital signature, if any, will remain on the page, but
it will no longer be a signature field. See also
:qpdf:ref:`--remove-restrictions`.
.. qpdf:option:: --copy-encryption=file .. qpdf:option:: --copy-encryption=file

View File

@ -221,9 +221,16 @@ present on the input file. This option overrides that behavior.
.TP .TP
.B --remove-restrictions \-\- remove security restrictions from input file .B --remove-restrictions \-\- remove security restrictions from input file
Remove restrictions associated with digitally signed PDF files. Remove restrictions associated with digitally signed PDF files.
This may be combined with --decrypt to allow free editing of This may be combined with --decrypt and --disable-signatures to
previously signed/encrypted files. This option invalidates the allow free editing of previously signed/encrypted files. This
signature but leaves its visual appearance intact. option invalidates the signature but leaves its visual
appearance intact. See also --disable-signatures.
.TP
.B --disable-signatures \-\- disable digital signature fields
Remove all digital signature fields from a file. The appearance
of the digital signature, if any, will remain on the page, but
it will no longer be a signature field. See also
--remove-restrictions.
.TP .TP
.B --copy-encryption \-\- copy another file's encryption details .B --copy-encryption \-\- copy another file's encryption details
--copy-encryption=file --copy-encryption=file

View File

@ -71,6 +71,11 @@ Planned changes for future 12.x (subject to change):
shell completion and allows creation of passwords that start shell completion and allows creation of passwords that start
with ``-``. with ``-``.
- Add ``QPDFAcroFormDocumentHelper::disableDigitalSignatures`` and
the :qpdf:ref:`--disable-signatures` command-line argument. This
disables any digital signature fields, leaving their visual
representations intact.
- Build Enhancements: - Build Enhancements:
- The qpdf test suite now passes when qpdf is linked with an - The qpdf test suite now passes when qpdf is linked with an