Commit 909a0b3f3a0fddfab6abd1f0775cdd50f1406be6

Authored by Jay Berkenbilt
1 parent 3d33a3a1

Implement --disable-signatures (fixes #1015)

ChangeLog
  1 +2023-12-23 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add QPDFAcroFormDocumentHelper::disableDigitalSignatures and the
  4 + --disable-signatures command-line argument. This disables any
  5 + digital signature fields, leaving their visual representations
  6 + intact.
  7 +
1 2023-12-22 Jay Berkenbilt <ejb@ql.org> 8 2023-12-22 Jay Berkenbilt <ejb@ql.org>
2 9
3 * Generate a more complete qpdf "man page" from the same source as 10 * Generate a more complete qpdf "man page" from the same source as
include/qpdf/QPDFJob.hh
@@ -557,6 +557,7 @@ class QPDFJob @@ -557,6 +557,7 @@ class QPDFJob
557 bool linearize{false}; 557 bool linearize{false};
558 bool decrypt{false}; 558 bool decrypt{false};
559 bool remove_restrictions{false}; 559 bool remove_restrictions{false};
  560 + bool disable_signatures{false};
560 int split_pages{0}; 561 int split_pages{0};
561 bool progress{false}; 562 bool progress{false};
562 std::function<void(int)> progress_handler{nullptr}; 563 std::function<void(int)> progress_handler{nullptr};
include/qpdf/auto_job_c_main.hh
@@ -11,6 +11,7 @@ QPDF_DLL Config* checkLinearization(); @@ -11,6 +11,7 @@ QPDF_DLL Config* checkLinearization();
11 QPDF_DLL Config* coalesceContents(); 11 QPDF_DLL Config* coalesceContents();
12 QPDF_DLL Config* decrypt(); 12 QPDF_DLL Config* decrypt();
13 QPDF_DLL Config* deterministicId(); 13 QPDF_DLL Config* deterministicId();
  14 +QPDF_DLL Config* disableSignatures();
14 QPDF_DLL Config* externalizeInlineImages(); 15 QPDF_DLL Config* externalizeInlineImages();
15 QPDF_DLL Config* filteredStreamData(); 16 QPDF_DLL Config* filteredStreamData();
16 QPDF_DLL Config* flattenRotation(); 17 QPDF_DLL Config* flattenRotation();
job.sums
@@ -4,17 +4,17 @@ generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a @@ -4,17 +4,17 @@ generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a
4 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 4 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4
5 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 5 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42
6 include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5 6 include/qpdf/auto_job_c_enc.hh 28446f3c32153a52afa239ea40503e6cc8ac2c026813526a349e0cd4ae17ddd5
7 -include/qpdf/auto_job_c_main.hh dbfc221d1533120d1aa9c361d8d2483dea5fcb1c0fd95144d98d305e64ed32a6 7 +include/qpdf/auto_job_c_main.hh 36b5ff48ae0dca67415efececa4470cda45364b10d0905e7de9971a2af1795ea
8 include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec 8 include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec
9 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1 9 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1
10 -job.yml 4f89fc7b622df897d30d403d8035aa36fc7de8d8c43042c736e0300d904cb05c 10 +job.yml 3c030ce21138967b8a6768b386c0d3bfab9ef41cafbb6ec52f30a81194a7421d
11 libqpdf/qpdf/auto_job_decl.hh 9c6f701c29f3f764d620186bed92685a2edf2e4d11e4f4532862c05470cfc4d2 11 libqpdf/qpdf/auto_job_decl.hh 9c6f701c29f3f764d620186bed92685a2edf2e4d11e4f4532862c05470cfc4d2
12 -libqpdf/qpdf/auto_job_help.hh bbd37ac0e8b3e38892a328ca08829d6e71c31ea3ab6c1a91b5f6983018695ef9  
13 -libqpdf/qpdf/auto_job_init.hh b4c2b3724fba61f1206fd3bae81951636852592f67a63ef9539839c2c5995065 12 +libqpdf/qpdf/auto_job_help.hh 57ea412972105bf302b78b88ae2d6abfc93cae6f5ff99a55e78f860db9354643
  13 +libqpdf/qpdf/auto_job_init.hh 4413804cc784f288245039af053bfe74bc2755e994308220d1939e452011e5a5
14 libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297 14 libqpdf/qpdf/auto_job_json_decl.hh 06caa46eaf71db8a50c046f91866baa8087745a9474319fb7c86d92634cc8297
15 -libqpdf/qpdf/auto_job_json_init.hh f5acb9aa103131cb68dec0e12c4d237a6459bdb49b24773c24f0c2724a462b8f  
16 -libqpdf/qpdf/auto_job_schema.hh b53c006fec2e75b1b73588d242d49a32f7d3db820b1541de106c5d4c27fbb4d9 15 +libqpdf/qpdf/auto_job_json_init.hh 7682e1e3bc465a3818036e1831aaf205478cc2e47ba5abe483d37c037b6bcf56
  16 +libqpdf/qpdf/auto_job_schema.hh 039ee828cf91ece434f0c57706aecc40798e5537308737e01efc8f61eb20685f
17 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 17 manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580
18 -manual/cli.rst 7bbeb2f234ca3d095c069f52e4a3c5e42a525b5ef6231955d036a6313eaffcd2  
19 -manual/qpdf.1 745cb32c1772e6d84ef962aca7a439ee045226ae547330778a4a3ba3cd8d25df 18 +manual/cli.rst 97aa745b37ef9824ae4cd159577f65b94935bbc545250c9065ed7d65670c68eb
  19 +manual/qpdf.1 e4ffa50a6ed735860a92571d33319a2b5e6aa73cacba1bb73f80bf209be7c040
20 manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b 20 manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b
@@ -104,6 +104,7 @@ options: @@ -104,6 +104,7 @@ options:
104 - copy-attachments-from 104 - copy-attachments-from
105 - decrypt 105 - decrypt
106 - deterministic-id 106 - deterministic-id
  107 + - disable-signatures
107 - empty 108 - empty
108 - encrypt 109 - encrypt
109 - externalize-inline-images 110 - externalize-inline-images
@@ -319,6 +320,7 @@ json: @@ -319,6 +320,7 @@ json:
319 decode-level: 320 decode-level:
320 decrypt: 321 decrypt:
321 deterministic-id: 322 deterministic-id:
  323 + disable-signatures:
322 static-aes-iv: 324 static-aes-iv:
323 static-id: 325 static-id:
324 no-original-object-ids: 326 no-original-object-ids:
libqpdf/QPDFJob.cc
@@ -2129,6 +2129,10 @@ QPDFJob::handleTransformations(QPDF&amp; pdf) @@ -2129,6 +2129,10 @@ QPDFJob::handleTransformations(QPDF&amp; pdf)
2129 if (m->remove_restrictions) { 2129 if (m->remove_restrictions) {
2130 pdf.removeSecurityRestrictions(); 2130 pdf.removeSecurityRestrictions();
2131 } 2131 }
  2132 + if (m->disable_signatures) {
  2133 + make_afdh();
  2134 + afdh->disableDigitalSignatures();
  2135 + }
2132 if (m->externalize_inline_images || (m->optimize_images && (!m->keep_inline_images))) { 2136 if (m->externalize_inline_images || (m->optimize_images && (!m->keep_inline_images))) {
2133 for (auto& ph: dh.getAllPages()) { 2137 for (auto& ph: dh.getAllPages()) {
2134 ph.externalizeInlineImages(m->ii_min_bytes); 2138 ph.externalizeInlineImages(m->ii_min_bytes);
libqpdf/QPDFJob_config.cc
@@ -145,6 +145,13 @@ QPDFJob::Config::deterministicId() @@ -145,6 +145,13 @@ QPDFJob::Config::deterministicId()
145 } 145 }
146 146
147 QPDFJob::Config* 147 QPDFJob::Config*
  148 +QPDFJob::Config::disableSignatures()
  149 +{
  150 + o.m->disable_signatures = true;
  151 + return this;
  152 +}
  153 +
  154 +QPDFJob::Config*
148 QPDFJob::Config::encryptionFilePassword(std::string const& parameter) 155 QPDFJob::Config::encryptionFilePassword(std::string const& parameter)
149 { 156 {
150 o.m->encryption_file_password = QUtil::make_shared_cstr(parameter); 157 o.m->encryption_file_password = QUtil::make_shared_cstr(parameter);
libqpdf/qpdf/auto_job_help.hh
@@ -157,9 +157,15 @@ encrypted. Normally qpdf preserves whatever encryption was @@ -157,9 +157,15 @@ encrypted. Normally qpdf preserves whatever encryption was
157 present on the input file. This option overrides that behavior. 157 present on the input file. This option overrides that behavior.
158 )"); 158 )");
159 ap.addOptionHelp("--remove-restrictions", "transformation", "remove security restrictions from input file", R"(Remove restrictions associated with digitally signed PDF files. 159 ap.addOptionHelp("--remove-restrictions", "transformation", "remove security restrictions from input file", R"(Remove restrictions associated with digitally signed PDF files.
160 -This may be combined with --decrypt to allow free editing of  
161 -previously signed/encrypted files. This option invalidates the  
162 -signature but leaves its visual appearance intact. 160 +This may be combined with --decrypt and --disable-signatures to
  161 +allow free editing of previously signed/encrypted files. This
  162 +option invalidates the signature but leaves its visual
  163 +appearance intact. See also --disable-signatures.
  164 +)");
  165 +ap.addOptionHelp("--disable-signatures", "transformation", "disable digital signature fields", R"(Remove all digital signature fields from a file. The appearance
  166 +of the digital signature, if any, will remain on the page, but
  167 +it will no longer be a signature field. See also
  168 +--remove-restrictions.
163 )"); 169 )");
164 ap.addOptionHelp("--copy-encryption", "transformation", "copy another file's encryption details", R"(--copy-encryption=file 170 ap.addOptionHelp("--copy-encryption", "transformation", "copy another file's encryption details", R"(--copy-encryption=file
165 171
@@ -167,14 +173,14 @@ Copy encryption details from the specified file instead of @@ -167,14 +173,14 @@ Copy encryption details from the specified file instead of
167 preserving the input file's encryption. Use --encryption-file-password 173 preserving the input file's encryption. Use --encryption-file-password
168 to specify the encryption file's password. 174 to specify the encryption file's password.
169 )"); 175 )");
  176 +}
  177 +static void add_help_3(QPDFArgParser& ap)
  178 +{
170 ap.addOptionHelp("--encryption-file-password", "transformation", "supply password for --copy-encryption", R"(--encryption-file-password=password 179 ap.addOptionHelp("--encryption-file-password", "transformation", "supply password for --copy-encryption", R"(--encryption-file-password=password
171 180
172 If the file named in --copy-encryption requires a password, use 181 If the file named in --copy-encryption requires a password, use
173 this option to supply the password. 182 this option to supply the password.
174 )"); 183 )");
175 -}  
176 -static void add_help_3(QPDFArgParser& ap)  
177 -{  
178 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 184 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
179 editing. This is for editing the PDF code, not the page contents. 185 editing. This is for editing the PDF code, not the page contents.
180 All streams that can be uncompressed are uncompressed, and 186 All streams that can be uncompressed are uncompressed, and
@@ -284,6 +290,9 @@ Force the output PDF file&#39;s PDF version header to be the specified @@ -284,6 +290,9 @@ Force the output PDF file&#39;s PDF version header to be the specified
284 value, even if the file uses features that may not be available 290 value, even if the file uses features that may not be available
285 in that version. 291 in that version.
286 )"); 292 )");
  293 +}
  294 +static void add_help_4(QPDFArgParser& ap)
  295 +{
287 ap.addHelpTopic("page-ranges", "page range syntax", R"(A full description of the page range syntax, with examples, can be 296 ap.addHelpTopic("page-ranges", "page range syntax", R"(A full description of the page range syntax, with examples, can be
288 found in the manual. Summary: 297 found in the manual. Summary:
289 298
@@ -297,9 +306,6 @@ resulting set of pages, where :odd starts with the first page and @@ -297,9 +306,6 @@ resulting set of pages, where :odd starts with the first page and
297 :even starts with the second page. These are odd and even pages 306 :even starts with the second page. These are odd and even pages
298 from the resulting set, not based on the original page numbers. 307 from the resulting set, not based on the original page numbers.
299 )"); 308 )");
300 -}  
301 -static void add_help_4(QPDFArgParser& ap)  
302 -{  
303 ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of 309 ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of
304 the PDF, causing the PDF to render differently from the original. 310 the PDF, causing the PDF to render differently from the original.
305 )"); 311 )");
@@ -475,13 +481,13 @@ ap.addOptionHelp(&quot;--user-password&quot;, &quot;encryption&quot;, &quot;specify user password&quot;, R&quot;(-- @@ -475,13 +481,13 @@ ap.addOptionHelp(&quot;--user-password&quot;, &quot;encryption&quot;, &quot;specify user password&quot;, R&quot;(--
475 481
476 Set the user password of the encrypted file. 482 Set the user password of the encrypted file.
477 )"); 483 )");
  484 +}
  485 +static void add_help_5(QPDFArgParser& ap)
  486 +{
478 ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password 487 ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password
479 488
480 Set the owner password of the encrypted file. 489 Set the owner password of the encrypted file.
481 )"); 490 )");
482 -}  
483 -static void add_help_5(QPDFArgParser& ap)  
484 -{  
485 ap.addOptionHelp("--bits", "encryption", "specify encryption key length", R"(--bits={48|128|256} 491 ap.addOptionHelp("--bits", "encryption", "specify encryption key length", R"(--bits={48|128|256}
486 492
487 Specify the encryption key length. For best security, always use 493 Specify the encryption key length. For best security, always use
@@ -653,15 +659,15 @@ the destination pages. See qpdf --help=page-ranges for help @@ -653,15 +659,15 @@ the destination pages. See qpdf --help=page-ranges for help
653 with the page range syntax. The page range may be omitted 659 with the page range syntax. The page range may be omitted
654 if --repeat is used. 660 if --repeat is used.
655 )"); 661 )");
  662 +}
  663 +static void add_help_6(QPDFArgParser& ap)
  664 +{
656 ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range 665 ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range
657 666
658 Specify pages from the overlay/underlay that are repeated after 667 Specify pages from the overlay/underlay that are repeated after
659 "from" pages have been exhausted. See qpdf --help=page-ranges 668 "from" pages have been exhausted. See qpdf --help=page-ranges
660 for help with the page range syntax. 669 for help with the page range syntax.
661 )"); 670 )");
662 -}  
663 -static void add_help_6(QPDFArgParser& ap)  
664 -{  
665 ap.addHelpTopic("attachments", "work with embedded files", R"(It is possible to list, add, or delete embedded files (also known 671 ap.addHelpTopic("attachments", "work with embedded files", R"(It is possible to list, add, or delete embedded files (also known
666 as attachments) and to copy attachments from other files. See help 672 as attachments) and to copy attachments from other files. See help
667 on individual options for details. Run qpdf --help=add-attachment 673 on individual options for details. Run qpdf --help=add-attachment
@@ -770,6 +776,9 @@ ap.addOptionHelp(&quot;--requires-password&quot;, &quot;inspection&quot;, &quot;silently test a file&#39;s pa @@ -770,6 +776,9 @@ ap.addOptionHelp(&quot;--requires-password&quot;, &quot;inspection&quot;, &quot;silently test a file&#39;s pa
770 2: the file is not encrypted 776 2: the file is not encrypted
771 3: the file is encrypted, and correct password (if any) has been supplied 777 3: the file is encrypted, and correct password (if any) has been supplied
772 )"); 778 )");
  779 +}
  780 +static void add_help_7(QPDFArgParser& ap)
  781 +{
773 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 782 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
774 aspects of the file, and write information about the file to 783 aspects of the file, and write information about the file to
775 standard output. Note that qpdf does not perform any validation 784 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 @@ -777,9 +786,6 @@ of the actual PDF page content or semantic correctness of the
777 PDF file. It merely checks that the PDF file is syntactically 786 PDF file. It merely checks that the PDF file is syntactically
778 valid. See also qpdf --help=exit-status. 787 valid. See also qpdf --help=exit-status.
779 )"); 788 )");
780 -}  
781 -static void add_help_7(QPDFArgParser& ap)  
782 -{  
783 ap.addOptionHelp("--show-encryption", "inspection", "information about encrypted files", R"(Show document encryption parameters. Also show the document's 789 ap.addOptionHelp("--show-encryption", "inspection", "information about encrypted files", R"(Show document encryption parameters. Also show the document's
784 user password if the owner password is given and the file was 790 user password if the owner password is given and the file was
785 encrypted using older encryption formats that allow user 791 encrypted using older encryption formats that allow user
@@ -860,6 +866,9 @@ This option is repeatable. If given, only specified objects will @@ -860,6 +866,9 @@ This option is repeatable. If given, only specified objects will
860 be shown in the "objects" key of the JSON output. Otherwise, all 866 be shown in the "objects" key of the JSON output. Otherwise, all
861 objects will be shown. 867 objects will be shown.
862 )"); 868 )");
  869 +}
  870 +static void add_help_8(QPDFArgParser& ap)
  871 +{
863 ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file} 872 ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file}
864 873
865 When used with --json, this option controls whether streams in 874 When used with --json, this option controls whether streams in
@@ -871,9 +880,6 @@ object number. The prefix can be overridden with @@ -871,9 +880,6 @@ object number. The prefix can be overridden with
871 when --json-output is specified, in which case the default is 880 when --json-output is specified, in which case the default is
872 "inline". 881 "inline".
873 )"); 882 )");
874 -}  
875 -static void add_help_8(QPDFArgParser& ap)  
876 -{  
877 ap.addOptionHelp("--json-stream-prefix", "json", "prefix for json stream data files", R"(--json-stream-prefix=file-prefix 883 ap.addOptionHelp("--json-stream-prefix", "json", "prefix for json stream data files", R"(--json-stream-prefix=file-prefix
878 884
879 When used with --json-stream-data=file, --json-stream-data=file-prefix 885 When used with --json-stream-data=file, --json-stream-data=file-prefix
libqpdf/qpdf/auto_job_init.hh
@@ -43,6 +43,7 @@ this-&gt;ap.addBare(&quot;coalesce-contents&quot;, [this](){c_main-&gt;coalesceContents();}); @@ -43,6 +43,7 @@ this-&gt;ap.addBare(&quot;coalesce-contents&quot;, [this](){c_main-&gt;coalesceContents();});
43 this->ap.addBare("copy-attachments-from", b(&ArgParser::argCopyAttachmentsFrom)); 43 this->ap.addBare("copy-attachments-from", b(&ArgParser::argCopyAttachmentsFrom));
44 this->ap.addBare("decrypt", [this](){c_main->decrypt();}); 44 this->ap.addBare("decrypt", [this](){c_main->decrypt();});
45 this->ap.addBare("deterministic-id", [this](){c_main->deterministicId();}); 45 this->ap.addBare("deterministic-id", [this](){c_main->deterministicId();});
  46 +this->ap.addBare("disable-signatures", [this](){c_main->disableSignatures();});
46 this->ap.addBare("empty", b(&ArgParser::argEmpty)); 47 this->ap.addBare("empty", b(&ArgParser::argEmpty));
47 this->ap.addBare("encrypt", b(&ArgParser::argEncrypt)); 48 this->ap.addBare("encrypt", b(&ArgParser::argEncrypt));
48 this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInlineImages();}); 49 this->ap.addBare("externalize-inline-images", [this](){c_main->externalizeInlineImages();});
libqpdf/qpdf/auto_job_json_init.hh
@@ -71,6 +71,9 @@ popHandler(); // key: decrypt @@ -71,6 +71,9 @@ popHandler(); // key: decrypt
71 pushKey("deterministicId"); 71 pushKey("deterministicId");
72 addBare([this]() { c_main->deterministicId(); }); 72 addBare([this]() { c_main->deterministicId(); });
73 popHandler(); // key: deterministicId 73 popHandler(); // key: deterministicId
  74 +pushKey("disableSignatures");
  75 +addBare([this]() { c_main->disableSignatures(); });
  76 +popHandler(); // key: disableSignatures
74 pushKey("staticAesIv"); 77 pushKey("staticAesIv");
75 addBare([this]() { c_main->staticAesIv(); }); 78 addBare([this]() { c_main->staticAesIv(); });
76 popHandler(); // key: staticAesIv 79 popHandler(); // key: staticAesIv
libqpdf/qpdf/auto_job_schema.hh
@@ -16,6 +16,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R&quot;({ @@ -16,6 +16,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R&quot;({
16 "decodeLevel": "control which streams to uncompress", 16 "decodeLevel": "control which streams to uncompress",
17 "decrypt": "remove encryption from input file", 17 "decrypt": "remove encryption from input file",
18 "deterministicId": "generate ID deterministically", 18 "deterministicId": "generate ID deterministically",
  19 + "disableSignatures": "disable digital signature fields",
19 "staticAesIv": "use a fixed AES vector", 20 "staticAesIv": "use a fixed AES vector",
20 "staticId": "use a fixed document ID", 21 "staticId": "use a fixed document ID",
21 "noOriginalObjectIds": "omit original object IDs in qdf", 22 "noOriginalObjectIds": "omit original object IDs in qdf",
manual/cli.rst
@@ -736,22 +736,40 @@ Related Options @@ -736,22 +736,40 @@ Related Options
736 whatever encryption was present on the input file. This 736 whatever encryption was present on the input file. This
737 functionality is not intended to be used for bypassing copyright 737 functionality is not intended to be used for bypassing copyright
738 restrictions or other restrictions placed on files by their 738 restrictions or other restrictions placed on files by their
739 - producers. See also :qpdf:ref:`--copy-encryption` and  
740 - :qpdf:ref:`--remove-restrictions`. 739 + producers. See also :qpdf:ref:`--copy-encryption`,
  740 + :qpdf:ref:`--remove-restrictions`, and
  741 + :qpdf:ref:`--disable-signatures`.
741 742
742 .. qpdf:option:: --remove-restrictions 743 .. qpdf:option:: --remove-restrictions
743 744
744 .. help: remove security restrictions from input file 745 .. help: remove security restrictions from input file
745 746
746 Remove restrictions associated with digitally signed PDF files. 747 Remove restrictions associated with digitally signed PDF files.
747 - This may be combined with --decrypt to allow free editing of  
748 - previously signed/encrypted files. This option invalidates the  
749 - signature but leaves its visual appearance intact. 748 + This may be combined with --decrypt and --disable-signatures to
  749 + allow free editing of previously signed/encrypted files. This
  750 + option invalidates the signature but leaves its visual
  751 + appearance intact. See also --disable-signatures.
750 752
751 Remove security restrictions associated with digitally signed PDF 753 Remove security restrictions associated with digitally signed PDF
752 - files. This may be combined with :qpdf:ref:--decrypt: to allow  
753 - free editing of previously signed/encrypted files. This option  
754 - invalidates the signature but leaves its visual appearance intact. 754 + files. This may be combined with :qpdf:ref:`--decrypt` and
  755 + :qpdf:ref:`--disable-signatures` to allow free editing of
  756 + previously signed/encrypted files. This option invalidates the
  757 + signature but leaves its visual appearance intact. See also
  758 + :qpdf:ref:`--disable-signatures`.
  759 +
  760 +.. qpdf:option:: --disable-signatures
  761 +
  762 + .. help: disable digital signature fields
  763 +
  764 + Remove all digital signature fields from a file. The appearance
  765 + of the digital signature, if any, will remain on the page, but
  766 + it will no longer be a signature field. See also
  767 + --remove-restrictions.
  768 +
  769 + Remove all digital signature fields from a file. The appearance
  770 + of the digital signature, if any, will remain on the page, but
  771 + it will no longer be a signature field. See also
  772 + :qpdf:ref:`--remove-restrictions`.
755 773
756 .. qpdf:option:: --copy-encryption=file 774 .. qpdf:option:: --copy-encryption=file
757 775
manual/qpdf.1
@@ -221,9 +221,16 @@ present on the input file. This option overrides that behavior. @@ -221,9 +221,16 @@ present on the input file. This option overrides that behavior.
221 .TP 221 .TP
222 .B --remove-restrictions \-\- remove security restrictions from input file 222 .B --remove-restrictions \-\- remove security restrictions from input file
223 Remove restrictions associated with digitally signed PDF files. 223 Remove restrictions associated with digitally signed PDF files.
224 -This may be combined with --decrypt to allow free editing of  
225 -previously signed/encrypted files. This option invalidates the  
226 -signature but leaves its visual appearance intact. 224 +This may be combined with --decrypt and --disable-signatures to
  225 +allow free editing of previously signed/encrypted files. This
  226 +option invalidates the signature but leaves its visual
  227 +appearance intact. See also --disable-signatures.
  228 +.TP
  229 +.B --disable-signatures \-\- disable digital signature fields
  230 +Remove all digital signature fields from a file. The appearance
  231 +of the digital signature, if any, will remain on the page, but
  232 +it will no longer be a signature field. See also
  233 +--remove-restrictions.
227 .TP 234 .TP
228 .B --copy-encryption \-\- copy another file's encryption details 235 .B --copy-encryption \-\- copy another file's encryption details
229 --copy-encryption=file 236 --copy-encryption=file
manual/release-notes.rst
@@ -71,6 +71,11 @@ Planned changes for future 12.x (subject to change): @@ -71,6 +71,11 @@ Planned changes for future 12.x (subject to change):
71 shell completion and allows creation of passwords that start 71 shell completion and allows creation of passwords that start
72 with ``-``. 72 with ``-``.
73 73
  74 + - Add ``QPDFAcroFormDocumentHelper::disableDigitalSignatures`` and
  75 + the :qpdf:ref:`--disable-signatures` command-line argument. This
  76 + disables any digital signature fields, leaving their visual
  77 + representations intact.
  78 +
74 - Build Enhancements: 79 - Build Enhancements:
75 80
76 - The qpdf test suite now passes when qpdf is linked with an 81 - The qpdf test suite now passes when qpdf is linked with an