diff --git a/ChangeLog b/ChangeLog index 5175d7b0..783d7052 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2023-12-23 Jay Berkenbilt + + * 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 * Generate a more complete qpdf "man page" from the same source as diff --git a/include/qpdf/QPDFJob.hh b/include/qpdf/QPDFJob.hh index b9c8ba50..21045019 100644 --- a/include/qpdf/QPDFJob.hh +++ b/include/qpdf/QPDFJob.hh @@ -557,6 +557,7 @@ class QPDFJob bool linearize{false}; bool decrypt{false}; bool remove_restrictions{false}; + bool disable_signatures{false}; int split_pages{0}; bool progress{false}; std::function progress_handler{nullptr}; diff --git a/include/qpdf/auto_job_c_main.hh b/include/qpdf/auto_job_c_main.hh index 6c661404..024f8469 100644 --- a/include/qpdf/auto_job_c_main.hh +++ b/include/qpdf/auto_job_c_main.hh @@ -11,6 +11,7 @@ QPDF_DLL Config* checkLinearization(); QPDF_DLL Config* coalesceContents(); QPDF_DLL Config* decrypt(); QPDF_DLL Config* deterministicId(); +QPDF_DLL Config* disableSignatures(); QPDF_DLL Config* externalizeInlineImages(); QPDF_DLL Config* filteredStreamData(); QPDF_DLL Config* flattenRotation(); diff --git a/job.sums b/job.sums index 58931220..7e86d0fd 100644 --- a/job.sums +++ b/job.sums @@ -4,17 +4,17 @@ generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 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_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1 -job.yml 4f89fc7b622df897d30d403d8035aa36fc7de8d8c43042c736e0300d904cb05c +job.yml 3c030ce21138967b8a6768b386c0d3bfab9ef41cafbb6ec52f30a81194a7421d libqpdf/qpdf/auto_job_decl.hh 9c6f701c29f3f764d620186bed92685a2edf2e4d11e4f4532862c05470cfc4d2 -libqpdf/qpdf/auto_job_help.hh bbd37ac0e8b3e38892a328ca08829d6e71c31ea3ab6c1a91b5f6983018695ef9 -libqpdf/qpdf/auto_job_init.hh b4c2b3724fba61f1206fd3bae81951636852592f67a63ef9539839c2c5995065 +libqpdf/qpdf/auto_job_help.hh 57ea412972105bf302b78b88ae2d6abfc93cae6f5ff99a55e78f860db9354643 +libqpdf/qpdf/auto_job_init.hh 4413804cc784f288245039af053bfe74bc2755e994308220d1939e452011e5a5 libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297 -libqpdf/qpdf/auto_job_json_init.hh f5acb9aa103131cb68dec0e12c4d237a6459bdb49b24773c24f0c2724a462b8f -libqpdf/qpdf/auto_job_schema.hh b53c006fec2e75b1b73588d242d49a32f7d3db820b1541de106c5d4c27fbb4d9 +libqpdf/qpdf/auto_job_json_init.hh 7682e1e3bc465a3818036e1831aaf205478cc2e47ba5abe483d37c037b6bcf56 +libqpdf/qpdf/auto_job_schema.hh 039ee828cf91ece434f0c57706aecc40798e5537308737e01efc8f61eb20685f manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 -manual/cli.rst 7bbeb2f234ca3d095c069f52e4a3c5e42a525b5ef6231955d036a6313eaffcd2 -manual/qpdf.1 745cb32c1772e6d84ef962aca7a439ee045226ae547330778a4a3ba3cd8d25df +manual/cli.rst 97aa745b37ef9824ae4cd159577f65b94935bbc545250c9065ed7d65670c68eb +manual/qpdf.1 e4ffa50a6ed735860a92571d33319a2b5e6aa73cacba1bb73f80bf209be7c040 manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b diff --git a/job.yml b/job.yml index d342e7a2..9849c16d 100644 --- a/job.yml +++ b/job.yml @@ -104,6 +104,7 @@ options: - copy-attachments-from - decrypt - deterministic-id + - disable-signatures - empty - encrypt - externalize-inline-images @@ -319,6 +320,7 @@ json: decode-level: decrypt: deterministic-id: + disable-signatures: static-aes-iv: static-id: no-original-object-ids: diff --git a/libqpdf/QPDFJob.cc b/libqpdf/QPDFJob.cc index ad186e13..7b007c08 100644 --- a/libqpdf/QPDFJob.cc +++ b/libqpdf/QPDFJob.cc @@ -2129,6 +2129,10 @@ QPDFJob::handleTransformations(QPDF& pdf) if (m->remove_restrictions) { pdf.removeSecurityRestrictions(); } + if (m->disable_signatures) { + make_afdh(); + afdh->disableDigitalSignatures(); + } if (m->externalize_inline_images || (m->optimize_images && (!m->keep_inline_images))) { for (auto& ph: dh.getAllPages()) { ph.externalizeInlineImages(m->ii_min_bytes); diff --git a/libqpdf/QPDFJob_config.cc b/libqpdf/QPDFJob_config.cc index 4798ce9b..922d46e5 100644 --- a/libqpdf/QPDFJob_config.cc +++ b/libqpdf/QPDFJob_config.cc @@ -144,6 +144,13 @@ QPDFJob::Config::deterministicId() return this; } +QPDFJob::Config* +QPDFJob::Config::disableSignatures() +{ + o.m->disable_signatures = true; + return this; +} + QPDFJob::Config* QPDFJob::Config::encryptionFilePassword(std::string const& parameter) { diff --git a/libqpdf/qpdf/auto_job_help.hh b/libqpdf/qpdf/auto_job_help.hh index 4a0f3a8f..d342abe3 100644 --- a/libqpdf/qpdf/auto_job_help.hh +++ b/libqpdf/qpdf/auto_job_help.hh @@ -157,9 +157,15 @@ encrypted. Normally qpdf preserves whatever encryption was 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. -This may be combined with --decrypt to allow free editing of -previously signed/encrypted files. This option invalidates the -signature but leaves its visual appearance intact. +This may be combined with --decrypt and --disable-signatures to +allow free editing of previously signed/encrypted files. This +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 @@ -167,14 +173,14 @@ Copy encryption details from the specified file instead of preserving the input file's encryption. Use --encryption-file-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 If the file named in --copy-encryption requires a password, use 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 editing. This is for editing the PDF code, not the page contents. 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 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 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 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 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. )"); +} +static void add_help_5(QPDFArgParser& ap) +{ ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password 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} 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 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 Specify pages from the overlay/underlay that are repeated after "from" pages have been exhausted. See qpdf --help=page-ranges 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 as attachments) and to copy attachments from other files. See help 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 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 aspects of the file, and write information about the file to 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 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 user password if the owner password is given and the file was 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 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} 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 "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 When used with --json-stream-data=file, --json-stream-data=file-prefix diff --git a/libqpdf/qpdf/auto_job_init.hh b/libqpdf/qpdf/auto_job_init.hh index 23b55c7f..5aa280d1 100644 --- a/libqpdf/qpdf/auto_job_init.hh +++ b/libqpdf/qpdf/auto_job_init.hh @@ -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("decrypt", [this](){c_main->decrypt();}); 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("encrypt", b(&ArgParser::argEncrypt)); this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInlineImages();}); diff --git a/libqpdf/qpdf/auto_job_json_init.hh b/libqpdf/qpdf/auto_job_json_init.hh index 135a5159..bce96593 100644 --- a/libqpdf/qpdf/auto_job_json_init.hh +++ b/libqpdf/qpdf/auto_job_json_init.hh @@ -71,6 +71,9 @@ popHandler(); // key: decrypt pushKey("deterministicId"); addBare([this]() { c_main->deterministicId(); }); popHandler(); // key: deterministicId +pushKey("disableSignatures"); +addBare([this]() { c_main->disableSignatures(); }); +popHandler(); // key: disableSignatures pushKey("staticAesIv"); addBare([this]() { c_main->staticAesIv(); }); popHandler(); // key: staticAesIv diff --git a/libqpdf/qpdf/auto_job_schema.hh b/libqpdf/qpdf/auto_job_schema.hh index 84f4cd4a..bd238aca 100644 --- a/libqpdf/qpdf/auto_job_schema.hh +++ b/libqpdf/qpdf/auto_job_schema.hh @@ -16,6 +16,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R"({ "decodeLevel": "control which streams to uncompress", "decrypt": "remove encryption from input file", "deterministicId": "generate ID deterministically", + "disableSignatures": "disable digital signature fields", "staticAesIv": "use a fixed AES vector", "staticId": "use a fixed document ID", "noOriginalObjectIds": "omit original object IDs in qdf", diff --git a/manual/cli.rst b/manual/cli.rst index 93131542..db32c515 100644 --- a/manual/cli.rst +++ b/manual/cli.rst @@ -736,22 +736,40 @@ Related Options whatever encryption was present on the input file. This functionality is not intended to be used for bypassing copyright restrictions or other restrictions placed on files by their - producers. See also :qpdf:ref:`--copy-encryption` and - :qpdf:ref:`--remove-restrictions`. + producers. See also :qpdf:ref:`--copy-encryption`, + :qpdf:ref:`--remove-restrictions`, and + :qpdf:ref:`--disable-signatures`. .. qpdf:option:: --remove-restrictions .. help: remove security restrictions from input file Remove restrictions associated with digitally signed PDF files. - This may be combined with --decrypt to allow free editing of - previously signed/encrypted files. This option invalidates the - signature but leaves its visual appearance intact. + This may be combined with --decrypt and --disable-signatures to + allow free editing of previously signed/encrypted files. This + option invalidates the signature but leaves its visual + appearance intact. See also --disable-signatures. Remove security restrictions associated with digitally signed PDF - files. This may be combined with :qpdf:ref:--decrypt: to allow - free editing of previously signed/encrypted files. This option - invalidates the signature but leaves its visual appearance intact. + files. This may be combined with :qpdf:ref:`--decrypt` and + :qpdf:ref:`--disable-signatures` to allow free editing of + 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 diff --git a/manual/qpdf.1 b/manual/qpdf.1 index b8bf5033..b8376877 100644 --- a/manual/qpdf.1 +++ b/manual/qpdf.1 @@ -221,9 +221,16 @@ present on the input file. This option overrides that behavior. .TP .B --remove-restrictions \-\- remove security restrictions from input file Remove restrictions associated with digitally signed PDF files. -This may be combined with --decrypt to allow free editing of -previously signed/encrypted files. This option invalidates the -signature but leaves its visual appearance intact. +This may be combined with --decrypt and --disable-signatures to +allow free editing of previously signed/encrypted files. This +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 .B --copy-encryption \-\- copy another file's encryption details --copy-encryption=file diff --git a/manual/release-notes.rst b/manual/release-notes.rst index 443a4b01..96bebb76 100644 --- a/manual/release-notes.rst +++ b/manual/release-notes.rst @@ -71,6 +71,11 @@ Planned changes for future 12.x (subject to change): shell completion and allows creation of passwords that start 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: - The qpdf test suite now passes when qpdf is linked with an