Commit 5508f74603d7a816ab67456939bd3ee57676f842

Authored by Jay Berkenbilt
1 parent b997fa53

Allow /P in encryption dictionary to be positive (fixes #382)

Even though this is disallowed by the spec, files like this have been
encountered in the wild.
ChangeLog
  1 +2019-11-09 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * When reading /P from the encryption dictionary, use static_cast
  4 + instead of QIntC to convert the value to a signed integer. The
  5 + value of /P is a bit field, and PDF files have been found in the
  6 + wild where /P is represented as an unsigned integer even though
  7 + the spec states that it is a signed 32-bit value. By using
  8 + static_cast, we allow qpdf to compensate for writers that
  9 + incorrectly represent the correct bit field as an unsigned value.
  10 + Fixes #382.
  11 +
1 12 2019-11-05 Jay Berkenbilt <ejb@ql.org>
2 13  
3 14 * Add support for pluggable crypto providers, enabling multiple
... ...
libqpdf/QPDFPageObjectHelper.cc
... ... @@ -661,6 +661,7 @@ QPDFPageObjectHelper::getFormXObjectForPage(bool handle_transformations)
661 661 return result;
662 662 }
663 663  
  664 +// ABI: name should be std:string const&
664 665 std::string
665 666 QPDFPageObjectHelper::placeFormXObject(
666 667 QPDFObjectHandle fo, std::string name,
... ...
libqpdf/QPDFWriter.cc
... ... @@ -762,7 +762,7 @@ QPDFWriter::copyEncryptionParameters(QPDF&amp; qpdf)
762 762 V,
763 763 encrypt.getKey("/R").getIntValueAsInt(),
764 764 key_len,
765   - encrypt.getKey("/P").getIntValueAsInt(),
  765 + static_cast<int>(encrypt.getKey("/P").getIntValue()),
766 766 encrypt.getKey("/O").getStringValue(),
767 767 encrypt.getKey("/U").getStringValue(),
768 768 OE,
... ...
libqpdf/QPDF_encryption.cc
... ... @@ -877,7 +877,7 @@ QPDF::initializeEncryption()
877 877 int R = encryption_dict.getKey("/R").getIntValueAsInt();
878 878 std::string O = encryption_dict.getKey("/O").getStringValue();
879 879 std::string U = encryption_dict.getKey("/U").getStringValue();
880   - int P = encryption_dict.getKey("/P").getIntValueAsInt();
  880 + int P = static_cast<int>(encryption_dict.getKey("/P").getIntValue());
881 881  
882 882 // If supporting new encryption R/V values, remember to update
883 883 // error message inside this if statement.
... ... @@ -1448,7 +1448,7 @@ QPDF::isEncrypted(int&amp; R, int&amp; P, int&amp; V,
1448 1448 QPDFObjectHandle Pkey = encrypt.getKey("/P");
1449 1449 QPDFObjectHandle Rkey = encrypt.getKey("/R");
1450 1450 QPDFObjectHandle Vkey = encrypt.getKey("/V");
1451   - P = Pkey.getIntValueAsInt();
  1451 + P = static_cast<int>(Pkey.getIntValue());
1452 1452 R = Rkey.getIntValueAsInt();
1453 1453 V = Vkey.getIntValueAsInt();
1454 1454 stream_method = this->m->encp->cf_stream;
... ...
qpdf/qtest/qpdf.test
... ... @@ -721,6 +721,32 @@ foreach my $d (@bug_tests)
721 721 }
722 722 show_ntests();
723 723 # ----------
  724 +$td->notify("--- Positive /P in encryption dictionary ---");
  725 +$n_tests += 4;
  726 +
  727 +# Files have been seen where /P in the encryption dictionary was an
  728 +# unsigned rather than a signed integer. To create
  729 +# encrypted-positive-P.pdf, I temporarily modified QPDFWriter.cc to
  730 +# introduce this error.
  731 +
  732 +$td->runtest("decrypt positive P",
  733 + {$td->COMMAND =>
  734 + "qpdf --decrypt --static-id encrypted-positive-P.pdf a.pdf"},
  735 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  736 +$td->runtest("check output",
  737 + {$td->FILE => "a.pdf"},
  738 + {$td->FILE => "decrypted-positive-P.pdf"});
  739 +$td->runtest("copy encryption positive P",
  740 + {$td->COMMAND =>
  741 + "qpdf --static-id --static-aes-iv" .
  742 + " encrypted-positive-P.pdf a.pdf"},
  743 + {$td->STRING => "", $td->EXIT_STATUS => 0});
  744 +$td->runtest("check output",
  745 + {$td->FILE => "a.pdf"},
  746 + {$td->FILE => "copied-positive-P.pdf"});
  747 +
  748 +show_ntests();
  749 +# ----------
724 750 $td->notify("--- Library version ---");
725 751 $n_tests += 3;
726 752  
... ...
qpdf/qtest/qpdf/copied-positive-P.pdf 0 โ†’ 100644
No preview for this file type
qpdf/qtest/qpdf/decrypted-positive-P.pdf 0 โ†’ 100644
No preview for this file type
qpdf/qtest/qpdf/encrypted-positive-P.pdf 0 โ†’ 100644
No preview for this file type