vcl/source/gdi/pdfwriter_impl.cxx | 260 +++++++++++++++++++++++++++++++++++--- 1 file changed, 243 insertions(+), 17 deletions(-)
New commits: commit 7d7c2ab1dffa82cfc0e2d6b15702d965b8b0245b Author: Tor Lillqvist <t...@collabora.com> Date: Mon Feb 23 15:27:01 2015 +0200 tdf#84881: Call NSS_CMSSignerInfo_AddSigningTime() only if not using a TSA Something is still wrong, Adobe Reader still says the PDF is signed with the local machine's timestamp, though. Change-Id: Ic9ed3190901025be48e1de191df976e1aa454822 diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 3cc60d0..3ac6de7 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6987,16 +6987,15 @@ bool PDFWriterImpl::finalizeSignature() return false; } } - - if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) + else if (NSS_CMSSignerInfo_AddSigningTime(cms_signer, PR_Now()) != SECSuccess) { - SAL_WARN("vcl.pdfwriter", "PDF signing: can't include cert chain."); + SAL_WARN("vcl.pdfwriter", "PDF signing: can't add signing time."); return false; } - if (NSS_CMSSignerInfo_AddSigningTime(cms_signer, PR_Now()) != SECSuccess) + if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) { - SAL_WARN("vcl.pdfwriter", "PDF signing: can't add signing time."); + SAL_WARN("vcl.pdfwriter", "PDF signing: can't include cert chain."); return false; } commit d1132ff3895aa67ed662446ef6f43612124455ae Author: Tor Lillqvist <t...@collabora.com> Date: Mon Feb 23 14:55:07 2015 +0200 tdf#84881: Actually check the status of the time stamp response Change-Id: If8d64b1e03c8318cd3329cd258131fddeb86fa7b diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 9d14f13..3cc60d0 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6941,6 +6941,13 @@ bool PDFWriterImpl::finalizeSignature() SAL_INFO("vcl.pdfwriter", "TimeStampResp received and decoded, status=" << PKIStatusInfoToString(response.status)); + if (response.status.status.len != 1 || + (response.status.status.data[0] != 0 && response.status.status.data[0] != 1)) + { + SAL_WARN("vcl.pdfwriter", "PDF signing: Timestamp request was not granted"); + return false; + } + NSSCMSAttribute timestamp; timestamp.type.type = siBuffer; commit e075fec6e18b24f4037c11f015e870a470fa8ef8 Author: Tor Lillqvist <t...@collabora.com> Date: Mon Feb 23 14:51:06 2015 +0200 Copy SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() here Despite being declared in a public header, they are not exported from libsmime, so copy them here. Sigh. Fix fallout from fe480d8136b204c8dc6c68916cce7e816f8b9c48. Change-Id: I9ecba690a66c263528e5c12738d60cacec4f14ee diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 5f1be3d..9d14f13 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -74,6 +74,7 @@ #include "nss.h" #include "cert.h" #include "hasht.h" +#include "secerr.h" #include "sechash.h" #include "cms.h" #include "cmst.h" @@ -6399,6 +6400,221 @@ OUString PKIStatusInfoToString(const PKIStatusInfo& rStatusInfo) return result; } +// SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are +// not exported from libsmime, so copy them here. Sigh. + +SECStatus +my_SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len) +{ + PRUint32 decimal_numbers = 0; + PRUint32 result_bytes = 0; + SECStatus rv; + PRUint8 result[1024]; + + static const PRUint32 max_decimal = (0xffffffff / 10); + static const char OIDstring[] = {"OID."}; + + if (!from || !to) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (!len) { + len = PL_strlen(from); + } + if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) { + from += 4; /* skip leading "OID." if present */ + len -= 4; + } + if (!len) { +bad_data: + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + do { + PRUint32 decimal = 0; + while (len > 0 && isdigit(*from)) { + PRUint32 addend = (*from++ - '0'); + --len; + if (decimal > max_decimal) /* overflow */ + goto bad_data; + decimal = (decimal * 10) + addend; + if (decimal < addend) /* overflow */ + goto bad_data; + } + if (len != 0 && *from != '.') { + goto bad_data; + } + if (decimal_numbers == 0) { + if (decimal > 2) + goto bad_data; + result[0] = decimal * 40; + result_bytes = 1; + } else if (decimal_numbers == 1) { + if (decimal > 40) + goto bad_data; + result[0] += decimal; + } else { + /* encode the decimal number, */ + PRUint8 * rp; + PRUint32 num_bytes = 0; + PRUint32 tmp = decimal; + while (tmp) { + num_bytes++; + tmp >>= 7; + } + if (!num_bytes ) + ++num_bytes; /* use one byte for a zero value */ + if (num_bytes + result_bytes > sizeof result) + goto bad_data; + tmp = num_bytes; + rp = result + result_bytes - 1; + rp[tmp] = (PRUint8)(decimal & 0x7f); + decimal >>= 7; + while (--tmp > 0) { + rp[tmp] = (PRUint8)(decimal | 0x80); + decimal >>= 7; + } + result_bytes += num_bytes; + } + ++decimal_numbers; + if (len > 0) { /* skip trailing '.' */ + ++from; + --len; + } + } while (len > 0); + /* now result contains result_bytes of data */ + if (to->data && to->len >= result_bytes) { + PORT_Memcpy(to->data, result, to->len = result_bytes); + rv = SECSuccess; + } else { + SECItem result_item = {siBuffer, NULL, 0 }; + result_item.data = result; + result_item.len = result_bytes; + rv = SECITEM_CopyItem(pool, to, &result_item); + } + return rv; +} + +NSSCMSAttribute * +my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only) +{ + SECOidData *oid; + NSSCMSAttribute *attr1, *attr2; + + if (attrs == NULL) + return NULL; + + oid = SECOID_FindOIDByTag(oidtag); + if (oid == NULL) + return NULL; + + while ((attr1 = *attrs++) != NULL) { + if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data, + oid->oid.data, + oid->oid.len) == 0) + break; + } + + if (attr1 == NULL) + return NULL; + + if (!only) + return attr1; + + while ((attr2 = *attrs++) != NULL) { + if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data, + oid->oid.data, + oid->oid.len) == 0) + break; + } + + if (attr2 != NULL) + return NULL; + + return attr1; +} + +SECStatus +my_NSS_CMSArray_Add(PLArenaPool *poolp, void ***array, void *obj) +{ + void **p; + int n; + void **dest; + + PORT_Assert(array != NULL); + if (array == NULL) + return SECFailure; + + if (*array == NULL) { + dest = (void **)PORT_ArenaAlloc(poolp, 2 * sizeof(void *)); + n = 0; + } else { + n = 0; p = *array; + while (*p++) + n++; + dest = (void **)PORT_ArenaGrow (poolp, + *array, + (n + 1) * sizeof(void *), + (n + 2) * sizeof(void *)); + } + + if (dest == NULL) + return SECFailure; + + dest[n] = obj; + dest[n+1] = NULL; + *array = dest; + return SECSuccess; +} + +SECOidTag +my_NSS_CMSAttribute_GetType(NSSCMSAttribute *attr) +{ + SECOidData *typetag; + + typetag = SECOID_FindOID(&(attr->type)); + if (typetag == NULL) + return SEC_OID_UNKNOWN; + + return typetag->offset; +} + +SECStatus +my_NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr) +{ + NSSCMSAttribute *oattr; + void *mark; + SECOidTag type; + + mark = PORT_ArenaMark(poolp); + + /* find oidtag of attr */ + type = my_NSS_CMSAttribute_GetType(attr); + + /* see if we have one already */ + oattr = my_NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE); + PORT_Assert (oattr == NULL); + if (oattr != NULL) + goto loser; /* XXX or would it be better to replace it? */ + + /* no, shove it in */ + if (my_NSS_CMSArray_Add(poolp, reinterpret_cast<void ***>(attrs), (void *)attr) != SECSuccess) + goto loser; + + PORT_ArenaUnmark(poolp, mark); + return SECSuccess; + +loser: + PORT_ArenaRelease(poolp, mark); + return SECFailure; +} + +SECStatus +my_NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr) +{ + return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr); +} + #if 0 { #endif @@ -6725,11 +6941,6 @@ bool PDFWriterImpl::finalizeSignature() SAL_INFO("vcl.pdfwriter", "TimeStampResp received and decoded, status=" << PKIStatusInfoToString(response.status)); -#if 0 // SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are - // not exported from libsmime, need to think of some other - // approach. (As such I don't know if the code below would do - // the right thing even if they were.) - NSSCMSAttribute timestamp; timestamp.type.type = siBuffer; @@ -6750,7 +6961,7 @@ bool PDFWriterImpl::finalizeSignature() // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1) // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) // smime(16) aa(2) 14 } - if (SEC_StringToOID(NULL, &typetag.oid, "1.2.840.113549.1.9.16.14", 0) != SECSuccess) + if (my_SEC_StringToOID(NULL, &typetag.oid, "1.2.840.113549.1.9.16.14", 0) != SECSuccess) { SAL_WARN("vcl.pdfwriter", "PDF signing: SEC_StringToOID failed"); return false; @@ -6761,14 +6972,13 @@ bool PDFWriterImpl::finalizeSignature() typetag.supportedExtension = UNSUPPORTED_CERT_EXTENSION; // ??? timestamp.typeTag = &typetag; - timestamp.encoded = PR_FALSE; + timestamp.encoded = PR_TRUE; - if (NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, ×tamp) != SECSuccess) + if (my_NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, ×tamp) != SECSuccess) { SAL_WARN("vcl.pdfwriter", "PDF signing: can't add timestamp attribute"); return false; } -#endif } if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) commit 639730a75294346d4195539c26f466f14d030802 Author: Tor Lillqvist <t...@collabora.com> Date: Mon Feb 23 14:42:08 2015 +0200 tdf#84881: Unclear what the PKIStatusInfo::statusString is Anyway, we can't assume that a string from an external source is correctly formed UTF-8. Change-Id: Ic906c7047b933388d5b51b23095a5a3d4ac7e508 diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index b0ec568..5f1be3d 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6385,10 +6385,12 @@ OUString PKIStatusInfoToString(const PKIStatusInfo& rStatusInfo) result += PKIStatusToString(rStatusInfo.status.data[0]); else result += "unknown (len=" + OUString::number(rStatusInfo.status.len); - if (rStatusInfo.statusString.data != NULL) - result += ",statusString='" + - OUString::fromUtf8(OString(reinterpret_cast<const sal_Char*>(rStatusInfo.statusString.data), rStatusInfo.statusString.len)) + - "'"; + + // FIXME: Perhaps look at rStatusInfo.statusString.data but note + // that we of course can't assume it contains proper UTF-8. After + // all, it is data from an external source. Also, RFC3161 claims + // it should be a SEQUENCE (1..MAX) OF UTF8String, but another + // source claimed it would be a single UTF8String, hmm? // FIXME: Worth it to decode failInfo to cleartext, probably not at least as long as this is only for a SAL_INFO commit f4f08203ba4acebb4ae3143323ca508fdc0644bd Author: Tor Lillqvist <t...@collabora.com> Date: Mon Feb 23 14:21:53 2015 +0200 tdf#84881: Dump also the CMS data in a DBG_UTIL build Change-Id: I651041a86083eb49aad9a96f6f379149c21854f3 diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 2e31647..b0ec568 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6833,6 +6833,14 @@ bool PDFWriterImpl::finalizeSignature() free(pass); +#ifdef DBG_UTIL + { + FILE *out = fopen("PDFWRITER.cms.data", "wb"); + fwrite(cms_output.data, cms_output.len, 1, out); + fclose(out); + } +#endif + OStringBuffer cms_hexbuffer; for (unsigned int i = 0; i < cms_output.len ; i++) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits