aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorMasamichi Hosoda <trueroad@trueroad.jp>2019-10-18 12:41:53 +0200
committerJay Berkenbilt <ejb@ql.org>2019-10-22 22:20:21 +0200
commit5a842792b69550cf441d4598feb1daff2fa8c83f (patch)
tree5c0bb58f6028cf48aab01f421a79b68fd92688ed /libqpdf
parentcdc46d78f441526d566c9da195e79b900617bb13 (diff)
downloadqpdf-5a842792b69550cf441d4598feb1daff2fa8c83f.tar.zst
Parse Contents in signature dictionary without encryption
Various PDF digital signing tools do not encrypt /Contents value in signature dictionary. Adobe Acrobat Reader DC can handle a PDF with the /Contents value not encrypted. Write Contents in signature dictionary without encryption Tests ensure that string /Contents are not handled specially when not found in sig dicts.
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/QPDFObjectHandle.cc44
-rw-r--r--libqpdf/QPDFWriter.cc3
2 files changed, 45 insertions, 2 deletions
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index d49976b6..3dacfb8e 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -1779,12 +1779,19 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
bool done = false;
int bad_count = 0;
int good_count = 0;
+ bool b_contents = false;
+ std::vector<std::string> contents_string_stack;
+ contents_string_stack.push_back("");
+ std::vector<qpdf_offset_t> contents_offset_stack;
+ contents_offset_stack.push_back(-1);
while (! done)
{
bool bad = false;
SparseOHArray& olist = olist_stack.back();
parser_state_e state = state_stack.back();
offset = offset_stack.back();
+ std::string& contents_string = contents_string_stack.back();
+ qpdf_offset_t& contents_offset = contents_offset_stack.back();
object = QPDFObjectHandle();
set_offset = false;
@@ -1894,6 +1901,9 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
state_stack.push_back(
(token.getType() == QPDFTokenizer::tt_array_open) ?
st_array : st_dictionary);
+ b_contents = false;
+ contents_string_stack.push_back("");
+ contents_offset_stack.push_back(-1);
}
break;
@@ -1914,7 +1924,19 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
break;
case QPDFTokenizer::tt_name:
- object = newName(token.getValue());
+ {
+ std::string name = token.getValue();
+ object = newName(name);
+
+ if (name == "/Contents")
+ {
+ b_contents = true;
+ }
+ else
+ {
+ b_contents = false;
+ }
+ }
break;
case QPDFTokenizer::tt_word:
@@ -1975,6 +1997,12 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
std::string val = token.getValue();
if (decrypter)
{
+ if (b_contents)
+ {
+ contents_string = val;
+ contents_offset = input->getLastOffset();
+ b_contents = false;
+ }
decrypter->decryptString(val);
}
object = QPDFObjectHandle::newString(val);
@@ -2168,6 +2196,18 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
}
dict[key] = val;
}
+ if (!contents_string.empty() &&
+ dict.count("/Type") &&
+ dict["/Type"].isName() &&
+ dict["/Type"].getName() == "/Sig" &&
+ dict.count("/ByteRange") &&
+ dict.count("/Contents") &&
+ dict["/Contents"].isString())
+ {
+ dict["/Contents"]
+ = QPDFObjectHandle::newString(contents_string);
+ dict["/Contents"].setParsedOffset(contents_offset);
+ }
object = newDictionary(dict);
setObjectDescriptionFromInput(
object, context, object_description, input, offset);
@@ -2190,6 +2230,8 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
{
olist_stack.back().append(object);
}
+ contents_string_stack.pop_back();
+ contents_offset_stack.pop_back();
}
}
diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc
index e7eae5c6..a31f5da9 100644
--- a/libqpdf/QPDFWriter.cc
+++ b/libqpdf/QPDFWriter.cc
@@ -1695,7 +1695,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
{
QTC::TC("qpdf", "QPDFWriter no encryption sig contents");
unparseChild(object.getKey(key), level + 1,
- child_flags | f_hex_string);
+ child_flags | f_hex_string | f_no_encryption);
}
else
{
@@ -1866,6 +1866,7 @@ QPDFWriter::unparseObject(QPDFObjectHandle object, int level,
std::string val;
if (this->m->encrypted &&
(! (flags & f_in_ostream)) &&
+ (! (flags & f_no_encryption)) &&
(! this->m->cur_data_key.empty()))
{
val = object.getStringValue();