filter/qa/data/ca.pem           |   70 ++++++++++++++++++++++++++++++++++++++++
 filter/qa/data/cert.pem         |   31 +++++++++++++++++
 filter/qa/data/key.pem          |   28 ++++++++++++++++
 filter/qa/pdf.cxx               |   60 ++++++++++++++++++++++++++++++++++
 filter/source/pdf/pdfexport.cxx |   28 ++++++++++++++++
 5 files changed, 217 insertions(+)

New commits:
commit b14098b69828cbafc81c10010f3276dd9b2683d8
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Oct 25 10:43:51 2024 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Fri Oct 25 14:50:56 2024 +0200

    cool#9992 lok doc sign: allow injecting sign cert/key during pdf export
    
    Interactive signing via the .uno:Signature command parameters were
    possible, but headless PDF export had no similar parameters.
    
    The primary difference is that the interactive signing works with the
    sign certificate of the SfxViewShell, while PDF export has its own
    vcl::PDFWriter::PDFWriterContext::SignCertificate.
    
    Fix the problem similar to what commit
    80723fccbb03c215bab84b10ac1eefaedef66b7c (filter: allow PDF export to
    sign from the cmdline, 2022-02-03) did, but here we don't refer to an
    already configured sign certificate by name, we take the sign cert/key
    from parameters instead.
    
    Test this in the NSS case where it's known to work, ignore the mscng
    signing case for now.
    
    Change-Id: Ib0c171736d2554fb3678ae4b8842541c43f9f3dd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175630
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/filter/qa/data/ca.pem b/filter/qa/data/ca.pem
new file mode 100644
index 000000000000..d08c9c67bcae
--- /dev/null
+++ b/filter/qa/data/ca.pem
@@ -0,0 +1,70 @@
+-----BEGIN CERTIFICATE-----
+MIIGADCCA+igAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgYsxCzAJBgNVBAYTAlVL
+MRAwDgYDVQQIDAdFbmdsYW5kMTAwLgYDVQQKDCdDcHB1bml0VGVzdF94bWxzZWN1
+cml0eV94bWxzZWMgUlNBIFRlc3QxODA2BgNVBAMML0NwcHVuaXRUZXN0X3htbHNl
+Y3VyaXR5X3htbHNlYyBSU0EgVGVzdCBSb290IENBMCAXDTI0MDkyMzEzMzA0MloY
+DzIxMjQwODMwMTMzMDQyWjCBjzELMAkGA1UEBhMCVUsxEDAOBgNVBAgMB0VuZ2xh
+bmQxMDAuBgNVBAoMJ0NwcHVuaXRUZXN0X3htbHNlY3VyaXR5X3htbHNlYyBSU0Eg
+VGVzdDE8MDoGA1UEAwwzQ3BwdW5pdFRlc3RfeG1sc2VjdXJpdHlfeG1sc2VjIElu
+dGVybWVkaWF0ZSBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
+AgEAj9kribqN994fmGGnL7l3Y4DEVEBUBV2kNlq9fM9wJmOEtaNyKIjYxzCFUAnt
+vKp0youu3tu48duDUez4I+Nc4gyez6IlyfPCXiEJulo0g6F3WZZg/xtk56JZnHFe
+aBHq3vm3L7a5y8c9j9Y26/BPRAqY1CtBSFUWV1uGPCQkNGNsO7qqtOdcKn7dFJq3
+K2sRaXp4J3QUhtlsEQ4/sWtXjuV7f4wqep0PEjFJ8oF6Jao5QYFHuLx4YZmo9vfX
+NSjv1TJbdQ+1zvw8sr3/SYyNt3B7Q3jXq8IC+Tfc1R9t/FaDeS9AiMuDJgq+aHWV
+ej8sspl2+d7mFXCuOoy9nE9aCWAwD1v6Ce1nK97qVUKRKxBxlKSM3TULWaJT8VC9
+UK0nsfK9OocCeybOa+irzVcgvVDlD8fPoM82bGAaA5z2SvSyrjk5/h2aHtG9U1tJ
+ke6GwxzyVlIySo4EC9SvW8Pu3v0vaHAeDAjUnA8aEPGmuKOMHsYq/Jgy3hkRLKuX
+iRENrshP/q0Vfso2NtfErSzqcBV5UWcYUhoCOiQXRo2Q9sy7lJDtRU5yFxlGtqRU
+ORY1LI9NMXi5pJioZftPZIMPJeDLeaEaNHD1vH9i/e/bN11/mYzM2SWuKdQbiYFX
+pZO8gDkp960R1VG3O0TKz7U678ZrjY0Y3t0uNhPFEOZgoCkCAwEAAaNmMGQwHQYD
+VR0OBBYEFFE6wan2eGv91MRbH6vbE4W3cMYNMB8GA1UdIwQYMBaAFOJn33YP7tq0
+45qRr2pHFpbwKe+7MBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGG
+MA0GCSqGSIb3DQEBCwUAA4ICAQAeNJClgszw5HQysHfoDe8YClRt9NI4b2obxRXY
+FGX4TgLNcXGBctOoB0B/kLK6TXSPNJqHQ2+cjm1Ol9vEr4iTuRDRBp1UPp6DycLO
+9moTnlw6IKj4Nq+OJ4NVPAl0FED2KWKW9fKHOSn2kqJ7Vf4owAGf3fSy6opeqLxg
+GlnwmDSuevdbiKUCTOL4XwAfl1YN7Jj+4lEKSQmJB786MUvb9YzCPXEBDPg0uN8w
+Jm/ToiKhN53rpXLToYAidJBJ1TyqKb0i9ohETrgiBHgLI5evd+5YrhEjkKdSsK4T
+qiodkiUb5UIEcw21D5M/kjimKQrOKWahOKZCjh3xkkRsJyaeoBetZyW79d6JvB5j
+sifp86HQPtohHo8XM6cEXhhQhwAbIoiD4JPoTtQefTvpBCVlh2RIMYgeSKSq/y3E
+aoWEt8OinvZw+JhJbK7oNNPsglIJtax8Jqdc3C4PTFrIA1PnWmr/+EbdMcwnYJjn
+uyUlSajOmTL50XBHJ4krgNTOCjS42obZ4/W7Z/INVhthqIy33fEq8CKaKKytCjDN
+wkZ6dqmMg/9+X/+ClWlr+Q7EPCUw5aW6Qc95aEv59kgct84wxqTQ2jaGuUv2DxNV
++hy8bsFGwPYc6yqbVm+Eu2ibyw+QV3jYJ3t6HdVJGntgRjeumRB/XuhwVwPaIijp
+jZWvGw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGCzCCA/OgAwIBAgIUf0E/LAmzIuu4Y81pnWRf+XARWkowDQYJKoZIhvcNAQEL
+BQAwgYsxCzAJBgNVBAYTAlVLMRAwDgYDVQQIDAdFbmdsYW5kMTAwLgYDVQQKDCdD
+cHB1bml0VGVzdF94bWxzZWN1cml0eV94bWxzZWMgUlNBIFRlc3QxODA2BgNVBAMM
+L0NwcHVuaXRUZXN0X3htbHNlY3VyaXR5X3htbHNlYyBSU0EgVGVzdCBSb290IENB
+MCAXDTI0MDkyMzEzMzA0MVoYDzIxMjQwODMwMTMzMDQxWjCBizELMAkGA1UEBhMC
+VUsxEDAOBgNVBAgMB0VuZ2xhbmQxMDAuBgNVBAoMJ0NwcHVuaXRUZXN0X3htbHNl
+Y3VyaXR5X3htbHNlYyBSU0EgVGVzdDE4MDYGA1UEAwwvQ3BwdW5pdFRlc3RfeG1s
+c2VjdXJpdHlfeG1sc2VjIFJTQSBUZXN0IFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDICUjHlgDCX741a9qvNgs2ba7nxLwb350hNzu7JbrP
+8R4NUpTgbJwbsxdqPPozXQP2Uos/F5zdLk7ZA5e7tH/sa7ZPbeL6LzSiMvR+Cl4T
+DKisr+C/3ASd3d78kLw0UPNpRyVLirxKT9ht10GYBLAgV9kUtQ9lLejOpHDtRq1q
+8TlX0c3N6tw4T7PWq52Hym4XaTtxJc1g7CHddg4CqsTVXf4HdooMVH5AECD52Uv7
+hjEQgY+hrNEQE7lN6gp3HtxANbZusL4N0kSXAH1N6A1JDw+V0Cd020CUxCOWN/SV
+gX9rV67t+ACbObRNLlSkiGQyaPd2UTlMa1zQbpPQuvxsmtBbh50gIlM5qYuCPT+X
+aI93IbGMRp8be7J2QU2T5nrb0wasVKVzaYcIs/fOBi+EL2t+Jd9a8IPrUkHVdcsx
+WW8Y/WA95s+G4M0/5uVWmaeraBJRUo/suu08v4w0ShGBlVdfPe5iTMQWVLmAAZ16
+icvcgtdCr7nyi3tl2Bv/VFNqi+T7lqyL1i+91sr2Stca4wfRmqE0KiU5npFjxkh4
+sbzpuZAfjCvF3ltIZ9TFlmxQ2edf95CrPfw8u0MjEh2sWflgZwzSAdThEyMEIty4
+ZomCqqJ76Fw2kJwMq++9uTJTVXsepqA/jQg0WgK2Tyz3/2eY99twcldXVXuMc7Ge
+AQIDAQABo2MwYTAdBgNVHQ4EFgQU4mffdg/u2rTjmpGvakcWlvAp77swHwYDVR0j
+BBgwFoAU4mffdg/u2rTjmpGvakcWlvAp77swDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBAC4errXBxYjJGtxT+5+VwISk
+4ve5nGna8/SNxt7VB0mREG91gnsu3uJvW05zoU+UUOHaaDvAuox2GGEAq/vKJN5y
+TpgnSYSgzFYxd8N+GqFqE3xwIPa02ntPwwLozF3aph4YcqrtCdPPNIXK5CRopnvQ
+LuUHwFvmz/nkoCPg/VlwFjxNvwGehy5wrhd3zmqd9dga8k3MWA+cVVtNnZld5HZu
+rpHOb3H7SCG+3l/kMdnMQCLvUrbKGSVKX6bOaW+FGm+oTTwLen/HHB21wxfPLySQ
+QDEyR1qGNj7sKgGaWU8334boSSjW3OrnHDLlMBr/XQAMgvHfy43qxOmww47xg685
+HNQYtbHIgVLZ6ou8vgzrjzV+Wpu8H7by2HH/yAHwRqsy2nmVPwkrdmCfSwYfZdAW
++Jzazg4gYVnBE89t8HarOXSiSh/YUS0V6F4koQKVv3b8MzmqO3ldRW2JcktrmZmU
+BYCh5UaK3X+Yyeus1UGrYCl6Yqj5M1JEmYmX/3EVeIcEK+H6Kx9Aeqr1WyJss0GT
+KVA5t+mOZ+SSvF3mFLxTo6ydTLOWA63NGuiLnhU1lbQRkTC0Dq0qenECx2gmG8XG
+FHlVbVsYqiaU6FdkFGzm+Scsl8UwygLV5KP0Y/54X8J6ZSRPHNRvBtRnZoRrjNFM
+wSJZ4vw/iDJO03o31TJ3
+-----END CERTIFICATE-----
diff --git a/filter/qa/data/cert.pem b/filter/qa/data/cert.pem
new file mode 100644
index 000000000000..e5bd58abc2a0
--- /dev/null
+++ b/filter/qa/data/cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVL
+MRAwDgYDVQQIDAdFbmdsYW5kMTAwLgYDVQQKDCdDcHB1bml0VGVzdF94bWxzZWN1
+cml0eV94bWxzZWMgUlNBIFRlc3QxPDA6BgNVBAMMM0NwcHVuaXRUZXN0X3htbHNl
+Y3VyaXR5X3htbHNlYyBJbnRlcm1lZGlhdGUgUm9vdCBDQTAgFw0yNDA5MjMxMzMw
+NDJaGA8yMTI0MDgzMDEzMzA0MlowgZExCzAJBgNVBAYTAlVLMRAwDgYDVQQIDAdF
+bmdsYW5kMTAwLgYDVQQKDCdDcHB1bml0VGVzdF94bWxzZWN1cml0eV94bWxzZWMg
+UlNBIFRlc3QxPjA8BgNVBAMMNUNwcHVuaXRUZXN0X3htbHNlY3VyaXR5X3htbHNl
+YyBSU0EgVGVzdCBleGFtcGxlIEFsaWNlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAlSfDFDdlDJv1YY6ANc3RuiGu3oduoDFFJL//l0j52J8btQRQrtp5
+P0OaplTYdLi1hK2cj/XV7KWB+E5p/IwgqNZdOXR+RY1jNkQFiSLdMbkwEoPtaPVh
+DAxfSLyIazSsrERgGOBn6EbomVyc87UrVj6QgwzofDRmPtgOFBlDSfFiqIKfxU4T
+lntLOnFiGLFGcVDSsRA/UQiy9o0bAfaS68IB7FpW9NoLTEgzGE/PzCFkGAmgC5yB
+rvk8/tfCVsx8FeqdZqlBZhrD+sP+rItRRXdSiH52C+XMXqowNxJhPBP4HFv5LVQo
+l9oXK5QXieYrFmMpwTJrkNdFXkm+2iJFAQIDAQABo4HFMIHCMAkGA1UdEwQCMAAw
+EQYJYIZIAYb4QgEBBAQDAgWgMDMGCWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVy
+YXRlZCBDbGllbnQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFKcwU0F2IER917YAPm5S
+FjaVtYHpMB8GA1UdIwQYMBaAFFE6wan2eGv91MRbH6vbE4W3cMYNMA4GA1UdDwEB
+/wQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcN
+AQELBQADggIBABtgvYTKyfIZobgnsrO8PjbQIFdyx5YV0RJ8fshcSzSFSZYN0qbC
+J4U2i84Hx9HvzzFtHHEgJ4ot6VXsfEGqFkf8dvafqi1gAQ4cbIazdHQoELgFKJwL
+U5X/NGl0PQ46/l4vKHKrpAN1TRu7MGE0SwxRYM5KlzibXRL485ck/dzap8qSaxt/
+sSW6YxpttM3umPRL+5Mc+ttJBPYKAwfu/dHkBxGC47E/h2oazNOI2nhLsfbT2YmW
+yJpgt/hnqxB7LtZbnAnaMVEWGdlBp79vU6V0+JSznMmc4t1eX6mUl5tXQF+BSmpw
+f4agwi+uSE9WEXfhChjLfEtEGgK/+/tl012EqY8qt1SdwDDH8usEcrK2iyd14Wgs
+uH3swGqYdBaHnNaAgtuMDlQmJYaq5cKbaTj+PGLr5WU9VIXFSIM03dkyGA13I3ts
+cBpWfh3f89q6YoAqdgwUlCg1OqU4LsfS8n8EKvyM1+zb45JlNxzXpFp+/CwR7I2D
+Tk4QXELeFOl1KU7X9eTftliwAqctRGLCvr2VXA4FbkFhtreCctCQm/FUgIr01YrW
+mhr29Wwaz3DBeymbFXUdYQZqI0OSBBc1bDJkMHftpTBp79EoglKXqMb1/7jcV3bT
+oWXfkHN//B4B2gpv7DxHyP7H6teW/hGuCZeIhYDiL0TR1E68RO1sHRT1
+-----END CERTIFICATE-----
diff --git a/filter/qa/data/key.pem b/filter/qa/data/key.pem
new file mode 100644
index 000000000000..6407bb9ab319
--- /dev/null
+++ b/filter/qa/data/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCVJ8MUN2UMm/Vh
+joA1zdG6Ia7eh26gMUUkv/+XSPnYnxu1BFCu2nk/Q5qmVNh0uLWErZyP9dXspYH4
+Tmn8jCCo1l05dH5FjWM2RAWJIt0xuTASg+1o9WEMDF9IvIhrNKysRGAY4GfoRuiZ
+XJzztStWPpCDDOh8NGY+2A4UGUNJ8WKogp/FThOWe0s6cWIYsUZxUNKxED9RCLL2
+jRsB9pLrwgHsWlb02gtMSDMYT8/MIWQYCaALnIGu+Tz+18JWzHwV6p1mqUFmGsP6
+w/6si1FFd1KIfnYL5cxeqjA3EmE8E/gcW/ktVCiX2hcrlBeJ5isWYynBMmuQ10Ve
+Sb7aIkUBAgMBAAECggEAANSKkIWiWjAZnRSjRzdkTtN5ZAJd4toK24h+v+wIZV61
+e3n66C4BzHzGDP2wMbJB8wdZjZvmqCxLvGTk+EqUM4Xj0Xwp8DWUQCf3zhuYvrI4
+PbRkok3KO7w7dRvk7FA4A0aHOJi6TdbEFHdVbaIqK9L93FeicTdsQ7aRkZ46UZRu
+YcOc//qIy4nD7O4UXaZoV/WKp2c9KJliED7QqnCGGUQpUsY5zvx6LQwWeXzrgCsT
+am6Hi38/o66Ikel1aMACeq6lGmYqyqNIzHgihuyfcZKoMIYZrLQd2P6aC45H81DS
+gQuMQVZBLDFoUX1ARAvvT8heNB38xPevQBo0uqOvAQKBgQDSdZogxv4c6quIY8xX
+3Bf8H+FKD3v82B++c88IUMGKyqZUp7eJoqivKEWDd/vsxEg3SewnRV2OpYgP2ekz
+seTzVPu877Kv+S/cZFlKYeKDovgCamWeDHR+PSasadk/7pG7izC3Khf9cdzWwgno
+OJKJBKlRwMYAvBNwkK026nTRgQKBgQC1bjimwPjUdtogaIfRqR/9KcShavjMWayh
+1QhH3oYoLIEuzIjd0S+zNSOe35fSslr2ss6NEu0yfERW1q/8HWl2TrNEp2oMn2FO
+Mg6OkwhsTbjWbr/mHae4stXpNIPO8UbuxpNx5qGkmcdAgbOsQJ4m7BERrVQItDsv
+mbNpo4gzgQKBgBVmb+21TlGSay7LNxQYBThV5YqqWGk1cMTk8cBetc9vG8qv4zHT
+oGNvLOJZaPyCWPWGRsUXgJPosRUri1L+W9GCarajiP/rzroSWiH+IhJQl/dm6j5P
+9eiAP1Z4zOZ7U8ZGOQXm+dmDonkT8f3zArN8DduKRpf8h92CWJqk7IwBAoGAa7m7
+V3/i/zxmvbFzW5DhFo+zWejLO4LPVvPHy+ybmcT7G0+EwLhRa0XVFaNLYWZXTn3S
+2L7xKfXRGgK1UawhD4chOFVzSXVk8GoWbJ9u8+eeJWxy8u6OxMMi8iolTT3D0UkF
+CS9YsQRB49JfXZqsjQ3EAMv6xoRFVDkd506bM4ECgYBPN8B6QpENSsVoVGcS/gpR
+hLno9fIvIhABCDoYNTkNT6ILJ8BcU7+lv/zs8UQacqf6Fy7JozbBeEY/Dxr97DKg
+e5djZvWYLqmvAiPilN5YEt5WvuswzrGaTcol/E3X5B3aACFFE8+O9i8T2q0VlAot
+hC+h7nh0KmPyzL73JUX2Jg==
+-----END PRIVATE KEY-----
diff --git a/filter/qa/pdf.cxx b/filter/qa/pdf.cxx
index 9ab11cd36d71..99275ce08c87 100644
--- a/filter/qa/pdf.cxx
+++ b/filter/qa/pdf.cxx
@@ -366,6 +366,66 @@ CPPUNIT_TEST_FIXTURE(Test, testWatermarkRotateAngle)
     // i.e. the rotation angle was 270 for an A4 page, not the requested 45 
degrees.
     CPPUNIT_ASSERT_EQUAL(nExpectedRotateAngle, nActualRotateAngle);
 }
+
+#ifdef UNX
+CPPUNIT_TEST_FIXTURE(Test, testSignCertificatePEM)
+{
+    // Given an empty document:
+    std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+    if (!pPDFium)
+        return;
+
+    uno::Reference<xml::crypto::XSEInitializer> xSEInitializer
+        = xml::crypto::SEInitializer::create(mxComponentContext);
+    uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext
+        = xSEInitializer->createSecurityContext(OUString());
+    uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment
+        = xSecurityContext->getSecurityEnvironment();
+    OUString aKeyPath = createFileURL(u"key.pem");
+    SvFileStream aKeyStream(aKeyPath, StreamMode::READ);
+    OUString aKeyPem
+        = OUString::fromUtf8(read_uInt8s_ToOString(aKeyStream, 
aKeyStream.remainingSize()));
+    OUString aCertPath = createFileURL(u"cert.pem");
+    SvFileStream aCertStream(aCertPath, StreamMode::READ);
+    OUString aCertPem
+        = OUString::fromUtf8(read_uInt8s_ToOString(aCertStream, 
aCertStream.remainingSize()));
+    OUString aCaPath = createFileURL(u"ca.pem");
+    SvFileStream aCaStream(aCaPath, StreamMode::READ);
+    OUString aCaPem
+        = OUString::fromUtf8(read_uInt8s_ToOString(aCaStream, 
aCaStream.remainingSize()));
+    uno::Sequence<beans::PropertyValue> aFilterData{
+        comphelper::makePropertyValue("SignPDF", true),
+        comphelper::makePropertyValue("SignCertificateCertPem", aCertPem),
+        comphelper::makePropertyValue("SignCertificateKeyPem", aKeyPem),
+        comphelper::makePropertyValue("aSignCertificateCaPem", aCaPem),
+    };
+    mxComponent.set(loadFromDesktop("private:factory/swriter", 
"com.sun.star.text.TextDocument"));
+
+    // When exporting to PDF, and referring to a certificate using a 
cert/key/ca PEM, which is not
+    // in the NSS database:
+    uno::Reference<css::lang::XMultiServiceFactory> xFactory = 
getMultiServiceFactory();
+    uno::Reference<document::XFilter> xFilter(
+        xFactory->createInstance("com.sun.star.document.PDFFilter"), 
uno::UNO_QUERY);
+    uno::Reference<document::XExporter> xExporter(xFilter, uno::UNO_QUERY);
+    xExporter->setSourceDocument(mxComponent);
+    SvMemoryStream aStream;
+    uno::Reference<io::XOutputStream> xOutputStream(new 
utl::OStreamWrapper(aStream));
+    uno::Sequence<beans::PropertyValue> aDescriptor{
+        comphelper::makePropertyValue("FilterName", 
OUString("writer_pdf_Export")),
+        comphelper::makePropertyValue("FilterData", aFilterData),
+        comphelper::makePropertyValue("OutputStream", xOutputStream),
+    };
+    xFilter->filter(aDescriptor);
+
+    // Then make sure the resulting PDF has a signature:
+    std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
+        = pPDFium->openDocument(aStream.GetData(), aStream.GetSize(), 
OString());
+    // Without the accompanying fix in place, this test would have failed, as 
signing was enabled
+    // without configured certificate, so the whole export failed.
+    CPPUNIT_ASSERT(pPdfDocument);
+    CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getSignatureCount());
+}
+#endif
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx
index f2874f5b8e94..b0143fc243ed 100644
--- a/filter/source/pdf/pdfexport.cxx
+++ b/filter/source/pdf/pdfexport.cxx
@@ -39,6 +39,7 @@
 #include <unotools/configmgr.hxx>
 #include <comphelper/compbase.hxx>
 #include <officecfg/Office/Common.hxx>
+#include <sfx2/lokhelper.hxx>
 
 #include "pdfexport.hxx"
 #include <strings.hrc>
@@ -515,6 +516,9 @@ bool PDFExport::Export( const OUString& rFile, const 
Sequence< PropertyValue >&
             aContext.DocumentInfo.Creator = aCreator;
 
             OUString aSignCertificateSubjectName;
+            OUString aSignCertificateCertPem;
+            OUString aSignCertificateKeyPem;
+            OUString aSignCertificateCaPem;
             for ( const beans::PropertyValue& rProp : rFilterData )
             {
                 if ( rProp.Name == "PageRange" )
@@ -678,6 +682,12 @@ bool PDFExport::Export( const OUString& rFile, const 
Sequence< PropertyValue >&
                     rProp.Value >>= aSignCertificate;
                 else if (rProp.Name == "SignCertificateSubjectName")
                     rProp.Value >>= aSignCertificateSubjectName;
+                else if (rProp.Name == "SignCertificateCertPem")
+                    rProp.Value >>= aSignCertificateCertPem;
+                else if (rProp.Name == "SignCertificateKeyPem")
+                    rProp.Value >>= aSignCertificateKeyPem;
+                else if (rProp.Name == "SignCertificateCaPem")
+                    rProp.Value >>= aSignCertificateCaPem;
                 else if ( rProp.Name == "SignatureTSA" )
                     rProp.Value >>= sSignTSA;
                 else if ( rProp.Name == "ExportPlaceholders" )
@@ -705,6 +715,24 @@ bool PDFExport::Export( const OUString& rFile, const 
Sequence< PropertyValue >&
                 aSignCertificate = 
GetCertificateFromSubjectName(aSignCertificateSubjectName);
             }
 
+            if (!aSignCertificate.is())
+            {
+                // Still no signing certificate configured, see if we got a 
ca/cert/key in PEM
+                // format:
+                if (!aSignCertificateCaPem.isEmpty())
+                {
+                    std::string aSignatureCa(aSignCertificateCaPem.toUtf8());
+                    std::vector<std::string> aCerts = 
SfxLokHelper::extractCertificates(aSignatureCa);
+                    SfxLokHelper::addCertificates(aCerts);
+                }
+                if (!aSignCertificateCertPem.isEmpty() && 
!aSignCertificateKeyPem.isEmpty())
+                {
+                    std::string 
aSignatureCert(aSignCertificateCertPem.toUtf8());
+                    std::string aSignatureKey(aSignCertificateKeyPem.toUtf8());
+                    aSignCertificate = 
SfxLokHelper::getSigningCertificate(aSignatureCert, aSignatureKey);
+                }
+            }
+
             aContext.URL        = 
aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
 
             // set the correct version, depending on user request

Reply via email to