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 8 2023-12-22 Jay Berkenbilt <ejb@ql.org>
2 9  
3 10 * Generate a more complete qpdf "man page" from the same source as
... ...
include/qpdf/QPDFJob.hh
... ... @@ -557,6 +557,7 @@ class QPDFJob
557 557 bool linearize{false};
558 558 bool decrypt{false};
559 559 bool remove_restrictions{false};
  560 + bool disable_signatures{false};
560 561 int split_pages{0};
561 562 bool progress{false};
562 563 std::function<void(int)> progress_handler{nullptr};
... ...
include/qpdf/auto_job_c_main.hh
... ... @@ -11,6 +11,7 @@ QPDF_DLL Config* checkLinearization();
11 11 QPDF_DLL Config* coalesceContents();
12 12 QPDF_DLL Config* decrypt();
13 13 QPDF_DLL Config* deterministicId();
  14 +QPDF_DLL Config* disableSignatures();
14 15 QPDF_DLL Config* externalizeInlineImages();
15 16 QPDF_DLL Config* filteredStreamData();
16 17 QPDF_DLL Config* flattenRotation();
... ...
job.sums
... ... @@ -4,17 +4,17 @@ generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a
4 4 include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4
5 5 include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42
6 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 8 include/qpdf/auto_job_c_pages.hh b3cc0f21029f6d89efa043dcdbfa183cb59325b6506001c18911614fe8e568ec
9 9 include/qpdf/auto_job_c_uo.hh ae21b69a1efa9333050f4833d465f6daff87e5b38e5106e49bbef5d4132e4ed1
10   -job.yml 4f89fc7b622df897d30d403d8035aa36fc7de8d8c43042c736e0300d904cb05c
  10 +job.yml 3c030ce21138967b8a6768b386c0d3bfab9ef41cafbb6ec52f30a81194a7421d
11 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 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 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 20 manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b
... ...
... ... @@ -104,6 +104,7 @@ options:
104 104 - copy-attachments-from
105 105 - decrypt
106 106 - deterministic-id
  107 + - disable-signatures
107 108 - empty
108 109 - encrypt
109 110 - externalize-inline-images
... ... @@ -319,6 +320,7 @@ json:
319 320 decode-level:
320 321 decrypt:
321 322 deterministic-id:
  323 + disable-signatures:
322 324 static-aes-iv:
323 325 static-id:
324 326 no-original-object-ids:
... ...
libqpdf/QPDFJob.cc
... ... @@ -2129,6 +2129,10 @@ QPDFJob::handleTransformations(QPDF&amp; pdf)
2129 2129 if (m->remove_restrictions) {
2130 2130 pdf.removeSecurityRestrictions();
2131 2131 }
  2132 + if (m->disable_signatures) {
  2133 + make_afdh();
  2134 + afdh->disableDigitalSignatures();
  2135 + }
2132 2136 if (m->externalize_inline_images || (m->optimize_images && (!m->keep_inline_images))) {
2133 2137 for (auto& ph: dh.getAllPages()) {
2134 2138 ph.externalizeInlineImages(m->ii_min_bytes);
... ...
libqpdf/QPDFJob_config.cc
... ... @@ -145,6 +145,13 @@ QPDFJob::Config::deterministicId()
145 145 }
146 146  
147 147 QPDFJob::Config*
  148 +QPDFJob::Config::disableSignatures()
  149 +{
  150 + o.m->disable_signatures = true;
  151 + return this;
  152 +}
  153 +
  154 +QPDFJob::Config*
148 155 QPDFJob::Config::encryptionFilePassword(std::string const& parameter)
149 156 {
150 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 157 present on the input file. This option overrides that behavior.
158 158 )");
159 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 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 173 preserving the input file's encryption. Use --encryption-file-password
168 174 to specify the encryption file's password.
169 175 )");
  176 +}
  177 +static void add_help_3(QPDFArgParser& ap)
  178 +{
170 179 ap.addOptionHelp("--encryption-file-password", "transformation", "supply password for --copy-encryption", R"(--encryption-file-password=password
171 180  
172 181 If the file named in --copy-encryption requires a password, use
173 182 this option to supply the password.
174 183 )");
175   -}
176   -static void add_help_3(QPDFArgParser& ap)
177   -{
178 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 185 editing. This is for editing the PDF code, not the page contents.
180 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 290 value, even if the file uses features that may not be available
285 291 in that version.
286 292 )");
  293 +}
  294 +static void add_help_4(QPDFArgParser& ap)
  295 +{
287 296 ap.addHelpTopic("page-ranges", "page range syntax", R"(A full description of the page range syntax, with examples, can be
288 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 306 :even starts with the second page. These are odd and even pages
298 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 309 ap.addHelpTopic("modification", "change parts of the PDF", R"(Modification options make systematic changes to certain parts of
304 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 481  
476 482 Set the user password of the encrypted file.
477 483 )");
  484 +}
  485 +static void add_help_5(QPDFArgParser& ap)
  486 +{
478 487 ap.addOptionHelp("--owner-password", "encryption", "specify owner password", R"(--owner-password=owner-password
479 488  
480 489 Set the owner password of the encrypted file.
481 490 )");
482   -}
483   -static void add_help_5(QPDFArgParser& ap)
484   -{
485 491 ap.addOptionHelp("--bits", "encryption", "specify encryption key length", R"(--bits={48|128|256}
486 492  
487 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 659 with the page range syntax. The page range may be omitted
654 660 if --repeat is used.
655 661 )");
  662 +}
  663 +static void add_help_6(QPDFArgParser& ap)
  664 +{
656 665 ap.addOptionHelp("--repeat", "overlay-underlay", "overlay/underlay pages to repeat", R"(--repeat=page-range
657 666  
658 667 Specify pages from the overlay/underlay that are repeated after
659 668 "from" pages have been exhausted. See qpdf --help=page-ranges
660 669 for help with the page range syntax.
661 670 )");
662   -}
663   -static void add_help_6(QPDFArgParser& ap)
664   -{
665 671 ap.addHelpTopic("attachments", "work with embedded files", R"(It is possible to list, add, or delete embedded files (also known
666 672 as attachments) and to copy attachments from other files. See help
667 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 776 2: the file is not encrypted
771 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 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 783 aspects of the file, and write information about the file to
775 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 786 PDF file. It merely checks that the PDF file is syntactically
778 787 valid. See also qpdf --help=exit-status.
779 788 )");
780   -}
781   -static void add_help_7(QPDFArgParser& ap)
782   -{
783 789 ap.addOptionHelp("--show-encryption", "inspection", "information about encrypted files", R"(Show document encryption parameters. Also show the document's
784 790 user password if the owner password is given and the file was
785 791 encrypted using older encryption formats that allow user
... ... @@ -860,6 +866,9 @@ This option is repeatable. If given, only specified objects will
860 866 be shown in the "objects" key of the JSON output. Otherwise, all
861 867 objects will be shown.
862 868 )");
  869 +}
  870 +static void add_help_8(QPDFArgParser& ap)
  871 +{
863 872 ap.addOptionHelp("--json-stream-data", "json", "how to handle streams in json output", R"(--json-stream-data={none|inline|file}
864 873  
865 874 When used with --json, this option controls whether streams in
... ... @@ -871,9 +880,6 @@ object number. The prefix can be overridden with
871 880 when --json-output is specified, in which case the default is
872 881 "inline".
873 882 )");
874   -}
875   -static void add_help_8(QPDFArgParser& ap)
876   -{
877 883 ap.addOptionHelp("--json-stream-prefix", "json", "prefix for json stream data files", R"(--json-stream-prefix=file-prefix
878 884  
879 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 43 this->ap.addBare("copy-attachments-from", b(&ArgParser::argCopyAttachmentsFrom));
44 44 this->ap.addBare("decrypt", [this](){c_main->decrypt();});
45 45 this->ap.addBare("deterministic-id", [this](){c_main->deterministicId();});
  46 +this->ap.addBare("disable-signatures", [this](){c_main->disableSignatures();});
46 47 this->ap.addBare("empty", b(&ArgParser::argEmpty));
47 48 this->ap.addBare("encrypt", b(&ArgParser::argEncrypt));
48 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 71 pushKey("deterministicId");
72 72 addBare([this]() { c_main->deterministicId(); });
73 73 popHandler(); // key: deterministicId
  74 +pushKey("disableSignatures");
  75 +addBare([this]() { c_main->disableSignatures(); });
  76 +popHandler(); // key: disableSignatures
74 77 pushKey("staticAesIv");
75 78 addBare([this]() { c_main->staticAesIv(); });
76 79 popHandler(); // key: staticAesIv
... ...
libqpdf/qpdf/auto_job_schema.hh
... ... @@ -16,6 +16,7 @@ static constexpr char const* JOB_SCHEMA_DATA = R&quot;({
16 16 "decodeLevel": "control which streams to uncompress",
17 17 "decrypt": "remove encryption from input file",
18 18 "deterministicId": "generate ID deterministically",
  19 + "disableSignatures": "disable digital signature fields",
19 20 "staticAesIv": "use a fixed AES vector",
20 21 "staticId": "use a fixed document ID",
21 22 "noOriginalObjectIds": "omit original object IDs in qdf",
... ...
manual/cli.rst
... ... @@ -736,22 +736,40 @@ Related Options
736 736 whatever encryption was present on the input file. This
737 737 functionality is not intended to be used for bypassing copyright
738 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 743 .. qpdf:option:: --remove-restrictions
743 744  
744 745 .. help: remove security restrictions from input file
745 746  
746 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 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 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 221 .TP
222 222 .B --remove-restrictions \-\- remove security restrictions from input file
223 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 234 .TP
228 235 .B --copy-encryption \-\- copy another file's encryption details
229 236 --copy-encryption=file
... ...
manual/release-notes.rst
... ... @@ -71,6 +71,11 @@ Planned changes for future 12.x (subject to change):
71 71 shell completion and allows creation of passwords that start
72 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 79 - Build Enhancements:
75 80  
76 81 - The qpdf test suite now passes when qpdf is linked with an
... ...