Subject: | decode_qp destroys PDF Signatures for no reason |
Date: | Thu, 7 Feb 2019 21:52:41 +0100 |
To: | bug-MIME-Base64 [...] rt.cpan.org |
From: | Sebastian Rose <chipsbarrier [...] gmail.com> |
Hello MIME::Base64 maintainers,
I use MIME::Decoder::QuotedPrint and other modules that rely on the XS
Code in the MIME::Base64 distribution.
Unfortunately, the decode_qp destroys signatures in PDF files created on
UNIXoids and signed and sent from a windows box using Outlook. Outlook
decides to send some PDFs quoted-printable encoded (...) and qp-encodes
\n-only linefeeds only as it considers \r\n the cannonical MIME LF.
The line distructing the signatures (and earning us nothing in MIME-mail
environments) is the insertion of linefeeds NOT found in the encoded
document (plus NOT being MIME-message LFs). This happens in Base64.xs,
line 459 ff:
else if (*str == '\r' && (str + 1) < end && str[1] == '\n') {
str++;
}
else if (*str == '\n') {
whitespace = 0;
*r++ = *str++;
}
It says:
- skip \r
- consider \n a whitspace.
It should say:
- If no qp-encoded LF was found before end of line, then insert the one
found in the user data.
The attached dirty hack fixes the problem for me. Its a little Perl
project and features a few simple tests.
perl Makefile.PL
make
make test
prove -vrc t
It is sure not the best Fix one could think of. But I urgently needed to
fix the LF problem in Base64.xs' encode_qp to stop it from destroying
customer data - and it seems to work perfectly well so far.
As you can see in the attached lib/MIME/QuotedPrintMsCompat.pm, I overwrite
*MIME::Decoder::QutotedPrint::decode_it()*, too (as I use
MIME::Parser::Filer). Not sure if that is necessary or even advisable.
Here's a diff between my proposal and the original, cut down to the
decode_qp function in Base64.xs:
--- ext/decode_qp-only.xs 2019-02-07 20:33:07.384921636 +0100
+++ ext/decode_qp_ms_compat.xs 2019-02-07 21:43:22.359144067 +0100
@@ -1,6 +1,5 @@
-
SV*
-decode_qp(sv)
+decode_qp_ms_compat(sv)
SV* sv
PROTOTYPE: $
@@ -10,6 +9,8 @@
char const* end = str + len;
char *r;
char *whitespace = 0;
+ /* True, if we indeed did encounter an encoded LF at and of line: */
+ int rfc_nl = 0;
CODE:
RETVAL = newSV(len ? len : 1);
@@ -22,13 +23,33 @@
str++;
}
else if (*str == '\r' && (str + 1) < end && str[1] == '\n') {
- str++;
+ whitespace = 0;
+ if( rfc_nl ) {
+ /* We've already found an encoded LF. Hence, we skip the
+ * original LF found in the document. */
+ rfc_nl = 0;
+ str += 2;
+ }
+ else {
+ /* Otherwise, add the original LF found in the document: */
+ *r++ = *str++;
+ *r++ = *str++;
+ }
}
else if (*str == '\n') {
whitespace = 0;
+ if( rfc_nl ) {
+ /* We've already found encoded LF(s) */
+ str++;
+ rfc_nl = 0;
+ }
+ else {
+ /* NOTE: Not canonical LF in MIME-messages! */
*r++ = *str++;
}
+ }
else {
+ rfc_nl = 0;
if (whitespace) {
while (whitespace < str) {
*r++ = *whitespace++;
@@ -43,6 +64,10 @@
buf[1] = *str++;
buf[2] = '\0';
*r++ = (char)strtol(buf, 0, 16);
+ if( '0' == buf[0] && ('A' == buf[1] || 'D' == buf[1])
) {
+ /* Encoded LF at hand. */
+ rfc_nl = 1;
+ }
}
else {
/* look for soft line break */
Best regards,
- Sebastian
Message body not shown because it is not plain text.