summaryrefslogtreecommitdiffstats
path: root/sfx2/source/doc/DocumentSigner.cxx
blob: 519a66a400899f3f3f2ba53d840012c0f24dc433 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <sfx2/DocumentSigner.hxx>

#include <tools/stream.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <unotools/streamwrap.hxx>

#include <comphelper/storagehelper.hxx>
#include <comphelper/processfactory.hxx>

#include <com/sun/star/embed/XStorage.hpp>
#include <com/sun/star/embed/StorageFormats.hpp>
#include <com/sun/star/embed/XTransactedObject.hpp>
#include <com/sun/star/security/DocumentSignatureInformation.hpp>
#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
#include <com/sun/star/io/WrongFormatException.hpp>
#include <com/sun/star/io/XStream.hpp>

using namespace css;

namespace sfx2
{
bool DocumentSigner::signDocument(uno::Reference<security::XCertificate> const& rxCertificate)
{
    std::unique_ptr<SvStream> pStream(
        utl::UcbStreamHelper::CreateStream(m_aUrl, StreamMode::READ | StreamMode::WRITE));
    uno::Reference<io::XStream> xInputStream(new utl::OStreamWrapper(std::move(pStream)));

    bool bResult = false;
    uno::Reference<embed::XStorage> xWriteableZipStore;
    try
    {
        xWriteableZipStore = comphelper::OStorageHelper::GetStorageOfFormatFromStream(
            ZIP_STORAGE_FORMAT_STRING, xInputStream);
    }
    catch (const io::IOException&)
    {
    }

    OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(xWriteableZipStore));

    uno::Reference<security::XDocumentDigitalSignatures> xSigner(
        security::DocumentDigitalSignatures::createWithVersionAndValidSignature(
            comphelper::getProcessComponentContext(), aODFVersion,
            /*bHasValidDocumentSignature*/ true));

    try
    {
        uno::Reference<embed::XStorage> xMetaInf;
        if (xWriteableZipStore.is() && xWriteableZipStore->hasByName("META-INF"))
        {
            xMetaInf = xWriteableZipStore->openStorageElement("META-INF",
                                                              embed::ElementModes::READWRITE);
            if (!xMetaInf.is())
                throw uno::RuntimeException();
        }
        if (xMetaInf.is())
        {
            uno::Reference<embed::XStorage> xStorage
                = comphelper::OStorageHelper::GetStorageOfFormatFromStream(
                    ZIP_STORAGE_FORMAT_STRING, xInputStream);

            // ODF.
            uno::Reference<io::XStream> xStream;
            xStream.set(
                xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(),
                                            embed::ElementModes::READWRITE),
                uno::UNO_SET_THROW);
            bool bSuccess = xSigner->signDocumentWithCertificate(rxCertificate, xStorage, xStream);
            if (bSuccess)
            {
                uno::Reference<embed::XTransactedObject> xTransact(xMetaInf, uno::UNO_QUERY_THROW);
                xTransact->commit();
                xTransact.set(xWriteableZipStore, uno::UNO_QUERY_THROW);
                xTransact->commit();
                bResult = true;
            }
        }
        else if (xWriteableZipStore.is())
        {
            uno::Reference<embed::XStorage> xStorage
                = comphelper::OStorageHelper::GetStorageOfFormatFromStream(
                    ZIP_STORAGE_FORMAT_STRING, xInputStream);

            // OOXML.
            uno::Reference<io::XStream> xStream;

            // We need read-write to be able to add the signature relation.
            bool bSuccess = xSigner->signDocumentWithCertificate(rxCertificate, xStorage, xStream);

            if (bSuccess)
            {
                uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStore,
                                                                   uno::UNO_QUERY_THROW);
                xTransact->commit();
                bResult = true;
            }
        }
        else
        {
            // Something not ZIP based: e.g. PDF.
            bResult = xSigner->signDocumentWithCertificate(
                rxCertificate, uno::Reference<embed::XStorage>(), xInputStream);
        }
    }
    catch (const uno::Exception&)
    {
    }
    return bResult;
}

} // namespace sfx2

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */