Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svl/source/crypto/cryptosign.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include <sal/config.h>
11
12
#include <algorithm>
13
#include <array>
14
15
#include <svl/cryptosign.hxx>
16
#include <svl/sigstruct.hxx>
17
#include <config_crypto.h>
18
#include <o3tl/numeric.hxx>
19
20
#if USE_CRYPTO_NSS
21
#include <systools/curlinit.hxx>
22
#endif
23
24
#include <rtl/character.hxx>
25
#include <rtl/strbuf.hxx>
26
#include <rtl/string.hxx>
27
#include <sal/log.hxx>
28
#include <tools/datetime.hxx>
29
#include <tools/stream.hxx>
30
#include <comphelper/base64.hxx>
31
#include <comphelper/hash.hxx>
32
#include <comphelper/processfactory.hxx>
33
#include <comphelper/random.hxx>
34
#include <comphelper/scopeguard.hxx>
35
#include <comphelper/lok.hxx>
36
#include <com/sun/star/security/XCertificate.hpp>
37
#include <com/sun/star/uno/Sequence.hxx>
38
#include <o3tl/char16_t2wchar_t.hxx>
39
40
#if USE_CRYPTO_NSS
41
// NSS headers for PDF signing
42
#include <cert.h>
43
#include <keyhi.h>
44
#include <pk11pub.h>
45
#include <hasht.h>
46
#include <secerr.h>
47
#include <sechash.h>
48
#include <cms.h>
49
#include <cmst.h>
50
51
// We use curl for RFC3161 time stamp requests
52
#include <curl/curl.h>
53
54
#include <com/sun/star/xml/crypto/DigestID.hpp>
55
#include <com/sun/star/xml/crypto/NSSInitializer.hpp>
56
#include <mutex>
57
#endif
58
59
#if USE_CRYPTO_MSCAPI
60
// WinCrypt headers for PDF signing
61
// Note: this uses Windows 7 APIs and requires the relevant data types
62
#include <prewin.h>
63
#include <wincrypt.h>
64
#include <postwin.h>
65
#include <comphelper/windowserrorstring.hxx>
66
#endif
67
68
using namespace com::sun::star;
69
70
namespace {
71
#if USE_CRYPTO_NSS
72
char *PDFSigningPKCS7PasswordCallback(PK11SlotInfo * /*slot*/, PRBool /*retry*/, void *arg)
73
{
74
    return PL_strdup(static_cast<char *>(arg));
75
}
76
77
// ASN.1 used in the (much simpler) time stamp request. From RFC3161
78
// and other sources.
79
80
/*
81
AlgorithmIdentifier  ::=  SEQUENCE  {
82
     algorithm  OBJECT IDENTIFIER,
83
     parameters ANY DEFINED BY algorithm OPTIONAL  }
84
                   -- contains a value of the type
85
                   -- registered for use with the
86
                   -- algorithm object identifier value
87
88
MessageImprint ::= SEQUENCE  {
89
    hashAlgorithm AlgorithmIdentifier,
90
    hashedMessage OCTET STRING  }
91
*/
92
93
struct MessageImprint {
94
    SECAlgorithmID hashAlgorithm;
95
    SECItem hashedMessage;
96
};
97
98
/*
99
Extension  ::=  SEQUENCE  {
100
    extnID    OBJECT IDENTIFIER,
101
    critical  BOOLEAN DEFAULT FALSE,
102
    extnValue OCTET STRING  }
103
*/
104
105
struct Extension {
106
    SECItem  extnID;
107
    SECItem  critical;
108
    SECItem  extnValue;
109
};
110
111
/*
112
Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
113
*/
114
115
/*
116
TSAPolicyId ::= OBJECT IDENTIFIER
117
118
TimeStampReq ::= SEQUENCE  {
119
    version            INTEGER  { v1(1) },
120
    messageImprint     MessageImprint,
121
    --a hash algorithm OID and the hash value of the data to be
122
    --time-stamped
123
    reqPolicy          TSAPolicyId         OPTIONAL,
124
    nonce              INTEGER             OPTIONAL,
125
    certReq            BOOLEAN             DEFAULT FALSE,
126
    extensions     [0] IMPLICIT Extensions OPTIONAL  }
127
*/
128
129
struct TimeStampReq {
130
    SECItem version;
131
    MessageImprint messageImprint;
132
    SECItem reqPolicy;
133
    SECItem nonce;
134
    SECItem certReq;
135
    Extension *extensions;
136
};
137
138
/**
139
 * General name, defined by RFC 3280.
140
 */
141
struct GeneralName
142
{
143
    CERTName name;
144
};
145
146
/**
147
 * List of general names (only one for now), defined by RFC 3280.
148
 */
149
struct GeneralNames
150
{
151
    GeneralName names;
152
};
153
154
/**
155
 * Supplies different fields to identify a certificate, defined by RFC 5035.
156
 */
157
struct IssuerSerial
158
{
159
    GeneralNames issuer;
160
    SECItem serialNumber;
161
};
162
163
/**
164
 * Supplies different fields that are used to identify certificates, defined by
165
 * RFC 5035.
166
 */
167
struct ESSCertIDv2
168
{
169
    SECAlgorithmID hashAlgorithm;
170
    SECItem certHash;
171
    IssuerSerial issuerSerial;
172
};
173
174
/**
175
 * This attribute uses the ESSCertIDv2 structure, defined by RFC 5035.
176
 */
177
struct SigningCertificateV2
178
{
179
    ESSCertIDv2** certs;
180
181
    SigningCertificateV2()
182
        : certs(nullptr)
183
    {
184
    }
185
};
186
187
/**
188
 * GeneralName ::= CHOICE {
189
 *      otherName                       [0]     OtherName,
190
 *      rfc822Name                      [1]     IA5String,
191
 *      dNSName                         [2]     IA5String,
192
 *      x400Address                     [3]     ORAddress,
193
 *      directoryName                   [4]     Name,
194
 *      ediPartyName                    [5]     EDIPartyName,
195
 *      uniformResourceIdentifier       [6]     IA5String,
196
 *      iPAddress                       [7]     OCTET STRING,
197
 *      registeredID                    [8]     OBJECT IDENTIFIER
198
 * }
199
 */
200
const SEC_ASN1Template GeneralNameTemplate[] =
201
{
202
    {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralName)},
203
    {SEC_ASN1_INLINE, offsetof(GeneralName, name), CERT_NameTemplate, 0},
204
    {0, 0, nullptr, 0}
205
};
206
207
/**
208
 * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
209
 */
210
const SEC_ASN1Template GeneralNamesTemplate[] =
211
{
212
    {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(GeneralNames)},
213
    {SEC_ASN1_INLINE | SEC_ASN1_CONTEXT_SPECIFIC | 4, offsetof(GeneralNames, names), GeneralNameTemplate, 0},
214
    {0, 0, nullptr, 0}
215
};
216
217
/**
218
 * IssuerSerial ::= SEQUENCE {
219
 *     issuer GeneralNames,
220
 *     serialNumber CertificateSerialNumber
221
 * }
222
 */
223
const SEC_ASN1Template IssuerSerialTemplate[] =
224
{
225
    {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(IssuerSerial)},
226
    {SEC_ASN1_INLINE, offsetof(IssuerSerial, issuer), GeneralNamesTemplate, 0},
227
    {SEC_ASN1_INTEGER, offsetof(IssuerSerial, serialNumber), nullptr, 0},
228
    {0, 0, nullptr, 0}
229
};
230
231
232
/**
233
 * Hash ::= OCTET STRING
234
 *
235
 * ESSCertIDv2 ::= SEQUENCE {
236
 *     hashAlgorithm AlgorithmIdentifier DEFAULT {algorithm id-sha256},
237
 *     certHash Hash,
238
 *     issuerSerial IssuerSerial OPTIONAL
239
 * }
240
 */
241
242
SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
243
244
const SEC_ASN1Template ESSCertIDv2Template[] =
245
{
246
    {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(ESSCertIDv2)},
247
    {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, hashAlgorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), 0},
248
    {SEC_ASN1_OCTET_STRING, offsetof(ESSCertIDv2, certHash), nullptr, 0},
249
    {SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(ESSCertIDv2, issuerSerial), IssuerSerialTemplate, 0},
250
    {0, 0, nullptr, 0}
251
};
252
253
/**
254
 * SigningCertificateV2 ::= SEQUENCE {
255
 * }
256
 */
257
const SEC_ASN1Template SigningCertificateV2Template[] =
258
{
259
    {SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(SigningCertificateV2)},
260
    {SEC_ASN1_SEQUENCE_OF, offsetof(SigningCertificateV2, certs), ESSCertIDv2Template, 0},
261
    {0, 0, nullptr, 0}
262
};
263
264
struct PKIStatusInfo {
265
    SECItem status;
266
    SECItem statusString;
267
    SECItem failInfo;
268
};
269
270
const SEC_ASN1Template PKIStatusInfo_Template[] =
271
{
272
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(PKIStatusInfo) },
273
    { SEC_ASN1_INTEGER, offsetof(PKIStatusInfo, status), nullptr, 0 },
274
    { SEC_ASN1_CONSTRUCTED | SEC_ASN1_SEQUENCE | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, statusString), nullptr, 0 },
275
    { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, offsetof(PKIStatusInfo, failInfo), nullptr, 0 },
276
    { 0, 0, nullptr, 0 }
277
};
278
279
const SEC_ASN1Template Any_Template[] =
280
{
281
    { SEC_ASN1_ANY, 0, nullptr, sizeof(SECItem) }
282
};
283
284
struct TimeStampResp {
285
    PKIStatusInfo status;
286
    SECItem timeStampToken;
287
};
288
289
const SEC_ASN1Template TimeStampResp_Template[] =
290
{
291
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampResp) },
292
    { SEC_ASN1_INLINE, offsetof(TimeStampResp, status), PKIStatusInfo_Template, 0 },
293
    { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), Any_Template, 0 },
294
    { 0, 0, nullptr, 0 }
295
};
296
297
const SEC_ASN1Template MessageImprint_Template[] =
298
{
299
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(MessageImprint) },
300
    { SEC_ASN1_INLINE, offsetof(MessageImprint, hashAlgorithm), SECOID_AlgorithmIDTemplate, 0 },
301
    { SEC_ASN1_OCTET_STRING, offsetof(MessageImprint, hashedMessage), nullptr, 0 },
302
    { 0, 0, nullptr, 0 }
303
};
304
305
const SEC_ASN1Template Extension_Template[] =
306
{
307
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(Extension) },
308
    { SEC_ASN1_OBJECT_ID, offsetof(Extension, extnID), nullptr, 0 },
309
    { SEC_ASN1_BOOLEAN, offsetof(Extension, critical), nullptr, 0 },
310
    { SEC_ASN1_OCTET_STRING, offsetof(Extension, extnValue), nullptr, 0 },
311
    { 0, 0, nullptr, 0 }
312
};
313
314
const SEC_ASN1Template Extensions_Template[] =
315
{
316
    { SEC_ASN1_SEQUENCE_OF, 0, Extension_Template, 0 }
317
};
318
319
const SEC_ASN1Template TimeStampReq_Template[] =
320
{
321
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(TimeStampReq) },
322
    { SEC_ASN1_INTEGER, offsetof(TimeStampReq, version), nullptr, 0 },
323
    { SEC_ASN1_INLINE, offsetof(TimeStampReq, messageImprint), MessageImprint_Template, 0 },
324
    { SEC_ASN1_OBJECT_ID | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, reqPolicy), nullptr, 0 },
325
    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, nonce), nullptr, 0 },
326
    { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, certReq), nullptr, 0 },
327
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), Extensions_Template, 0 },
328
    { 0, 0, nullptr, 0 }
329
};
330
331
// 1.2.840.113549.1.9.16.2.47
332
constexpr unsigned char OID_SIGNINGCERTIFICATEV2[] {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x2f};
333
// 1.2.840.113549.1.9.16.2.14
334
constexpr unsigned char OID_TIMESTAMPTOKEN[] {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x02, 0x0e};
335
336
struct cms_recode_attribute {
337
  SECItem type;
338
  SECItem **values;
339
};
340
341
struct cms_recode_signer_info {
342
  SECItem version;
343
  SECItem signerIdentifier;
344
  SECItem digestAlg;
345
  SECItem authAttr;
346
  SECItem digestEncAlg;
347
  SECItem encDigest;
348
  cms_recode_attribute **unAuthAttr;
349
};
350
351
struct cms_recode_signed_data {
352
  SECItem version;
353
  SECItem digestAlgorithms;
354
  SECItem contentInfo;
355
  SECItem rawCerts;
356
  SECItem crls;
357
  cms_recode_signer_info **signerInfos;
358
};
359
360
struct cms_recode_message {
361
  SECItem contentType;
362
  cms_recode_signed_data signedData;
363
};
364
365
const SEC_ASN1Template recode_attribute_template[] = {
366
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(cms_recode_attribute) },
367
    { SEC_ASN1_OBJECT_ID, offsetof(cms_recode_attribute, type), nullptr, 0 },
368
    { SEC_ASN1_SET_OF, offsetof(cms_recode_attribute, values), SEC_AnyTemplate, 0 },
369
    {0, 0, nullptr, 0}};
370
371
const SEC_ASN1Template recode_set_of_attribute_template[] = {
372
    { SEC_ASN1_SET_OF, 0, recode_attribute_template, 0 }
373
};
374
375
const SEC_ASN1Template recode_signer_info_template[] = {
376
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(cms_recode_signer_info) },
377
    { SEC_ASN1_ANY, offsetof(cms_recode_signer_info, version), nullptr, 0 },
378
    { SEC_ASN1_ANY, offsetof(cms_recode_signer_info, signerIdentifier), nullptr, 0 },
379
    { SEC_ASN1_ANY, offsetof(cms_recode_signer_info, digestAlg), nullptr, 0 },
380
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
381
      offsetof(cms_recode_signer_info, authAttr), SEC_AnyTemplate, 0 },
382
    { SEC_ASN1_ANY, offsetof(cms_recode_signer_info, digestEncAlg), nullptr, 0 },
383
    { SEC_ASN1_ANY, offsetof(cms_recode_signer_info, encDigest), nullptr, 0 },
384
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
385
      offsetof(cms_recode_signer_info, unAuthAttr), recode_set_of_attribute_template, 0 },
386
    {0, 0, nullptr, 0}};
387
388
const SEC_ASN1Template recode_signed_data_template[] = {
389
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(cms_recode_signed_data) },
390
    { SEC_ASN1_ANY, offsetof(cms_recode_signed_data, version), nullptr, 0 },
391
    { SEC_ASN1_ANY, offsetof(cms_recode_signed_data, digestAlgorithms), nullptr, 0 },
392
    { SEC_ASN1_ANY, offsetof(cms_recode_signed_data, contentInfo), nullptr, 0 },
393
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
394
      offsetof(cms_recode_signed_data, rawCerts), SEC_AnyTemplate, 0 },
395
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
396
      offsetof(cms_recode_signed_data, crls), SEC_AnyTemplate, 0 },
397
    { SEC_ASN1_SET_OF, offsetof(cms_recode_signed_data, signerInfos), recode_signer_info_template,
398
      0 },
399
    {0, 0, nullptr, 0}};
400
401
const SEC_ASN1Template recode_message_template[] = {
402
    { SEC_ASN1_SEQUENCE, 0, nullptr, sizeof(cms_recode_message) },
403
    { SEC_ASN1_ANY, offsetof(cms_recode_message, contentType), nullptr, 0 },
404
    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
405
      offsetof(cms_recode_message, signedData), recode_signed_data_template, 0 },
406
    {0, 0, nullptr, 0}};
407
408
size_t AppendToBuffer(char const *ptr, size_t size, size_t nmemb, void *userdata)
409
{
410
    OStringBuffer *pBuffer = static_cast<OStringBuffer*>(userdata);
411
    pBuffer->append(ptr, size*nmemb);
412
413
    return size*nmemb;
414
}
415
416
OUString PKIStatusToString(int n)
417
{
418
    switch (n)
419
    {
420
    case 0: return u"granted"_ustr;
421
    case 1: return u"grantedWithMods"_ustr;
422
    case 2: return u"rejection"_ustr;
423
    case 3: return u"waiting"_ustr;
424
    case 4: return u"revocationWarning"_ustr;
425
    case 5: return u"revocationNotification"_ustr;
426
    default: return "unknown (" + OUString::number(n) + ")";
427
    }
428
}
429
430
OUString PKIStatusInfoToString(const PKIStatusInfo& rStatusInfo)
431
{
432
    OUString result = u"{status="_ustr;
433
    if (rStatusInfo.status.len == 1)
434
        result += PKIStatusToString(rStatusInfo.status.data[0]);
435
    else
436
        result += "unknown (len=" + OUString::number(rStatusInfo.status.len);
437
438
    // FIXME: Perhaps look at rStatusInfo.statusString.data but note
439
    // that we of course can't assume it contains proper UTF-8. After
440
    // all, it is data from an external source. Also, RFC3161 claims
441
    // it should be a SEQUENCE (1..MAX) OF UTF8String, but another
442
    // source claimed it would be a single UTF8String, hmm?
443
444
    // FIXME: Worth it to decode failInfo to cleartext, probably not at least as long as this is only for a SAL_INFO
445
446
    result += "}";
447
448
    return result;
449
}
450
451
// SEC_StringToOID() and NSS_CMSSignerInfo_AddUnauthAttr() are
452
// not exported from libsmime, so copy them here. Sigh.
453
454
NSSCMSAttribute *
455
my_NSS_CMSAttributeArray_FindAttrByOidTag(NSSCMSAttribute **attrs, SECOidTag oidtag, PRBool only)
456
{
457
    SECOidData *oid;
458
    NSSCMSAttribute *attr1, *attr2;
459
460
    if (attrs == nullptr)
461
        return nullptr;
462
463
    oid = SECOID_FindOIDByTag(oidtag);
464
    if (oid == nullptr)
465
        return nullptr;
466
467
    while ((attr1 = *attrs++) != nullptr) {
468
    if (attr1->type.len == oid->oid.len && PORT_Memcmp (attr1->type.data,
469
                                oid->oid.data,
470
                                oid->oid.len) == 0)
471
        break;
472
    }
473
474
    if (attr1 == nullptr)
475
        return nullptr;
476
477
    if (!only)
478
        return attr1;
479
480
    while ((attr2 = *attrs++) != nullptr) {
481
    if (attr2->type.len == oid->oid.len && PORT_Memcmp (attr2->type.data,
482
                                oid->oid.data,
483
                                oid->oid.len) == 0)
484
        break;
485
    }
486
487
    if (attr2 != nullptr)
488
        return nullptr;
489
490
    return attr1;
491
}
492
493
SECStatus
494
my_NSS_CMSArray_Add(PLArenaPool *poolp, void ***array, void *obj)
495
{
496
    int n = 0;
497
    void **dest;
498
499
    PORT_Assert(array != NULL);
500
    if (array == nullptr)
501
        return SECFailure;
502
503
    if (*array == nullptr) {
504
        dest = static_cast<void **>(PORT_ArenaAlloc(poolp, 2 * sizeof(void *)));
505
    } else {
506
        void **p = *array;
507
        while (*p++)
508
            n++;
509
        dest = static_cast<void **>(PORT_ArenaGrow (poolp,
510
                      *array,
511
                      (n + 1) * sizeof(void *),
512
                      (n + 2) * sizeof(void *)));
513
    }
514
515
    if (dest == nullptr)
516
        return SECFailure;
517
518
    dest[n] = obj;
519
    dest[n+1] = nullptr;
520
    *array = dest;
521
    return SECSuccess;
522
}
523
524
SECOidTag
525
my_NSS_CMSAttribute_GetType(const NSSCMSAttribute *attr)
526
{
527
    SECOidData *typetag;
528
529
    typetag = SECOID_FindOID(&(attr->type));
530
    if (typetag == nullptr)
531
        return SEC_OID_UNKNOWN;
532
533
    return typetag->offset;
534
}
535
536
SECStatus
537
my_NSS_CMSAttributeArray_AddAttr(PLArenaPool *poolp, NSSCMSAttribute ***attrs, NSSCMSAttribute *attr)
538
{
539
    NSSCMSAttribute *oattr;
540
    void *mark;
541
    SECOidTag type;
542
543
    mark = PORT_ArenaMark(poolp);
544
545
    /* find oidtag of attr */
546
    type = my_NSS_CMSAttribute_GetType(attr);
547
548
    /* see if we have one already */
549
    oattr = my_NSS_CMSAttributeArray_FindAttrByOidTag(*attrs, type, PR_FALSE);
550
    PORT_Assert (oattr == NULL);
551
    if (oattr != nullptr)
552
        goto loser; /* XXX or would it be better to replace it? */
553
554
    /* no, shove it in */
555
    if (my_NSS_CMSArray_Add(poolp, reinterpret_cast<void ***>(attrs), static_cast<void *>(attr)) != SECSuccess)
556
        goto loser;
557
558
    PORT_ArenaUnmark(poolp, mark);
559
    return SECSuccess;
560
561
loser:
562
    PORT_ArenaRelease(poolp, mark);
563
    return SECFailure;
564
}
565
566
SECStatus
567
my_NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
568
{
569
    return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
570
}
571
572
NSSCMSMessage *CreateCMSMessage(const PRTime* time,
573
                                NSSCMSSignedData **cms_sd,
574
                                NSSCMSSignerInfo **cms_signer,
575
                                CERTCertificate *cert,
576
                                SECItem *digest)
577
{
578
    NSSCMSMessage *result = NSS_CMSMessage_Create(nullptr);
579
    if (!result)
580
    {
581
        SAL_WARN("svl.crypto", "NSS_CMSMessage_Create failed");
582
        return nullptr;
583
    }
584
585
    *cms_sd = NSS_CMSSignedData_Create(result);
586
    if (!*cms_sd)
587
    {
588
        SAL_WARN("svl.crypto", "NSS_CMSSignedData_Create failed");
589
        NSS_CMSMessage_Destroy(result);
590
        return nullptr;
591
    }
592
593
    NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(result);
594
    if (NSS_CMSContentInfo_SetContent_SignedData(result, cms_cinfo, *cms_sd) != SECSuccess)
595
    {
596
        SAL_WARN("svl.crypto", "NSS_CMSContentInfo_SetContent_SignedData failed");
597
        NSS_CMSSignedData_Destroy(*cms_sd);
598
        NSS_CMSMessage_Destroy(result);
599
        return nullptr;
600
    }
601
602
    cms_cinfo = NSS_CMSSignedData_GetContentInfo(*cms_sd);
603
604
    // Attach NULL data as detached data
605
    if (NSS_CMSContentInfo_SetContent_Data(result, cms_cinfo, nullptr, PR_TRUE) != SECSuccess)
606
    {
607
        SAL_WARN("svl.crypto", "NSS_CMSContentInfo_SetContent_Data failed");
608
        NSS_CMSSignedData_Destroy(*cms_sd);
609
        NSS_CMSMessage_Destroy(result);
610
        return nullptr;
611
    }
612
613
    // workaround: with legacy "dbm:", NSS can't find the private key - try out
614
    // if it works, and fallback if it doesn't.
615
    if (SECKEYPrivateKey * pPrivateKey = PK11_FindKeyByAnyCert(cert, nullptr))
616
    {
617
        if (!comphelper::LibreOfficeKit::isActive())
618
        {
619
            // pPrivateKey only exists in the memory in the LOK case, don't delete it.
620
            SECKEY_DestroyPrivateKey(pPrivateKey);
621
        }
622
        *cms_signer = NSS_CMSSignerInfo_Create(result, cert, SEC_OID_SHA256);
623
    }
624
    else
625
    {
626
        pPrivateKey = PK11_FindKeyByDERCert(cert->slot, cert, nullptr);
627
        SECKEYPublicKey *const pPublicKey = CERT_ExtractPublicKey(cert);
628
        if (pPublicKey && pPrivateKey)
629
        {
630
            *cms_signer = NSS_CMSSignerInfo_CreateWithSubjKeyID(result, &cert->subjectKeyID, pPublicKey, pPrivateKey, SEC_OID_SHA256);
631
            SECKEY_DestroyPrivateKey(pPrivateKey);
632
            SECKEY_DestroyPublicKey(pPublicKey);
633
            if (*cms_signer)
634
            {
635
                // this is required in NSS_CMSSignerInfo_IncludeCerts()
636
                // (and NSS_CMSSignerInfo_GetSigningCertificate() doesn't work)
637
                (**cms_signer).cert = CERT_DupCertificate(cert);
638
            }
639
        }
640
    }
641
    if (!*cms_signer)
642
    {
643
        SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_Create failed");
644
        NSS_CMSSignedData_Destroy(*cms_sd);
645
        NSS_CMSMessage_Destroy(result);
646
        return nullptr;
647
    }
648
649
    if (time && NSS_CMSSignerInfo_AddSigningTime(*cms_signer, *time) != SECSuccess)
650
    {
651
        SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_AddSigningTime failed");
652
        NSS_CMSSignedData_Destroy(*cms_sd);
653
        NSS_CMSMessage_Destroy(result);
654
        return nullptr;
655
    }
656
657
    if (NSS_CMSSignerInfo_IncludeCerts(*cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
658
    {
659
        SAL_WARN("svl.crypto", "NSS_CMSSignerInfo_IncludeCerts failed");
660
        NSS_CMSSignedData_Destroy(*cms_sd);
661
        NSS_CMSMessage_Destroy(result);
662
        return nullptr;
663
    }
664
665
    if (NSS_CMSSignedData_AddSignerInfo(*cms_sd, *cms_signer) != SECSuccess)
666
    {
667
        SAL_WARN("svl.crypto", "NSS_CMSSignedData_AddSignerInfo failed");
668
        NSS_CMSSignedData_Destroy(*cms_sd);
669
        NSS_CMSMessage_Destroy(result);
670
        return nullptr;
671
    }
672
673
    if (NSS_CMSSignedData_SetDigestValue(*cms_sd, SEC_OID_SHA256, digest) != SECSuccess)
674
    {
675
        SAL_WARN("svl.crypto", "NSS_CMSSignedData_SetDigestValue failed");
676
        NSS_CMSSignedData_Destroy(*cms_sd);
677
        NSS_CMSMessage_Destroy(result);
678
        return nullptr;
679
    }
680
681
    return result;
682
}
683
684
#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
685
686
/// Counts how many bytes are needed to encode a given length.
687
size_t GetDERLengthOfLength(size_t nLength)
688
{
689
    size_t nRet = 1;
690
691
    if(nLength > 127)
692
    {
693
        while (nLength >> (nRet * 8))
694
            ++nRet;
695
        // Long form means one additional byte: the length of the length and
696
        // the length itself.
697
        ++nRet;
698
    }
699
    return nRet;
700
}
701
702
/// Writes the length part of the header.
703
void WriteDERLength(SvStream& rStream, size_t nLength)
704
{
705
    size_t nLengthOfLength = GetDERLengthOfLength(nLength);
706
    if (nLengthOfLength == 1)
707
    {
708
        // We can use the short form.
709
        rStream.WriteUInt8(nLength);
710
        return;
711
    }
712
713
    // 0x80 means that the we use the long form: the first byte is the length
714
    // of length with the highest bit set to 1, not the actual length.
715
    rStream.WriteUInt8(0x80 | (nLengthOfLength - 1));
716
    for (size_t i = 1; i < nLengthOfLength; ++i)
717
        rStream.WriteUInt8(nLength >> ((nLengthOfLength - i - 1) * 8));
718
}
719
720
const unsigned nASN1_INTEGER = 0x02;
721
const unsigned nASN1_OCTET_STRING = 0x04;
722
const unsigned nASN1_NULL = 0x05;
723
const unsigned nASN1_OBJECT_IDENTIFIER = 0x06;
724
const unsigned nASN1_SEQUENCE = 0x10;
725
/// An explicit tag on a constructed value.
726
const unsigned nASN1_TAGGED_CONSTRUCTED = 0xa0;
727
const unsigned nASN1_CONSTRUCTED = 0x20;
728
729
/// Create payload for the 'signing-certificate' signed attribute.
730
bool CreateSigningCertificateAttribute(void const * pDerEncoded, int nDerEncoded, PCCERT_CONTEXT pCertContext, SvStream& rEncodedCertificate)
731
{
732
    // CryptEncodeObjectEx() does not support encoding arbitrary ASN.1
733
    // structures, like SigningCertificateV2 from RFC 5035, so let's build it
734
    // manually.
735
736
    // Count the certificate hash and put it to aHash.
737
    // 2.16.840.1.101.3.4.2.1, i.e. sha256.
738
    std::vector<unsigned char> aSHA256{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};
739
740
    HCRYPTPROV hProv = 0;
741
    if (!CryptAcquireContextW(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
742
    {
743
        SAL_WARN("svl.crypto", "CryptAcquireContext() failed");
744
        return false;
745
    }
746
747
    HCRYPTHASH hHash = 0;
748
    if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
749
    {
750
        SAL_WARN("svl.crypto", "CryptCreateHash() failed");
751
        return false;
752
    }
753
754
    if (!CryptHashData(hHash, static_cast<const BYTE*>(pDerEncoded), nDerEncoded, 0))
755
    {
756
        SAL_WARN("svl.crypto", "CryptHashData() failed");
757
        return false;
758
    }
759
760
    DWORD nHash = 0;
761
    if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nHash, 0))
762
    {
763
        SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash length");
764
        return false;
765
    }
766
767
    std::vector<unsigned char> aHash(nHash);
768
    if (!CryptGetHashParam(hHash, HP_HASHVAL, aHash.data(), &nHash, 0))
769
    {
770
        SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash");
771
        return false;
772
    }
773
774
    CryptDestroyHash(hHash);
775
    CryptReleaseContext(hProv, 0);
776
777
    // Collect info for IssuerSerial.
778
    BYTE* pIssuer = pCertContext->pCertInfo->Issuer.pbData;
779
    DWORD nIssuer = pCertContext->pCertInfo->Issuer.cbData;
780
    BYTE* pSerial = pCertContext->pCertInfo->SerialNumber.pbData;
781
    DWORD nSerial = pCertContext->pCertInfo->SerialNumber.cbData;
782
    // pSerial is LE, aSerial is BE.
783
    std::vector<BYTE> aSerial(nSerial);
784
    for (size_t i = 0; i < nSerial; ++i)
785
        aSerial[i] = *(pSerial + nSerial - i - 1);
786
787
    // We now have all the info to count the lengths.
788
    // The layout of the payload is:
789
    // SEQUENCE: SigningCertificateV2
790
    //     SEQUENCE: SEQUENCE OF ESSCertIDv2
791
    //         SEQUENCE: ESSCertIDv2
792
    //             SEQUENCE: AlgorithmIdentifier
793
    //                 OBJECT: algorithm
794
    //                 NULL: parameters
795
    //             OCTET STRING: certHash
796
    //             SEQUENCE: IssuerSerial
797
    //                 SEQUENCE: GeneralNames
798
    //                     cont [ 4 ]: Name
799
    //                         SEQUENCE: Issuer blob
800
    //                 INTEGER: CertificateSerialNumber
801
802
    size_t nAlgorithm = 1 + GetDERLengthOfLength(aSHA256.size()) + aSHA256.size();
803
    size_t nParameters = 1 + GetDERLengthOfLength(1);
804
    size_t nAlgorithmIdentifier = 1 + GetDERLengthOfLength(nAlgorithm + nParameters) + nAlgorithm + nParameters;
805
    size_t nCertHash = 1 + GetDERLengthOfLength(aHash.size()) + aHash.size();
806
    size_t nName = 1 + GetDERLengthOfLength(nIssuer) + nIssuer;
807
    size_t nGeneralNames = 1 + GetDERLengthOfLength(nName) + nName;
808
    size_t nCertificateSerialNumber = 1 + GetDERLengthOfLength(nSerial) + nSerial;
809
    size_t nIssuerSerial = 1 + GetDERLengthOfLength(nGeneralNames + nCertificateSerialNumber) + nGeneralNames + nCertificateSerialNumber;
810
    size_t nESSCertIDv2 = 1 + GetDERLengthOfLength(nAlgorithmIdentifier + nCertHash + nIssuerSerial) + nAlgorithmIdentifier + nCertHash + nIssuerSerial;
811
    size_t nESSCertIDv2s = 1 + GetDERLengthOfLength(nESSCertIDv2) + nESSCertIDv2;
812
813
    // Write SigningCertificateV2.
814
    rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
815
    WriteDERLength(rEncodedCertificate, nESSCertIDv2s);
816
    // Write SEQUENCE OF ESSCertIDv2.
817
    rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
818
    WriteDERLength(rEncodedCertificate, nESSCertIDv2);
819
    // Write ESSCertIDv2.
820
    rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
821
    WriteDERLength(rEncodedCertificate, nAlgorithmIdentifier + nCertHash + nIssuerSerial);
822
    // Write AlgorithmIdentifier.
823
    rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
824
    WriteDERLength(rEncodedCertificate, nAlgorithm + nParameters);
825
    // Write algorithm.
826
    rEncodedCertificate.WriteUInt8(nASN1_OBJECT_IDENTIFIER);
827
    WriteDERLength(rEncodedCertificate, aSHA256.size());
828
    rEncodedCertificate.WriteBytes(aSHA256.data(), aSHA256.size());
829
    // Write parameters.
830
    rEncodedCertificate.WriteUInt8(nASN1_NULL);
831
    rEncodedCertificate.WriteUInt8(0);
832
    // Write certHash.
833
    rEncodedCertificate.WriteUInt8(nASN1_OCTET_STRING);
834
    WriteDERLength(rEncodedCertificate, aHash.size());
835
    rEncodedCertificate.WriteBytes(aHash.data(), aHash.size());
836
    // Write IssuerSerial.
837
    rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
838
    WriteDERLength(rEncodedCertificate, nGeneralNames + nCertificateSerialNumber);
839
    // Write GeneralNames.
840
    rEncodedCertificate.WriteUInt8(nASN1_SEQUENCE | nASN1_CONSTRUCTED);
841
    WriteDERLength(rEncodedCertificate, nName);
842
    // Write Name.
843
    rEncodedCertificate.WriteUInt8(nASN1_TAGGED_CONSTRUCTED | 4);
844
    WriteDERLength(rEncodedCertificate, nIssuer);
845
    rEncodedCertificate.WriteBytes(pIssuer, nIssuer);
846
    // Write CertificateSerialNumber.
847
    rEncodedCertificate.WriteUInt8(nASN1_INTEGER);
848
    WriteDERLength(rEncodedCertificate, nSerial);
849
    rEncodedCertificate.WriteBytes(aSerial.data(), aSerial.size());
850
851
    return true;
852
}
853
#endif // USE_CRYPTO_MSCAPI
854
855
} // anonymous namespace
856
857
namespace svl::crypto {
858
859
std::vector<unsigned char> DecodeHexString(std::string_view rHex)
860
0
{
861
0
    std::vector<unsigned char> aRet;
862
0
    size_t nHexLen = rHex.size();
863
0
    {
864
0
        int nByte = 0;
865
0
        int nCount = 2;
866
0
        for (size_t i = 0; i < nHexLen; ++i)
867
0
        {
868
0
            nByte = nByte << 4;
869
0
            sal_Int8 nParsed = o3tl::convertToHex<int>(rHex[i]);
870
0
            if (nParsed == -1)
871
0
            {
872
0
                SAL_WARN("svl.crypto", "DecodeHexString: invalid hex value");
873
0
                return aRet;
874
0
            }
875
0
            nByte += nParsed;
876
0
            --nCount;
877
0
            if (!nCount)
878
0
            {
879
0
                aRet.push_back(nByte);
880
0
                nCount = 2;
881
0
                nByte = 0;
882
0
            }
883
0
        }
884
0
    }
885
886
0
    return aRet;
887
0
}
888
889
bool Signing::Sign(OStringBuffer& rCMSHexBuffer)
890
0
{
891
0
#if !USE_CRYPTO_ANY
892
0
    (void)rCMSHexBuffer;
893
0
    (void)m_rSigningContext;
894
0
    return false;
895
#else
896
    // Create the PKCS#7 object.
897
    css::uno::Sequence<sal_Int8> aDerEncoded;
898
    if (m_rSigningContext.m_xCertificate.is())
899
    {
900
        aDerEncoded = m_rSigningContext.m_xCertificate->getEncoded();
901
        if (!aDerEncoded.hasElements())
902
        {
903
            SAL_WARN("svl.crypto", "Crypto::Signing: empty certificate");
904
            return false;
905
        }
906
    }
907
908
#if USE_CRYPTO_NSS
909
    std::vector<unsigned char> aHashResult;
910
    {
911
        comphelper::Hash aHash(comphelper::HashType::SHA256);
912
913
        for (const auto& pair : m_dataBlocks)
914
            aHash.update(pair.first, pair.second);
915
916
        aHashResult = aHash.finalize();
917
    }
918
    SECItem digest;
919
    digest.data = aHashResult.data();
920
    digest.len = aHashResult.size();
921
922
    PRTime now = PR_Now();
923
924
    // The context unit is milliseconds, PR_Now() unit is microseconds.
925
    if (m_rSigningContext.m_nSignatureTime)
926
    {
927
        now = m_rSigningContext.m_nSignatureTime * 1000;
928
    }
929
    else
930
    {
931
        m_rSigningContext.m_nSignatureTime = now / 1000;
932
    }
933
934
    if (!m_rSigningContext.m_xCertificate.is())
935
    {
936
        m_rSigningContext.m_aDigest = std::move(aHashResult);
937
        // No certificate is provided: don't actually sign -- just update the context with the
938
        // parameters for the signing and return.
939
        return false;
940
    }
941
942
    CERTCertificate *cert = CERT_DecodeCertFromPackage(reinterpret_cast<char *>(aDerEncoded.getArray()), aDerEncoded.getLength());
943
944
    if (!cert)
945
    {
946
        SAL_WARN("svl.crypto", "CERT_DecodeCertFromPackage failed");
947
        return false;
948
    }
949
950
    NSSCMSSignedData *cms_sd(nullptr);
951
    NSSCMSSignerInfo *cms_signer(nullptr);
952
    NSSCMSMessage *cms_msg = CreateCMSMessage(nullptr, &cms_sd, &cms_signer, cert, &digest);
953
    if (!cms_msg)
954
        return false;
955
956
    OString pass(OUStringToOString( m_aSignPassword, RTL_TEXTENCODING_UTF8 ));
957
958
    // Add the signing certificate as a signed attribute.
959
    ESSCertIDv2* aCertIDs[2];
960
    ESSCertIDv2 aCertID;
961
    // Write ESSCertIDv2.hashAlgorithm.
962
    aCertID.hashAlgorithm.algorithm.data = nullptr;
963
    aCertID.hashAlgorithm.parameters.data = nullptr;
964
    SECOID_SetAlgorithmID(nullptr, &aCertID.hashAlgorithm, SEC_OID_SHA256, nullptr);
965
    comphelper::ScopeGuard aAlgoGuard(
966
        [&aCertID] () { SECOID_DestroyAlgorithmID(&aCertID.hashAlgorithm, false); } );
967
    // Write ESSCertIDv2.certHash.
968
    SECItem aCertHashItem;
969
    auto pDerEncoded = reinterpret_cast<const unsigned char *>(aDerEncoded.getArray());
970
    std::vector<unsigned char> aCertHashResult = comphelper::Hash::calculateHash(pDerEncoded, aDerEncoded.getLength(), comphelper::HashType::SHA256);
971
    aCertHashItem.type = siBuffer;
972
    aCertHashItem.data = aCertHashResult.data();
973
    aCertHashItem.len = aCertHashResult.size();
974
    aCertID.certHash = aCertHashItem;
975
    // Write ESSCertIDv2.issuerSerial.
976
    IssuerSerial aSerial;
977
    GeneralName aName;
978
    aName.name = cert->issuer;
979
    aSerial.issuer.names = aName;
980
    aSerial.serialNumber = cert->serialNumber;
981
    aCertID.issuerSerial = aSerial;
982
    // Write SigningCertificateV2.certs.
983
    aCertIDs[0] = &aCertID;
984
    aCertIDs[1] = nullptr;
985
    SigningCertificateV2 aCertificate;
986
    aCertificate.certs = &aCertIDs[0];
987
    SECItem* pEncodedCertificate = SEC_ASN1EncodeItem(nullptr, nullptr, &aCertificate, SigningCertificateV2Template);
988
    if (!pEncodedCertificate)
989
    {
990
        SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem() failed");
991
        return false;
992
    }
993
994
    NSSCMSAttribute aAttribute;
995
    SECItem aAttributeValues[2];
996
    SECItem* pAttributeValues[2];
997
    pAttributeValues[0] = aAttributeValues;
998
    pAttributeValues[1] = nullptr;
999
    aAttributeValues[0] = *pEncodedCertificate;
1000
    aAttributeValues[1].type = siBuffer;
1001
    aAttributeValues[1].data = nullptr;
1002
    aAttributeValues[1].len = 0;
1003
    aAttribute.values = pAttributeValues;
1004
1005
    SECOidData aOidData;
1006
    auto cert_oid_buffer = std::to_array(OID_SIGNINGCERTIFICATEV2);
1007
    aOidData.oid.data = cert_oid_buffer.data();
1008
    aOidData.oid.len = cert_oid_buffer.size();
1009
    /*
1010
     * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1011
     * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1012
     *   smime(16) id-aa(2) 47 }
1013
     */
1014
    aOidData.offset = SEC_OID_UNKNOWN;
1015
    aOidData.desc = "id-aa-signingCertificateV2";
1016
    aOidData.mechanism = CKM_SHA_1;
1017
    aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
1018
    aAttribute.typeTag = &aOidData;
1019
    aAttribute.type = aOidData.oid;
1020
    aAttribute.encoded = PR_TRUE;
1021
1022
    if (my_NSS_CMSSignerInfo_AddAuthAttr(cms_signer, &aAttribute) != SECSuccess)
1023
    {
1024
        SAL_WARN("svl.crypto", "my_NSS_CMSSignerInfo_AddAuthAttr() failed");
1025
        return false;
1026
    }
1027
1028
    SECItem cms_output;
1029
    cms_output.data = nullptr;
1030
    cms_output.len = 0;
1031
    PLArenaPool *arena = PORT_NewArena(10000);
1032
    const ::comphelper::ScopeGuard aScopeGuard(
1033
        [&arena]() mutable { PORT_FreeArena(arena, true); } );
1034
    NSSCMSEncoderContext *cms_ecx;
1035
1036
    // Possibly it would work to even just pass NULL for the password callback function and its
1037
    // argument here. After all, at least with the hardware token and associated software I tested
1038
    // with, the software itself pops up a dialog asking for the PIN (password). But I am not going
1039
    // to test it and risk locking up my token...
1040
1041
    cms_ecx = NSS_CMSEncoder_Start(cms_msg, nullptr, nullptr, &cms_output, arena, PDFSigningPKCS7PasswordCallback,
1042
                                   const_cast<char*>(pass.getStr()), nullptr, nullptr, nullptr, nullptr);
1043
1044
    if (!cms_ecx)
1045
    {
1046
        SAL_WARN("svl.crypto", "NSS_CMSEncoder_Start failed");
1047
        return false;
1048
    }
1049
1050
    if (NSS_CMSEncoder_Finish(cms_ecx) != SECSuccess)
1051
    {
1052
        SAL_WARN("svl.crypto", "NSS_CMSEncoder_Finish failed");
1053
        return false;
1054
    }
1055
1056
    if( !m_aSignTSA.isEmpty() )
1057
    {
1058
        TimeStampReq src;
1059
        OStringBuffer response_buffer;
1060
        TimeStampResp response;
1061
        SECItem response_item;
1062
        cms_recode_attribute timestamp;
1063
        SECItem values[2];
1064
        SECItem *valuesp[2];
1065
        valuesp[0] = values;
1066
        valuesp[1] = nullptr;
1067
1068
        std::vector<unsigned char> aTsHashResult = comphelper::Hash::calculateHash(cms_signer->encDigest.data, cms_signer->encDigest.len, comphelper::HashType::SHA256);
1069
        SECItem ts_digest;
1070
        ts_digest.type = siBuffer;
1071
        ts_digest.data = aTsHashResult.data();
1072
        ts_digest.len = aTsHashResult.size();
1073
1074
        unsigned char cOne = 1;
1075
        unsigned char cTRUE = 0xff; // under DER rules true is 0xff, false is 0x00
1076
        src.version.type = siUnsignedInteger;
1077
        src.version.data = &cOne;
1078
        src.version.len = sizeof(cOne);
1079
1080
        src.messageImprint.hashAlgorithm.algorithm.data = nullptr;
1081
        src.messageImprint.hashAlgorithm.parameters.data = nullptr;
1082
        SECOID_SetAlgorithmID(arena, &src.messageImprint.hashAlgorithm, SEC_OID_SHA256, nullptr);
1083
        src.messageImprint.hashedMessage = ts_digest;
1084
1085
        src.reqPolicy.type = siBuffer;
1086
        src.reqPolicy.data = nullptr;
1087
        src.reqPolicy.len = 0;
1088
1089
        unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
1090
        src.nonce.type = siUnsignedInteger;
1091
        src.nonce.data = reinterpret_cast<unsigned char*>(&nNonce);
1092
        src.nonce.len = sizeof(nNonce);
1093
1094
        src.certReq.type = siUnsignedInteger;
1095
        src.certReq.data = &cTRUE;
1096
        src.certReq.len = sizeof(cTRUE);
1097
1098
        src.extensions = nullptr;
1099
1100
        SECItem* timestamp_request = SEC_ASN1EncodeItem(nullptr, nullptr, &src, TimeStampReq_Template);
1101
        if (timestamp_request == nullptr)
1102
        {
1103
            SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem failed");
1104
            return false;
1105
        }
1106
1107
        if (timestamp_request->data == nullptr)
1108
        {
1109
            SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem succeeded but got NULL data");
1110
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1111
            return false;
1112
        }
1113
1114
        SAL_INFO("svl.crypto", "request length=" << timestamp_request->len);
1115
1116
        // Send time stamp request to TSA server, receive response
1117
1118
        CURL* curl = curl_easy_init();
1119
        CURLcode rc;
1120
        struct curl_slist* slist = nullptr;
1121
1122
        if (!curl)
1123
        {
1124
            SAL_WARN("svl.crypto", "curl_easy_init failed");
1125
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1126
            return false;
1127
        }
1128
1129
        ::InitCurl_easy(curl);
1130
1131
        SAL_INFO("svl.crypto", "Setting curl to verbose: " << (curl_easy_setopt(curl, CURLOPT_VERBOSE, 1) == CURLE_OK ? "OK" : "FAIL"));
1132
1133
        if ((rc = curl_easy_setopt(curl, CURLOPT_URL, OUStringToOString(m_aSignTSA, RTL_TEXTENCODING_UTF8).getStr())) != CURLE_OK)
1134
        {
1135
            SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_URL) failed: " << curl_easy_strerror(rc));
1136
            curl_easy_cleanup(curl);
1137
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1138
            return false;
1139
        }
1140
1141
        slist = curl_slist_append(slist, "Content-Type: application/timestamp-query");
1142
        slist = curl_slist_append(slist, "Accept: application/timestamp-reply");
1143
1144
        if ((rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist)) != CURLE_OK)
1145
        {
1146
            SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_HTTPHEADER) failed: " << curl_easy_strerror(rc));
1147
            curl_slist_free_all(slist);
1148
            curl_easy_cleanup(curl);
1149
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1150
            return false;
1151
        }
1152
1153
        if ((rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, static_cast<tools::Long>(timestamp_request->len))) != CURLE_OK ||
1154
            (rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, timestamp_request->data)) != CURLE_OK)
1155
        {
1156
            SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDS) failed: " << curl_easy_strerror(rc));
1157
            curl_easy_cleanup(curl);
1158
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1159
            return false;
1160
        }
1161
1162
        if ((rc = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer)) != CURLE_OK ||
1163
            (rc = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToBuffer)) != CURLE_OK)
1164
        {
1165
            SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_WRITEDATA or CURLOPT_WRITEFUNCTION) failed: " << curl_easy_strerror(rc));
1166
            curl_easy_cleanup(curl);
1167
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1168
            return false;
1169
        }
1170
1171
        if ((rc = curl_easy_setopt(curl, CURLOPT_POST, 1)) != CURLE_OK)
1172
        {
1173
            SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_POST) failed: " << curl_easy_strerror(rc));
1174
            curl_easy_cleanup(curl);
1175
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1176
            return false;
1177
        }
1178
1179
        char error_buffer[CURL_ERROR_SIZE];
1180
        if ((rc = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer)) != CURLE_OK)
1181
        {
1182
            SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_ERRORBUFFER) failed: " << curl_easy_strerror(rc));
1183
            curl_easy_cleanup(curl);
1184
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1185
            return false;
1186
        }
1187
1188
        // Use a ten second timeout
1189
        if ((rc = curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10)) != CURLE_OK ||
1190
            (rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10)) != CURLE_OK)
1191
        {
1192
            SAL_WARN("svl.crypto", "curl_easy_setopt(CURLOPT_TIMEOUT or CURLOPT_CONNECTTIMEOUT) failed: " << curl_easy_strerror(rc));
1193
            curl_easy_cleanup(curl);
1194
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1195
            return false;
1196
        }
1197
1198
        if (curl_easy_perform(curl) != CURLE_OK)
1199
        {
1200
            SAL_WARN("svl.crypto", "curl_easy_perform failed: " << error_buffer);
1201
            curl_easy_cleanup(curl);
1202
            SECITEM_FreeItem(timestamp_request, PR_TRUE);
1203
            return false;
1204
        }
1205
1206
        SAL_INFO("svl.crypto", "PDF signing: got response, length=" << response_buffer.getLength());
1207
1208
        curl_slist_free_all(slist);
1209
        curl_easy_cleanup(curl);
1210
        SECITEM_FreeItem(timestamp_request, PR_TRUE);
1211
1212
        memset(&response, 0, sizeof(response));
1213
1214
        response_item.type = siBuffer;
1215
        response_item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(response_buffer.getStr()));
1216
        response_item.len = response_buffer.getLength();
1217
1218
        if (SEC_ASN1DecodeItem(arena, &response, TimeStampResp_Template, &response_item) != SECSuccess)
1219
        {
1220
            SAL_WARN("svl.crypto", "SEC_ASN1DecodeItem failed");
1221
            return false;
1222
        }
1223
1224
        SAL_INFO("svl.crypto", "TimeStampResp received and decoded, status=" << PKIStatusInfoToString(response.status));
1225
1226
        if (response.status.status.len != 1 ||
1227
            (response.status.status.data[0] != 0 && response.status.status.data[0] != 1))
1228
        {
1229
            SAL_WARN("svl.crypto", "Timestamp request was not granted");
1230
            return false;
1231
        }
1232
1233
        // timestamp.type filled in below
1234
1235
        // Not sure if we actually need two entries in the values array, now when valuesp is an
1236
        // array too, the pointer to the values array followed by a null pointer. But I don't feel
1237
        // like experimenting.
1238
        values[0] = response.timeStampToken;
1239
        values[1].type = siBuffer;
1240
        values[1].data = nullptr;
1241
        values[1].len = 0;
1242
1243
        timestamp.values = valuesp;
1244
1245
        auto ts_oid_buffer = std::to_array(OID_TIMESTAMPTOKEN);
1246
        // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1)
1247
        // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)
1248
        // smime(16) aa(2) 14 }
1249
1250
        timestamp.type.data = ts_oid_buffer.data();
1251
        timestamp.type.len =  ts_oid_buffer.size();
1252
1253
        cms_recode_message decoded_cms_output {};
1254
1255
        if (SEC_ASN1DecodeItem(arena, &decoded_cms_output, recode_message_template, &cms_output) != SECSuccess)
1256
        {
1257
            SAL_WARN("svl.crypto", "SEC_ASN1DecodeItem failed");
1258
            return false;
1259
        }
1260
1261
        // now insert the new attribute
1262
1263
        cms_recode_signer_info **decoded_signerinfos = decoded_cms_output.signedData.signerInfos;
1264
        if (!decoded_signerinfos || !*decoded_signerinfos) {
1265
            SAL_WARN("svl.crypto", "Decoded signed message invalid");
1266
            return false;
1267
        }
1268
1269
        std::vector<cms_recode_attribute *> updated_attrs;
1270
1271
        // there are no unauthenticated attributes at the moment
1272
        // if this ever changes, make sure to preserve them
1273
        cms_recode_attribute **existing_attrs = (*decoded_signerinfos)->unAuthAttr ;
1274
1275
        if (existing_attrs)
1276
            while (*existing_attrs)
1277
                updated_attrs.push_back(*existing_attrs++);
1278
1279
        updated_attrs.push_back(&timestamp);
1280
        updated_attrs.push_back(nullptr);
1281
1282
        (*decoded_signerinfos)->unAuthAttr = updated_attrs.data();
1283
1284
        SECItem * ts_cms_output = SEC_ASN1EncodeItem(arena, nullptr, &decoded_cms_output, recode_message_template);
1285
        if (!ts_cms_output)
1286
        {
1287
            SAL_WARN("svl.crypto", "SEC_ASN1EncodeItem failed");
1288
            return false;
1289
        }
1290
1291
        cms_output = *ts_cms_output;
1292
    }
1293
1294
    if (cms_output.len*2 > MAX_SIGNATURE_CONTENT_LENGTH)
1295
    {
1296
        SAL_WARN("svl.crypto", "Signature requires more space (" << cms_output.len*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
1297
        NSS_CMSMessage_Destroy(cms_msg);
1298
        return false;
1299
    }
1300
1301
    for (unsigned int i = 0; i < cms_output.len ; i++)
1302
        appendHex(cms_output.data[i], rCMSHexBuffer);
1303
1304
    SECITEM_FreeItem(pEncodedCertificate, PR_TRUE);
1305
    NSS_CMSMessage_Destroy(cms_msg);
1306
1307
    return true;
1308
1309
#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
1310
1311
    PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(aDerEncoded.getArray()), aDerEncoded.getLength());
1312
    if (pCertContext == nullptr)
1313
    {
1314
        SAL_WARN("svl.crypto", "CertCreateCertificateContext failed: " << comphelper::WindowsErrorString(GetLastError()));
1315
        return false;
1316
    }
1317
1318
    CRYPT_SIGN_MESSAGE_PARA aPara = {};
1319
    aPara.cbSize = sizeof(aPara);
1320
    aPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;
1321
    aPara.pSigningCert = pCertContext;
1322
    aPara.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256);
1323
    aPara.HashAlgorithm.Parameters.cbData = 0;
1324
    aPara.cMsgCert = 1;
1325
    aPara.rgpMsgCert = &pCertContext;
1326
1327
    NCRYPT_KEY_HANDLE hCryptKey = 0;
1328
    DWORD dwFlags = CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
1329
    HCRYPTPROV_OR_NCRYPT_KEY_HANDLE* phCryptProvOrNCryptKey = &hCryptKey;
1330
    DWORD nKeySpec;
1331
    BOOL bFreeNeeded;
1332
1333
    if (!CryptAcquireCertificatePrivateKey(pCertContext,
1334
                                           dwFlags,
1335
                                           nullptr,
1336
                                           phCryptProvOrNCryptKey,
1337
                                           &nKeySpec,
1338
                                           &bFreeNeeded))
1339
    {
1340
        SAL_WARN("svl.crypto", "CryptAcquireCertificatePrivateKey failed: " << comphelper::WindowsErrorString(GetLastError()));
1341
        CertFreeCertificateContext(pCertContext);
1342
        return false;
1343
    }
1344
    assert(!bFreeNeeded);
1345
1346
    CMSG_SIGNER_ENCODE_INFO aSignerInfo = {};
1347
    aSignerInfo.cbSize = sizeof(aSignerInfo);
1348
    aSignerInfo.pCertInfo = pCertContext->pCertInfo;
1349
    aSignerInfo.hNCryptKey = hCryptKey;
1350
    aSignerInfo.dwKeySpec = nKeySpec;
1351
    aSignerInfo.HashAlgorithm.pszObjId = const_cast<LPSTR>(szOID_NIST_sha256);
1352
    aSignerInfo.HashAlgorithm.Parameters.cbData = 0;
1353
1354
    // Add the signing certificate as a signed attribute.
1355
    CRYPT_INTEGER_BLOB aCertificateBlob;
1356
    SvMemoryStream aEncodedCertificate;
1357
    if (!CreateSigningCertificateAttribute(aDerEncoded.getArray(), aDerEncoded.getLength(), pCertContext, aEncodedCertificate))
1358
    {
1359
        SAL_WARN("svl.crypto", "CreateSigningCertificateAttribute() failed");
1360
        return false;
1361
    }
1362
    aCertificateBlob.pbData = const_cast<BYTE*>(static_cast<const BYTE*>(aEncodedCertificate.GetData()));
1363
    aCertificateBlob.cbData = aEncodedCertificate.GetSize();
1364
    CRYPT_ATTRIBUTE aCertificateAttribute;
1365
    /*
1366
     * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1367
     * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1368
     *   smime(16) id-aa(2) 47 }
1369
     */
1370
    aCertificateAttribute.pszObjId = const_cast<LPSTR>("1.2.840.113549.1.9.16.2.47");
1371
    aCertificateAttribute.cValue = 1;
1372
    aCertificateAttribute.rgValue = &aCertificateBlob;
1373
    aSignerInfo.cAuthAttr = 1;
1374
    aSignerInfo.rgAuthAttr = &aCertificateAttribute;
1375
1376
    CMSG_SIGNED_ENCODE_INFO aSignedInfo = {};
1377
    aSignedInfo.cbSize = sizeof(aSignedInfo);
1378
    aSignedInfo.cSigners = 1;
1379
    aSignedInfo.rgSigners = &aSignerInfo;
1380
1381
    CERT_BLOB aCertBlob;
1382
1383
    aCertBlob.cbData = pCertContext->cbCertEncoded;
1384
    aCertBlob.pbData = pCertContext->pbCertEncoded;
1385
1386
    aSignedInfo.cCertEncoded = 1;
1387
    aSignedInfo.rgCertEncoded = &aCertBlob;
1388
1389
    HCRYPTMSG hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1390
                                          CMSG_DETACHED_FLAG,
1391
                                          CMSG_SIGNED,
1392
                                          &aSignedInfo,
1393
                                          nullptr,
1394
                                          nullptr);
1395
    if (!hMsg)
1396
    {
1397
        SAL_WARN("svl.crypto", "CryptMsgOpenToEncode failed: " << comphelper::WindowsErrorString(GetLastError()));
1398
        CertFreeCertificateContext(pCertContext);
1399
        return false;
1400
    }
1401
1402
    for (size_t i = 0; i < m_dataBlocks.size(); ++i)
1403
    {
1404
        const bool last = (i == m_dataBlocks.size() - 1);
1405
        if (!CryptMsgUpdate(hMsg, static_cast<const BYTE *>(m_dataBlocks[i].first), m_dataBlocks[i].second, last))
1406
        {
1407
            SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << comphelper::WindowsErrorString(GetLastError()));
1408
            CryptMsgClose(hMsg);
1409
            CertFreeCertificateContext(pCertContext);
1410
            return false;
1411
        }
1412
    }
1413
    CertFreeCertificateContext(pCertContext);
1414
1415
    PCRYPT_TIMESTAMP_CONTEXT pTsContext = nullptr;
1416
    DWORD dwEncodedMessageParamType = CMSG_CONTENT_PARAM;
1417
1418
    if( !m_aSignTSA.isEmpty() )
1419
    {
1420
        HCRYPTMSG hDecodedMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1421
                                                     CMSG_DETACHED_FLAG,
1422
                                                     CMSG_SIGNED,
1423
                                                     0,
1424
                                                     nullptr,
1425
                                                     nullptr);
1426
        if (!hDecodedMsg)
1427
        {
1428
            SAL_WARN("svl.crypto", "CryptMsgOpenToDecode failed: " << comphelper::WindowsErrorString(GetLastError()));
1429
            CryptMsgClose(hMsg);
1430
            return false;
1431
        }
1432
1433
        DWORD nTsSigLen = 0;
1434
1435
        if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, nullptr, &nTsSigLen))
1436
        {
1437
            SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << comphelper::WindowsErrorString(GetLastError()));
1438
            CryptMsgClose(hDecodedMsg);
1439
            CryptMsgClose(hMsg);
1440
            return false;
1441
        }
1442
1443
        SAL_INFO("svl.crypto", "nTsSigLen=" << nTsSigLen);
1444
1445
        std::unique_ptr<BYTE[]> pTsSig(new BYTE[nTsSigLen]);
1446
1447
        if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, pTsSig.get(), &nTsSigLen))
1448
        {
1449
            SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << comphelper::WindowsErrorString(GetLastError()));
1450
            CryptMsgClose(hDecodedMsg);
1451
            CryptMsgClose(hMsg);
1452
            return false;
1453
        }
1454
1455
        CryptMsgClose(hMsg);
1456
1457
        if (!CryptMsgUpdate(hDecodedMsg, pTsSig.get(), nTsSigLen, TRUE))
1458
        {
1459
            SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << comphelper::WindowsErrorString(GetLastError()));
1460
            CryptMsgClose(hDecodedMsg);
1461
            return false;
1462
        }
1463
1464
        DWORD nDecodedSignerInfoLen = 0;
1465
        if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, nullptr, &nDecodedSignerInfoLen))
1466
        {
1467
            SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << comphelper::WindowsErrorString(GetLastError()));
1468
            CryptMsgClose(hDecodedMsg);
1469
            return false;
1470
        }
1471
1472
        std::unique_ptr<BYTE[]> pDecodedSignerInfoBuf(new BYTE[nDecodedSignerInfoLen]);
1473
1474
        if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, pDecodedSignerInfoBuf.get(), &nDecodedSignerInfoLen))
1475
        {
1476
            SAL_WARN("svl.crypto", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << comphelper::WindowsErrorString(GetLastError()));
1477
            CryptMsgClose(hDecodedMsg);
1478
            return false;
1479
        }
1480
1481
        CMSG_SIGNER_INFO *pDecodedSignerInfo = reinterpret_cast<CMSG_SIGNER_INFO *>(pDecodedSignerInfoBuf.get());
1482
1483
        CRYPT_TIMESTAMP_PARA aTsPara;
1484
        unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
1485
1486
        aTsPara.pszTSAPolicyId = nullptr;
1487
        aTsPara.fRequestCerts = TRUE;
1488
        aTsPara.Nonce.cbData = sizeof(nNonce);
1489
        aTsPara.Nonce.pbData = reinterpret_cast<BYTE *>(&nNonce);
1490
        aTsPara.cExtension = 0;
1491
        aTsPara.rgExtension = nullptr;
1492
1493
        if (!CryptRetrieveTimeStamp(o3tl::toW(m_aSignTSA.getStr()),
1494
                     0,
1495
                     10000,
1496
                     szOID_NIST_sha256,
1497
                     &aTsPara,
1498
                     pDecodedSignerInfo->EncryptedHash.pbData,
1499
                     pDecodedSignerInfo->EncryptedHash.cbData,
1500
                     &pTsContext,
1501
                     nullptr,
1502
                     nullptr))
1503
        {
1504
            SAL_WARN("svl.crypto", "CryptRetrieveTimeStamp failed: " << comphelper::WindowsErrorString(GetLastError()));
1505
            CryptMsgClose(hDecodedMsg);
1506
            return false;
1507
        }
1508
1509
        SAL_INFO("svl.crypto", "Time stamp size is " << pTsContext->cbEncoded << " bytes");
1510
1511
        CRYPT_INTEGER_BLOB aTimestampBlob;
1512
        aTimestampBlob.cbData = pTsContext->cbEncoded;
1513
        aTimestampBlob.pbData = pTsContext->pbEncoded;
1514
1515
        CRYPT_ATTRIBUTE aTimestampAttribute;
1516
        aTimestampAttribute.pszObjId = const_cast<LPSTR>(
1517
            "1.2.840.113549.1.9.16.2.14");
1518
        aTimestampAttribute.cValue = 1;
1519
        aTimestampAttribute.rgValue = &aTimestampBlob;
1520
1521
        DWORD nEncodedTsAttributeLen = 0;
1522
        if (!CryptEncodeObject(PKCS_7_ASN_ENCODING, PKCS_ATTRIBUTE, &aTimestampAttribute, nullptr, &nEncodedTsAttributeLen))
1523
        {
1524
            SAL_WARN("svl.crypto", "CryptEncodeObject(PKCS_ATTRIBUTE) failed: " << comphelper::WindowsErrorString(GetLastError()));
1525
            CryptMsgClose(hDecodedMsg);
1526
            return false;
1527
        }
1528
1529
        std::unique_ptr<BYTE[]> pEncodedTsAttributeBuf(new BYTE[nEncodedTsAttributeLen]);
1530
1531
        CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA aAddTsAttrPara;
1532
        aAddTsAttrPara.dwSignerIndex = 0;
1533
        aAddTsAttrPara.cbSize = sizeof(aAddTsAttrPara);
1534
1535
        if (!CryptEncodeObject(PKCS_7_ASN_ENCODING, PKCS_ATTRIBUTE, &aTimestampAttribute, pEncodedTsAttributeBuf.get(), &nEncodedTsAttributeLen))
1536
        {
1537
            SAL_WARN("svl.crypto", "CryptEncodeObject(PKCS_ATTRIBUTE) failed: " << comphelper::WindowsErrorString(GetLastError()));
1538
            CryptMsgClose(hDecodedMsg);
1539
            return false;
1540
        }
1541
1542
         aAddTsAttrPara.blob.cbData = nEncodedTsAttributeLen;
1543
         aAddTsAttrPara.blob.pbData = pEncodedTsAttributeBuf.get();
1544
1545
        if (!CryptMsgControl(hDecodedMsg, 0, CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, &aAddTsAttrPara))
1546
        {
1547
            SAL_WARN("svl.crypto", "CryptMsgControl(CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR) failed: " << comphelper::WindowsErrorString(GetLastError()));
1548
            CryptMsgClose(hDecodedMsg);
1549
            return false;
1550
        }
1551
        hMsg = hDecodedMsg;
1552
        dwEncodedMessageParamType = CMSG_ENCODED_MESSAGE;
1553
    }
1554
1555
    DWORD nSigLen = 0;
1556
1557
    if (!CryptMsgGetParam(hMsg, dwEncodedMessageParamType, 0, nullptr, &nSigLen))
1558
    {
1559
        SAL_WARN("svl.crypto", "Reading the encoded message via CryptMsgGetParam() failed: " << comphelper::WindowsErrorString(GetLastError()));
1560
        if (pTsContext)
1561
            CryptMemFree(pTsContext);
1562
        CryptMsgClose(hMsg);
1563
        return false;
1564
    }
1565
1566
    if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
1567
    {
1568
        SAL_WARN("svl.crypto", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
1569
        if (pTsContext)
1570
            CryptMemFree(pTsContext);
1571
        CryptMsgClose(hMsg);
1572
        return false;
1573
    }
1574
1575
    SAL_INFO("svl.crypto", "Signature size is " << nSigLen << " bytes");
1576
    std::unique_ptr<BYTE[]> pSig(new BYTE[nSigLen]);
1577
1578
    if (!CryptMsgGetParam(hMsg, dwEncodedMessageParamType, 0, pSig.get(), &nSigLen))
1579
    {
1580
        SAL_WARN("svl.crypto", "Reading the encoded message via CryptMsgGetParam() failed: " << comphelper::WindowsErrorString(GetLastError()));
1581
        if (pTsContext)
1582
            CryptMemFree(pTsContext);
1583
        CryptMsgClose(hMsg);
1584
        return false;
1585
    }
1586
1587
    // Release resources
1588
    if (pTsContext)
1589
        CryptMemFree(pTsContext);
1590
    CryptMsgClose(hMsg);
1591
1592
    for (unsigned int i = 0; i < nSigLen ; i++)
1593
        appendHex(pSig[i], rCMSHexBuffer);
1594
1595
    return true;
1596
#endif // USE_CRYPTO_MSCAPI
1597
#endif // USE_CRYPTO_ANY
1598
0
}
1599
1600
namespace
1601
{
1602
#if USE_CRYPTO_NSS
1603
/// Similar to NSS_CMSAttributeArray_FindAttrByOidTag(), but works directly with a SECOidData.
1604
NSSCMSAttribute* CMSAttributeArray_FindAttrByOidData(NSSCMSAttribute** attrs, SECOidData const * oid, PRBool only)
1605
{
1606
    NSSCMSAttribute* attr1, *attr2;
1607
1608
    if (attrs == nullptr)
1609
        return nullptr;
1610
1611
    if (oid == nullptr)
1612
        return nullptr;
1613
1614
    while ((attr1 = *attrs++) != nullptr)
1615
    {
1616
        if (attr1->type.len == oid->oid.len && PORT_Memcmp(attr1->type.data,
1617
                oid->oid.data,
1618
                oid->oid.len) == 0)
1619
            break;
1620
    }
1621
1622
    if (attr1 == nullptr)
1623
        return nullptr;
1624
1625
    if (!only)
1626
        return attr1;
1627
1628
    while ((attr2 = *attrs++) != nullptr)
1629
    {
1630
        if (attr2->type.len == oid->oid.len && PORT_Memcmp(attr2->type.data,
1631
                oid->oid.data,
1632
                oid->oid.len) == 0)
1633
            break;
1634
    }
1635
1636
    if (attr2 != nullptr)
1637
        return nullptr;
1638
1639
    return attr1;
1640
}
1641
1642
#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
1643
1644
/// Verifies a non-detached signature using CryptoAPI.
1645
bool VerifyNonDetachedSignature(const std::vector<unsigned char>& aData, const std::vector<BYTE>& rExpectedHash)
1646
{
1647
    HCRYPTPROV hProv = 0;
1648
    if (!CryptAcquireContextW(&hProv, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
1649
    {
1650
        SAL_WARN("svl.crypto", "CryptAcquireContext() failed");
1651
        return false;
1652
    }
1653
1654
    HCRYPTHASH hHash = 0;
1655
    if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash))
1656
    {
1657
        SAL_WARN("svl.crypto", "CryptCreateHash() failed");
1658
        return false;
1659
    }
1660
1661
    if (!CryptHashData(hHash, aData.data(), aData.size(), 0))
1662
    {
1663
        SAL_WARN("svl.crypto", "CryptHashData() failed");
1664
        return false;
1665
    }
1666
1667
    DWORD nActualHash = 0;
1668
    if (!CryptGetHashParam(hHash, HP_HASHVAL, nullptr, &nActualHash, 0))
1669
    {
1670
        SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash length");
1671
        return false;
1672
    }
1673
1674
    std::vector<unsigned char> aActualHash(nActualHash);
1675
    if (!CryptGetHashParam(hHash, HP_HASHVAL, aActualHash.data(), &nActualHash, 0))
1676
    {
1677
        SAL_WARN("svl.crypto", "CryptGetHashParam() failed to provide the hash");
1678
        return false;
1679
    }
1680
1681
    CryptDestroyHash(hHash);
1682
    CryptReleaseContext(hProv, 0);
1683
1684
    return aActualHash.size() == rExpectedHash.size() &&
1685
           !std::memcmp(aActualHash.data(), rExpectedHash.data(), aActualHash.size());
1686
}
1687
1688
OUString GetSubjectName(PCCERT_CONTEXT pCertContext)
1689
{
1690
    OUString subjectName;
1691
1692
    // Get Subject name size.
1693
    DWORD dwData = CertGetNameStringW(pCertContext,
1694
                                      CERT_NAME_SIMPLE_DISPLAY_TYPE,
1695
                                      0,
1696
                                      nullptr,
1697
                                      nullptr,
1698
                                      0);
1699
    if (!dwData)
1700
    {
1701
        SAL_WARN("svl.crypto", "ValidateSignature: CertGetNameString failed");
1702
        return subjectName;
1703
    }
1704
1705
    // Allocate memory for subject name.
1706
    LPWSTR szName = static_cast<LPWSTR>(
1707
        LocalAlloc(LPTR, dwData * sizeof(WCHAR)));
1708
    if (!szName)
1709
    {
1710
        SAL_WARN("svl.crypto", "ValidateSignature: Unable to allocate memory for subject name");
1711
        return subjectName;
1712
    }
1713
1714
    // Get subject name.
1715
    if (!CertGetNameStringW(pCertContext,
1716
                            CERT_NAME_SIMPLE_DISPLAY_TYPE,
1717
                            0,
1718
                            nullptr,
1719
                            szName,
1720
                            dwData))
1721
    {
1722
        LocalFree(szName);
1723
        SAL_WARN("svl.crypto", "ValidateSignature: CertGetNameString failed");
1724
        return subjectName;
1725
    }
1726
1727
    subjectName = o3tl::toU(szName);
1728
    LocalFree(szName);
1729
1730
    return subjectName;
1731
}
1732
#endif // USE_CRYPTO_MSCAPI
1733
1734
#if USE_CRYPTO_NSS
1735
    void ensureNssInit()
1736
    {
1737
        // e.g. tdf#122599 ensure NSS library is initialized for NSS_CMSMessage_CreateFromDER
1738
        css::uno::Reference<css::xml::crypto::XNSSInitializer>
1739
            xNSSInitializer = css::xml::crypto::NSSInitializer::create(comphelper::getProcessComponentContext());
1740
1741
        // this calls NSS_Init
1742
        xNSSInitializer->getDigestContext(css::xml::crypto::DigestID::SHA256,
1743
                                          uno::Sequence<beans::NamedValue>());
1744
    }
1745
#endif
1746
} // anonymous namespace
1747
1748
bool Signing::Verify(const std::vector<unsigned char>& aData,
1749
                     const bool bNonDetached,
1750
                     const std::vector<unsigned char>& aSignature,
1751
                     SignatureInformation& rInformation)
1752
0
{
1753
#if USE_CRYPTO_NSS
1754
    // ensure NSS_Init() is called before using NSS_CMSMessage_CreateFromDER
1755
    static std::once_flag aInitOnce;
1756
    std::call_once(aInitOnce, ensureNssInit);
1757
1758
    // Validate the signature.
1759
    SECItem aSignatureItem;
1760
    aSignatureItem.data = const_cast<unsigned char*>(aSignature.data());
1761
    aSignatureItem.len = aSignature.size();
1762
    NSSCMSMessage* pCMSMessage = NSS_CMSMessage_CreateFromDER(&aSignatureItem,
1763
                                 /*cb=*/nullptr,
1764
                                 /*cb_arg=*/nullptr,
1765
                                 /*pwfn=*/nullptr,
1766
                                 /*pwfn_arg=*/nullptr,
1767
                                 /*decrypt_key_cb=*/nullptr,
1768
                                 /*decrypt_key_cb_arg=*/nullptr);
1769
    if (!NSS_CMSMessage_IsSigned(pCMSMessage))
1770
    {
1771
        SAL_WARN("svl.crypto", "ValidateSignature: message is not signed");
1772
        return false;
1773
    }
1774
1775
    NSSCMSContentInfo* pCMSContentInfo = NSS_CMSMessage_ContentLevel(pCMSMessage, 0);
1776
    if (!pCMSContentInfo)
1777
    {
1778
        SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSMessage_ContentLevel() failed");
1779
        return false;
1780
    }
1781
1782
    auto pCMSSignedData = static_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(pCMSContentInfo));
1783
    if (!pCMSSignedData)
1784
    {
1785
        SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSContentInfo_GetContent() failed");
1786
        return false;
1787
    }
1788
1789
    // Import certificates from the signed data temporarily, so it'll be
1790
    // possible to verify the signature, even if we didn't have the certificate
1791
    // previously.
1792
    std::vector<CERTCertificate*> aDocumentCertificates;
1793
    if (auto aCerts = pCMSSignedData->rawCerts) {
1794
        while (*aCerts)
1795
            aDocumentCertificates.push_back(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), *aCerts++, nullptr, 0, 0));
1796
    }
1797
1798
    NSSCMSSignerInfo* pCMSSignerInfo = NSS_CMSSignedData_GetSignerInfo(pCMSSignedData, 0);
1799
    if (!pCMSSignerInfo)
1800
    {
1801
        SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSSignedData_GetSignerInfo() failed");
1802
        return false;
1803
    }
1804
1805
    auto aDigestAlgs = NSS_CMSSignedData_GetDigestAlgs(pCMSSignedData);
1806
    if (!aDigestAlgs || !*aDigestAlgs) {
1807
        SAL_WARN("svl.crypto", "ValidateSignature: digestAlgorithms missing");
1808
        return false;
1809
    }
1810
1811
    SECItem aAlgorithm = aDigestAlgs[0]->algorithm;
1812
    SECOidTag eOidTag = SECOID_FindOIDTag(&aAlgorithm);
1813
1814
    // Map a sign algorithm to a digest algorithm.
1815
    // See NSS_CMSUtil_MapSignAlgs(), which is private to us.
1816
    switch (eOidTag)
1817
    {
1818
    case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
1819
        eOidTag = SEC_OID_SHA1;
1820
        break;
1821
    case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
1822
        eOidTag = SEC_OID_SHA256;
1823
        break;
1824
    case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
1825
        eOidTag = SEC_OID_SHA512;
1826
        break;
1827
    default:
1828
        break;
1829
    }
1830
1831
    HASH_HashType eHashType = HASH_GetHashTypeByOidTag(eOidTag);
1832
    HASHContext* pHASHContext = HASH_Create(bNonDetached ? HASH_AlgSHA1 : eHashType);
1833
    if (!pHASHContext)
1834
    {
1835
        SAL_WARN("svl.crypto", "ValidateSignature: HASH_Create() failed");
1836
        return false;
1837
    }
1838
1839
    // We have a hash, update it with the byte ranges.
1840
    HASH_Update(pHASHContext, aData.data(), aData.size());
1841
1842
    // Find out what is the expected length of the hash.
1843
    unsigned int nMaxResultLen = 0;
1844
    switch (eOidTag)
1845
    {
1846
    case SEC_OID_SHA1:
1847
        nMaxResultLen = comphelper::SHA1_HASH_LENGTH;
1848
        rInformation.nDigestID = xml::crypto::DigestID::SHA1;
1849
        break;
1850
    case SEC_OID_SHA256:
1851
        nMaxResultLen = comphelper::SHA256_HASH_LENGTH;
1852
        rInformation.nDigestID = xml::crypto::DigestID::SHA256;
1853
        break;
1854
    case SEC_OID_SHA512:
1855
        nMaxResultLen = comphelper::SHA512_HASH_LENGTH;
1856
        rInformation.nDigestID = xml::crypto::DigestID::SHA512;
1857
        break;
1858
    default:
1859
        SAL_WARN("svl.crypto", "ValidateSignature: unrecognized algorithm");
1860
        return false;
1861
    }
1862
1863
    auto pActualResultBuffer = static_cast<unsigned char*>(PORT_Alloc(nMaxResultLen));
1864
    unsigned int nActualResultLen;
1865
    HASH_End(pHASHContext, pActualResultBuffer, &nActualResultLen, nMaxResultLen);
1866
1867
    CERTCertificate* pCertificate = NSS_CMSSignerInfo_GetSigningCertificate(pCMSSignerInfo, CERT_GetDefaultCertDB());
1868
    if (!pCertificate)
1869
    {
1870
        SAL_WARN("svl.crypto", "ValidateSignature: NSS_CMSSignerInfo_GetSigningCertificate() failed");
1871
        return false;
1872
    }
1873
    else
1874
    {
1875
        uno::Sequence<sal_Int8> aDerCert(pCertificate->derCert.len);
1876
        auto aDerCertRange = asNonConstRange(aDerCert);
1877
        for (size_t i = 0; i < pCertificate->derCert.len; ++i)
1878
            aDerCertRange[i] = pCertificate->derCert.data[i];
1879
        OUStringBuffer aBuffer;
1880
        comphelper::Base64::encode(aBuffer, aDerCert);
1881
        SignatureInformation::X509Data temp;
1882
        temp.emplace_back();
1883
        temp.back().X509Certificate = aBuffer.makeStringAndClear();
1884
        temp.back().X509Subject = OUString(pCertificate->subjectName, PL_strlen(pCertificate->subjectName), RTL_TEXTENCODING_UTF8);
1885
        rInformation.X509Datas.clear();
1886
        rInformation.X509Datas.emplace_back(temp);
1887
    }
1888
1889
    PRTime nSigningTime;
1890
    // This may fail, in which case the date should be taken from the PDF's dictionary's "M" key,
1891
    // so not critical for PDF at least.
1892
    if (NSS_CMSSignerInfo_GetSigningTime(pCMSSignerInfo, &nSigningTime) == SECSuccess)
1893
    {
1894
        // First convert the UTC UNIX timestamp to a tools::DateTime.
1895
        // nSigningTime is in microseconds.
1896
        DateTime aDateTime = DateTime::CreateFromUnixTime(static_cast<double>(nSigningTime) / 1000000);
1897
1898
        // Then convert to a local UNO DateTime.
1899
        aDateTime.ConvertToLocalTime();
1900
        rInformation.stDateTime = aDateTime.GetUNODateTime();
1901
        if (rInformation.ouDateTime.isEmpty())
1902
        {
1903
            OUStringBuffer rBuffer;
1904
            rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
1905
            rBuffer.append('-');
1906
            if (aDateTime.GetMonth() < 10)
1907
                rBuffer.append('0');
1908
            rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
1909
            rBuffer.append('-');
1910
            if (aDateTime.GetDay() < 10)
1911
                rBuffer.append('0');
1912
            rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
1913
            rInformation.ouDateTime = rBuffer.makeStringAndClear();
1914
        }
1915
    }
1916
1917
    // Check if we have a signing certificate attribute.
1918
    SECOidData aOidData;
1919
    auto cert_oid_buffer = std::to_array(OID_SIGNINGCERTIFICATEV2);
1920
    aOidData.oid.data = cert_oid_buffer.data();
1921
    aOidData.oid.len = cert_oid_buffer.size();
1922
    /*
1923
     * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
1924
     * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
1925
     *   smime(16) id-aa(2) 47 }
1926
     */
1927
    aOidData.offset = SEC_OID_UNKNOWN;
1928
    aOidData.desc = "id-aa-signingCertificateV2";
1929
    aOidData.mechanism = CKM_SHA_1;
1930
    aOidData.supportedExtension = UNSUPPORTED_CERT_EXTENSION;
1931
    NSSCMSAttribute* pAttribute = CMSAttributeArray_FindAttrByOidData(pCMSSignerInfo->authAttr, &aOidData, PR_TRUE);
1932
    if (pAttribute)
1933
        rInformation.bHasSigningCertificate = true;
1934
1935
    SECItem aSignedDigestItem {siBuffer, nullptr, 0};
1936
1937
    SECItem* pContentInfoContentData = pCMSSignedData->contentInfo.content.data;
1938
    if (pContentInfoContentData && pContentInfoContentData->data)
1939
    {
1940
        // Not a detached signature.
1941
        if (bNonDetached && nActualResultLen == pContentInfoContentData->len &&
1942
            !std::memcmp(pActualResultBuffer, pContentInfoContentData->data, nActualResultLen) &&
1943
            HASH_HashBuf(eHashType, pActualResultBuffer, pContentInfoContentData->data, nActualResultLen) == SECSuccess)
1944
        {
1945
            aSignedDigestItem.data = pActualResultBuffer;
1946
            aSignedDigestItem.len = nMaxResultLen;
1947
        }
1948
    }
1949
    else if (!bNonDetached)
1950
    {
1951
        // Detached, the usual case.
1952
        aSignedDigestItem.data = pActualResultBuffer;
1953
        aSignedDigestItem.len = nActualResultLen;
1954
    }
1955
1956
    if (aSignedDigestItem.data && NSS_CMSSignerInfo_Verify(pCMSSignerInfo, &aSignedDigestItem, nullptr) == SECSuccess)
1957
            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
1958
1959
    // Everything went fine
1960
    PORT_Free(pActualResultBuffer);
1961
    HASH_Destroy(pHASHContext);
1962
    NSS_CMSSignerInfo_Destroy(pCMSSignerInfo);
1963
    for (auto pDocumentCertificate : aDocumentCertificates)
1964
        CERT_DestroyCertificate(pDocumentCertificate);
1965
1966
    return true;
1967
1968
#elif USE_CRYPTO_MSCAPI // ends USE_CRYPTO_NSS
1969
1970
    // Open a message for decoding.
1971
    HCRYPTMSG hMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
1972
                                          CMSG_DETACHED_FLAG,
1973
                                          0,
1974
                                          0,
1975
                                          nullptr,
1976
                                          nullptr);
1977
    if (!hMsg)
1978
    {
1979
        SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgOpenToDecode() failed");
1980
        return false;
1981
    }
1982
1983
    // Update the message with the encoded header blob.
1984
    if (!CryptMsgUpdate(hMsg, aSignature.data(), aSignature.size(), TRUE))
1985
    {
1986
        SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the header failed: " << comphelper::WindowsErrorString(GetLastError()));
1987
        return false;
1988
    }
1989
1990
    if (!bNonDetached)
1991
    {
1992
        // Update the message with the content blob.
1993
        if (!CryptMsgUpdate(hMsg, aData.data(), aData.size(), FALSE))
1994
        {
1995
            SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the content failed: " << comphelper::WindowsErrorString(GetLastError()));
1996
            return false;
1997
        }
1998
1999
        if (!CryptMsgUpdate(hMsg, nullptr, 0, TRUE))
2000
        {
2001
            SAL_WARN("svl.crypto", "ValidateSignature, CryptMsgUpdate() for the last content failed: " << comphelper::WindowsErrorString(GetLastError()));
2002
            return false;
2003
        }
2004
    }
2005
    // Get the CRYPT_ALGORITHM_IDENTIFIER from the message.
2006
    DWORD nDigestID = 0;
2007
    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, nullptr, &nDigestID))
2008
    {
2009
        SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed: " << comphelper::WindowsErrorString(GetLastError()));
2010
        return false;
2011
    }
2012
    std::unique_ptr<BYTE[]> pDigestBytes(new BYTE[nDigestID]);
2013
    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_HASH_ALGORITHM_PARAM, 0, pDigestBytes.get(), &nDigestID))
2014
    {
2015
        SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed: " << comphelper::WindowsErrorString(GetLastError()));
2016
        return false;
2017
    }
2018
    auto pDigestID = reinterpret_cast<CRYPT_ALGORITHM_IDENTIFIER*>(pDigestBytes.get());
2019
    if (std::string_view(szOID_NIST_sha256) == pDigestID->pszObjId)
2020
        rInformation.nDigestID = xml::crypto::DigestID::SHA256;
2021
    else if (std::string_view(szOID_RSA_SHA1RSA) == pDigestID->pszObjId || std::string_view(szOID_OIWSEC_sha1) == pDigestID->pszObjId)
2022
        rInformation.nDigestID = xml::crypto::DigestID::SHA1;
2023
    else
2024
        // Don't error out here, we can still verify the message digest correctly, just the digest ID won't be set.
2025
        SAL_WARN("svl.crypto", "ValidateSignature: unhandled algorithm identifier '"<<pDigestID->pszObjId<<"'");
2026
2027
    // Get the signer CERT_INFO from the message.
2028
    DWORD nSignerCertInfo = 0;
2029
    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, nullptr, &nSignerCertInfo))
2030
    {
2031
        SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2032
        return false;
2033
    }
2034
    std::unique_ptr<BYTE[]> pSignerCertInfoBuf(new BYTE[nSignerCertInfo]);
2035
    if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_INFO_PARAM, 0, pSignerCertInfoBuf.get(), &nSignerCertInfo))
2036
    {
2037
        SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2038
        return false;
2039
    }
2040
    PCERT_INFO pSignerCertInfo = reinterpret_cast<PCERT_INFO>(pSignerCertInfoBuf.get());
2041
2042
    // Open a certificate store in memory using CERT_STORE_PROV_MSG, which
2043
    // initializes it with the certificates from the message.
2044
    HCERTSTORE hStoreHandle = CertOpenStore(CERT_STORE_PROV_MSG,
2045
                                            PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2046
                                            0,
2047
                                            0,
2048
                                            hMsg);
2049
    if (!hStoreHandle)
2050
    {
2051
        SAL_WARN("svl.crypto", "ValidateSignature: CertOpenStore() failed");
2052
        return false;
2053
    }
2054
2055
    // Find the signer's certificate in the store.
2056
    PCCERT_CONTEXT pSignerCertContext = CertGetSubjectCertificateFromStore(hStoreHandle,
2057
                                        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
2058
                                        pSignerCertInfo);
2059
    if (!pSignerCertContext)
2060
    {
2061
        SAL_WARN("svl.crypto", "ValidateSignature: CertGetSubjectCertificateFromStore() failed");
2062
        return false;
2063
    }
2064
    else
2065
    {
2066
        // Write rInformation.ouX509Certificate.
2067
        uno::Sequence<sal_Int8> aDerCert(pSignerCertContext->cbCertEncoded);
2068
        std::copy_n(pSignerCertContext->pbCertEncoded, pSignerCertContext->cbCertEncoded,
2069
                    aDerCert.getArray());
2070
        OUStringBuffer aBuffer;
2071
        comphelper::Base64::encode(aBuffer, aDerCert);
2072
        SignatureInformation::X509Data temp;
2073
        temp.emplace_back();
2074
        temp.back().X509Certificate = aBuffer.makeStringAndClear();
2075
        temp.back().X509Subject = GetSubjectName(pSignerCertContext);
2076
        rInformation.X509Datas.clear();
2077
        rInformation.X509Datas.emplace_back(temp);
2078
    }
2079
2080
    std::vector<BYTE> aContentParam;
2081
2082
    if (bNonDetached)
2083
    {
2084
        // Not a detached signature.
2085
        DWORD nContentParam = 0;
2086
        if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, nullptr, &nContentParam))
2087
        {
2088
            SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2089
            return false;
2090
        }
2091
2092
        aContentParam.resize(nContentParam);
2093
        if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, aContentParam.data(), &nContentParam))
2094
        {
2095
            SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() failed");
2096
            return false;
2097
        }
2098
    }
2099
2100
    if (!bNonDetached || VerifyNonDetachedSignature(aData, aContentParam))
2101
    {
2102
        // Use the CERT_INFO from the signer certificate to verify the signature.
2103
        if (CryptMsgControl(hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE, pSignerCertContext->pCertInfo))
2104
            rInformation.nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED;
2105
    }
2106
2107
    // Check if we have a signing certificate attribute.
2108
    DWORD nSignedAttributes = 0;
2109
    if (CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
2110
    {
2111
        std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
2112
        if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_AUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
2113
        {
2114
            SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() authenticated failed");
2115
            return false;
2116
        }
2117
        auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
2118
        for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
2119
        {
2120
            CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
2121
            /*
2122
             * id-aa-signingCertificateV2 OBJECT IDENTIFIER ::=
2123
             * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
2124
             *   smime(16) id-aa(2) 47 }
2125
             */
2126
            if (std::string_view("1.2.840.113549.1.9.16.2.47") == rAttr.pszObjId)
2127
            {
2128
                rInformation.bHasSigningCertificate = true;
2129
                break;
2130
            }
2131
        }
2132
    }
2133
2134
    // Get the unauthorized attributes.
2135
    nSignedAttributes = 0;
2136
    if (CryptMsgGetParam(hMsg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, nullptr, &nSignedAttributes))
2137
    {
2138
        std::unique_ptr<BYTE[]> pSignedAttributesBuf(new BYTE[nSignedAttributes]);
2139
        if (!CryptMsgGetParam(hMsg, CMSG_SIGNER_UNAUTH_ATTR_PARAM, 0, pSignedAttributesBuf.get(), &nSignedAttributes))
2140
        {
2141
            SAL_WARN("svl.crypto", "ValidateSignature: CryptMsgGetParam() unauthenticated failed");
2142
            return false;
2143
        }
2144
        auto pSignedAttributes = reinterpret_cast<PCRYPT_ATTRIBUTES>(pSignedAttributesBuf.get());
2145
        for (size_t nAttr = 0; nAttr < pSignedAttributes->cAttr; ++nAttr)
2146
        {
2147
            CRYPT_ATTRIBUTE& rAttr = pSignedAttributes->rgAttr[nAttr];
2148
            // Timestamp blob
2149
            if (std::string_view("1.2.840.113549.1.9.16.2.14") == rAttr.pszObjId)
2150
            {
2151
                PCRYPT_TIMESTAMP_CONTEXT pTsContext;
2152
                if (!CryptVerifyTimeStampSignature(rAttr.rgValue->pbData, rAttr.rgValue->cbData, nullptr, 0, nullptr, &pTsContext, nullptr, nullptr))
2153
                {
2154
                    SAL_WARN("svl.crypto", "CryptMsgUpdate failed: " << comphelper::WindowsErrorString(GetLastError()));
2155
                    break;
2156
                }
2157
2158
                DateTime aDateTime = DateTime::CreateFromWin32FileDateTime(pTsContext->pTimeStamp->ftTime.dwLowDateTime, pTsContext->pTimeStamp->ftTime.dwHighDateTime);
2159
2160
                // Then convert to a local UNO DateTime.
2161
                aDateTime.ConvertToLocalTime();
2162
                rInformation.stDateTime = aDateTime.GetUNODateTime();
2163
                if (rInformation.ouDateTime.isEmpty())
2164
                {
2165
                    OUStringBuffer rBuffer;
2166
                    rBuffer.append(static_cast<sal_Int32>(aDateTime.GetYear()));
2167
                    rBuffer.append('-');
2168
                    if (aDateTime.GetMonth() < 10)
2169
                        rBuffer.append('0');
2170
                    rBuffer.append(static_cast<sal_Int32>(aDateTime.GetMonth()));
2171
                    rBuffer.append('-');
2172
                    if (aDateTime.GetDay() < 10)
2173
                        rBuffer.append('0');
2174
                    rBuffer.append(static_cast<sal_Int32>(aDateTime.GetDay()));
2175
                    rInformation.ouDateTime = rBuffer.makeStringAndClear();
2176
                }
2177
                break;
2178
            }
2179
        }
2180
    }
2181
2182
    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);
2183
    CryptMsgClose(hMsg);
2184
    return true;
2185
#else
2186
    // Not implemented.
2187
0
    (void)aData;
2188
0
    (void)bNonDetached;
2189
0
    (void)aSignature;
2190
0
    (void)rInformation;
2191
0
    return false;
2192
0
#endif
2193
0
}
2194
2195
bool Signing::Verify(SvStream& rStream,
2196
                     const std::vector<std::pair<size_t, size_t>>& aByteRanges,
2197
                     const bool bNonDetached,
2198
                     const std::vector<unsigned char>& aSignature,
2199
                     SignatureInformation& rInformation)
2200
0
{
2201
#if USE_CRYPTO_ANY
2202
    std::vector<unsigned char> buffer;
2203
2204
    // Copy the byte ranges into a single buffer.
2205
    for (const auto& rByteRange : aByteRanges)
2206
    {
2207
        rStream.Seek(rByteRange.first);
2208
        const size_t size = buffer.size();
2209
        buffer.resize(size + rByteRange.second);
2210
        rStream.ReadBytes(buffer.data() + size, rByteRange.second);
2211
    }
2212
2213
    return Verify(buffer, bNonDetached, aSignature, rInformation);
2214
2215
#else
2216
    // Not implemented.
2217
0
    (void)rStream;
2218
0
    (void)aByteRanges;
2219
0
    (void)bNonDetached;
2220
0
    (void)aSignature;
2221
0
    (void)rInformation;
2222
0
    return false;
2223
0
#endif
2224
0
}
2225
2226
void Signing::appendHex(sal_Int8 nInt, OStringBuffer& rBuffer)
2227
0
{
2228
0
    static const char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
2229
0
                                           '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
2230
0
    rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
2231
0
    rBuffer.append( pHexDigits[ nInt & 15 ] );
2232
0
}
2233
2234
bool CertificateOrName::Is() const
2235
0
{
2236
0
    return m_xCertificate.is() || !m_aName.isEmpty();
2237
0
}
2238
}
2239
2240
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */