summaryrefslogtreecommitdiffstats
path: root/include/iprt/crypto/pkcs7.h
blob: 2bc3f950e2aad66b1151bfa2822ace215889819a (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
/** @file
 * IPRT - PKCS \#7, Cryptographic Message Syntax Standard (aka CMS).
 */

/*
 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
 * in the VirtualBox distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 *
 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
 */

#ifndef IPRT_INCLUDED_crypto_pkcs7_h
#define IPRT_INCLUDED_crypto_pkcs7_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <iprt/asn1.h>
#include <iprt/crypto/x509.h>


RT_C_DECLS_BEGIN

struct RTCRPKCS7CONTENTINFO;


/** @defgroup grp_rt_crpkcs7 RTCrPkcs7 - PKCS \#7, Cryptographic Message Syntax Standard (aka CMS).
 * @ingroup grp_rt_crypto
 * @{
 */

/** PKCS \#7 data object ID.*/
#define RTCR_PKCS7_DATA_OID                         "1.2.840.113549.1.7.1"
/** PKCS \#7 signedData object ID. */
#define RTCR_PKCS7_SIGNED_DATA_OID                  "1.2.840.113549.1.7.2"
/** PKCS \#7 envelopedData object ID. */
#define RTCR_PKCS7_ENVELOPED_DATA_OID               "1.2.840.113549.1.7.3"
/** PKCS \#7 signedAndEnvelopedData object ID.  */
#define RTCR_PKCS7_SIGNED_AND_ENVELOPED_DATA_OID    "1.2.840.113549.1.7.4"
/** PKCS \#7 digestedData object ID. */
#define RTCR_PKCS7_DIGESTED_DATA_OID                "1.2.840.113549.1.7.5"
/** PKCS \#7 encryptedData object ID. */
#define RTCR_PKCS7_ENCRYPTED_DATA_OID               "1.2.840.113549.1.7.6"


/**
 * PKCS \#7 IssuerAndSerialNumber (IPRT representation).
 */
typedef struct RTCRPKCS7ISSUERANDSERIALNUMBER
{
    /** Sequence core. */
    RTASN1SEQUENCECORE                  SeqCore;
    /** The certificate name. */
    RTCRX509NAME                        Name;
    /** The certificate serial number. */
    RTASN1INTEGER                       SerialNumber;
} RTCRPKCS7ISSUERANDSERIALNUMBER;
/** Pointer to the IPRT representation of a PKCS \#7 IssuerAndSerialNumber. */
typedef RTCRPKCS7ISSUERANDSERIALNUMBER *PRTCRPKCS7ISSUERANDSERIALNUMBER;
/** Pointer to the const IPRT representation of a PKCS \#7
 * IssuerAndSerialNumber. */
typedef RTCRPKCS7ISSUERANDSERIALNUMBER const *PCRTCRPKCS7ISSUERANDSERIALNUMBER;
RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7ISSUERANDSERIALNUMBER, RTDECL, RTCrPkcs7IssuerAndSerialNumber, SeqCore.Asn1Core);


/** Pointer to the IPRT representation of a PKCS \#7 SignerInfo. */
typedef struct RTCRPKCS7SIGNERINFO *PRTCRPKCS7SIGNERINFO;
/** Pointer to the const IPRT representation of a PKCS \#7 SignerInfo. */
typedef struct RTCRPKCS7SIGNERINFO const *PCRTCRPKCS7SIGNERINFO;
RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SIGNERINFOS, RTCRPKCS7SIGNERINFO, RTDECL, RTCrPkcs7SignerInfos);


/**
 * Attribute value type (for the union).
 */
typedef enum RTCRPKCS7ATTRIBUTETYPE
{
    /** Zero is invalid. */
    RTCRPKCS7ATTRIBUTETYPE_INVALID = 0,
    /** Not present, union is NULL. */
    RTCRPKCS7ATTRIBUTETYPE_NOT_PRESENT,
    /** Unknown values, pCores. */
    RTCRPKCS7ATTRIBUTETYPE_UNKNOWN,
    /** Object IDs, use pObjIds. */
    RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS,
    /** Octet strings, use pOctetStrings. */
    RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS,
    /** Counter signatures (PKCS \#9), use pCounterSignatures.
     * RTCR_PKCS9_ID_COUNTER_SIGNATURE_OID - 1.2.840.113549.1.9.6.  */
    RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES,
    /** Signing time (PKCS \#9), use pSigningTime.
     * RTCR_PKCS9_ID_SIGNING_TIME_OID - 1.2.840.113549.1.9.5.  */
    RTCRPKCS7ATTRIBUTETYPE_SIGNING_TIME,
    /** Microsoft timestamp info (RFC-3161) signed data, use pContentInfo.
     * RTCR_PKCS9_ID_MS_TIMESTAMP - 1.3.6.1.4.1.311.3.3.1. */
    RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP,
    /** Microsoft nested PKCS\#7 signature (signtool /as).
     * RTCR_PKCS9_ID_MS_NESTED_SIGNATURE  - 1.3.6.1.4.1.311.2.4.1. */
    RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE,
    /** Microsoft statement type, use pObjIdSeqs.
     * RTCR_PKCS9_ID_MS_STATEMENT_TYPE - 1.3.6.1.4.1.311.2.1.11. */
    RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE,
    /** Apple plist with the all code directory digests, use pOctetStrings.
     * RTCR_PKCS9_ID_APPLE_MULTI_CD_PLIST - 1.2.840.113635.100.9.1.  */
    RTCRPKCS7ATTRIBUTETYPE_APPLE_MULTI_CD_PLIST,
    /** Blow the type up to 32-bits. */
    RTCRPKCS7ATTRIBUTETYPE_32BIT_HACK = 0x7fffffff
} RTCRPKCS7ATTRIBUTETYPE;

/**
 * PKCS \#7 Attribute (IPRT representation).
 */
typedef struct RTCRPKCS7ATTRIBUTE
{
    /** Sequence core. */
    RTASN1SEQUENCECORE                  SeqCore;
    /** The attribute type (object ID). */
    RTASN1OBJID                         Type;
    /** The type of data found in the values union. */
    RTCRPKCS7ATTRIBUTETYPE              enmType;
    /** Value allocation. */
    RTASN1ALLOCATION                    Allocation;
    /** Values.  */
    union
    {
        /** ASN.1 cores (RTCRPKCS7ATTRIBUTETYPE_UNKNOWN). */
        PRTASN1SETOFCORES               pCores;
        /** ASN.1 object identifiers (RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS). */
        PRTASN1SETOFOBJIDS              pObjIds;
        /** Sequence of ASN.1 object identifiers (RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE). */
        PRTASN1SETOFOBJIDSEQS           pObjIdSeqs;
        /** ASN.1 octet strings (RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS). */
        PRTASN1SETOFOCTETSTRINGS        pOctetStrings;
        /** Counter signatures RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES(). */
        PRTCRPKCS7SIGNERINFOS           pCounterSignatures;
        /** Signing time(s) (RTCRPKCS7ATTRIBUTETYPE_SIGNING_TIME). */
        PRTASN1SETOFTIMES               pSigningTime;
        /** Microsoft timestamp (RFC-3161 signed data, RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP),
         * Microsoft nested signature (RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE). */
        struct RTCRPKCS7SETOFCONTENTINFOS *pContentInfos;
    } uValues;
} RTCRPKCS7ATTRIBUTE;
/** Pointer to the IPRT representation of a PKCS \#7 Attribute. */
typedef RTCRPKCS7ATTRIBUTE *PRTCRPKCS7ATTRIBUTE;
/** Pointer to the const IPRT representation of a PKCS \#7 Attribute. */
typedef RTCRPKCS7ATTRIBUTE const *PCRTCRPKCS7ATTRIBUTE;
RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7ATTRIBUTE, RTDECL, RTCrPkcs7Attribute, SeqCore.Asn1Core);

RTDECL(int) RTCrPkcs7Attribute_SetAppleMultiCdPlist(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOCTETSTRINGS pToClone,
                                                    PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Attribute_SetContentType(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOBJIDS pToClone,
                                              PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Attribute_SetCounterSignatures(PRTCRPKCS7ATTRIBUTE pThis, PCRTCRPKCS7SIGNERINFOS pToClone,
                                                    PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Attribute_SetMessageDigest(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOCTETSTRINGS pToClone,
                                                PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Attribute_SetMsStatementType(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFOBJIDSEQS pToClone,
                                                  PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Attribute_SetMsNestedSignature(PRTCRPKCS7ATTRIBUTE pThis, struct RTCRPKCS7SETOFCONTENTINFOS const *pToClone,
                                                    PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Attribute_SetMsTimestamp(PRTCRPKCS7ATTRIBUTE pThis, struct RTCRPKCS7SETOFCONTENTINFOS const *pToClone,
                                              PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Attribute_SetSigningTime(PRTCRPKCS7ATTRIBUTE pThis, PCRTASN1SETOFTIMES pToClone,
                                              PCRTASN1ALLOCATORVTABLE pAllocator);

RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7ATTRIBUTES, RTCRPKCS7ATTRIBUTE, RTDECL, RTCrPkcs7Attributes);

RTDECL(int) RTCrPkcs7Attributes_HashAttributes(PRTCRPKCS7ATTRIBUTES pAttributes, RTCRDIGEST hDigest, PRTERRINFO pErrInfo);


/**
 * One PKCS \#7 SignerInfo (IPRT representation).
 */
typedef struct RTCRPKCS7SIGNERINFO
{
    /** Sequence core. */
    RTASN1SEQUENCECORE                  SeqCore;
    /** The structure version (RTCRPKCS7SIGNERINFO_V1). */
    RTASN1INTEGER                       Version;
    /** The issuer and serial number of the certificate used to produce the
     * encrypted digest below. */
    RTCRPKCS7ISSUERANDSERIALNUMBER      IssuerAndSerialNumber;
    /** The digest algorithm use to digest the signed content. */
    RTCRX509ALGORITHMIDENTIFIER         DigestAlgorithm;
    /** Authenticated attributes, optional [0].
     * @todo Check how other producers formats this. The microsoft one does not
     *       have explicit tags, but combines it with the SET OF. */
    RTCRPKCS7ATTRIBUTES                 AuthenticatedAttributes;
    /** The digest encryption algorithm use to encrypt the digest of the signed
     * content. */
    RTCRX509ALGORITHMIDENTIFIER         DigestEncryptionAlgorithm;
    /** The encrypted digest. */
    RTASN1OCTETSTRING                   EncryptedDigest;
    /** Unauthenticated attributes, optional [1].
     * @todo Check how other producers formats this. The microsoft one does not
     *       have explicit tags, but combines it with the SET OF. */
    RTCRPKCS7ATTRIBUTES                 UnauthenticatedAttributes;
} RTCRPKCS7SIGNERINFO;
RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7SIGNERINFO, RTDECL, RTCrPkcs7SignerInfo, SeqCore.Asn1Core);

RTDECL(int) RTCrPkcs7SignerInfo_SetAuthenticatedAttributes(PRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7ATTRIBUTES pAttributes,
                                                           PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7SignerInfo_SetUnauthenticatedAttributes(PRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7ATTRIBUTES pAttributes,
                                                             PCRTASN1ALLOCATORVTABLE pAllocator);

/** RTCRPKCS7SIGNERINFO::Version value.  */
#define RTCRPKCS7SIGNERINFO_V1    1

/** @name PKCS \#9 Attribute IDs
 * @{ */
/** Content type (RFC-2630 11.1).
 * Value: Object Identifier */
#define RTCR_PKCS9_ID_CONTENT_TYPE_OID      "1.2.840.113549.1.9.3"
/** Message digest (RFC-2630 11.2).
 * Value: Octet string. */
#define RTCR_PKCS9_ID_MESSAGE_DIGEST_OID    "1.2.840.113549.1.9.4"
/** Signing time (RFC-2630 11.3).
 * Value: Octet string. */
#define RTCR_PKCS9_ID_SIGNING_TIME_OID      "1.2.840.113549.1.9.5"
/** Counter signature (RFC-2630 11.4).
 * Value: SignerInfo. */
#define RTCR_PKCS9_ID_COUNTER_SIGNATURE_OID "1.2.840.113549.1.9.6"
/** Microsoft timestamp (RTF-3161) counter signature (SignedData).
 * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */
#define RTCR_PKCS9_ID_MS_TIMESTAMP          "1.3.6.1.4.1.311.3.3.1"
/** Microsoft nested PKCS\#7 signature.
 * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. */
#define RTCR_PKCS9_ID_MS_NESTED_SIGNATURE   "1.3.6.1.4.1.311.2.4.1"
/** Microsoft statement type.
 * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */
#define RTCR_PKCS9_ID_MS_STATEMENT_TYPE     "1.3.6.1.4.1.311.2.1.11"
/** Microsoft opus info.
 * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. It's actually listed as SPC by MS. */
#define RTCR_PKCS9_ID_MS_SP_OPUS_INFO       "1.3.6.1.4.1.311.2.1.12"
/** Apple code signing multi-code-directory plist.
 * @remarks This isn't defined by PKCS \#9, but lumped in here for convenience. */
#define RTCR_PKCS9_ID_APPLE_MULTI_CD_PLIST  "1.2.840.113635.100.9.1"
/** @} */


/**
 * Get the (next) signing time attribute from the specfied SignerInfo or one of
 * the immediate counter signatures.
 *
 * @returns Pointer to the signing time if found, NULL if not.
 * @param   pThis               The SignerInfo to search.
 * @param   ppSignerInfo        Pointer to variable keeping track of the
 *                              enumeration, optional.
 *
 *                              If specified the input value is taken to the be
 *                              SignerInfo of the previously returned signing
 *                              time.  The value pointed to is NULL, the
 *                              search/enum restarts.
 *
 *                              On successful return this is set to the
 *                              SignerInfo which we found the signing time in.
 */
RTDECL(PCRTASN1TIME) RTCrPkcs7SignerInfo_GetSigningTime(PCRTCRPKCS7SIGNERINFO pThis, PCRTCRPKCS7SIGNERINFO *ppSignerInfo);


/**
 * Get the (first) timestamp from within a Microsoft timestamp server counter
 * signature.
 *
 * @returns Pointer to the signing time if found, NULL if not.
 * @param   pThis               The SignerInfo to search.
 * @param   ppContentInfoRet    Where to return the pointer to the counter
 *                              signature, optional.
 */
RTDECL(PCRTASN1TIME) RTCrPkcs7SignerInfo_GetMsTimestamp(PCRTCRPKCS7SIGNERINFO pThis,
                                                        struct RTCRPKCS7CONTENTINFO const **ppContentInfoRet);



/**
 * PKCS \#7 ContentInfo (IPRT representation).
 */
typedef struct RTCRPKCS7CONTENTINFO
{
    /** Sequence core. */
    RTASN1SEQUENCECORE                  SeqCore;
    /** Object ID identifying the content below. */
    RTASN1OBJID                         ContentType;
    /** Content, optional, explicit tag 0.
     *
     * Hack alert! This should've been an explict context tag 0 structure with a
     * type selected according to ContentType.  However, it's simpler to replace the
     * explicit context with an OCTET STRING with implict tag 0.  Then we can tag
     * along on the encapsulation logic RTASN1OCTETSTRING provides for the dynamic
     * inner type.  The default decoder code will detect known structures as
     * outlined in the union below, and decode the octet string content as an
     * anonymous RTASN1CORE if not known.
     *
     * If the user want to decode the octet string content differently, it can do so
     * by destroying and freeing the current encapsulated pointer, replacing it with
     * it's own.  (Of course following the RTASN1OCTETSTRING rules.)  Just remember
     * to also update the value in the union.
     *
     * @remarks What's signed and verified is Content.pEncapsulated->uData.pv.
     */
    RTASN1OCTETSTRING                   Content;
    /** Pointer to the CMS octet string that's inside the Content, NULL if PKCS \#7.
     *
     * Hack alert! When transitioning from PKCS \#7 to CMS, the designers decided to
     * change things and add another wrapper.  This time we're talking about a real
     * octet string, not like the one above which is really an explicit content tag.
     * When constructing or decoding CMS content, this will be the same pointer as
     * Content.pEncapsulated, while the union below will be holding the same pointer
     * as pCmsContent->pEncapsulated.
     */
    PRTASN1OCTETSTRING                  pCmsContent;
    /** Same as Content.pEncapsulated, except a choice of known types. */
    union
    {
        /** ContentType is RTCRPKCS7SIGNEDDATA_OID. */
        struct RTCRPKCS7SIGNEDDATA         *pSignedData;
        /** ContentType is RTCRSPCINDIRECTDATACONTENT_OID. */
        struct RTCRSPCINDIRECTDATACONTENT  *pIndirectDataContent;
        /** ContentType is RTCRTSPTSTINFO_OID. */
        struct RTCRTSPTSTINFO              *pTstInfo;
        /** Generic / Unknown / User. */
        PRTASN1CORE                         pCore;
    } u;
} RTCRPKCS7CONTENTINFO;
/** Pointer to the IPRT representation of a PKCS \#7 ContentInfo. */
typedef RTCRPKCS7CONTENTINFO *PRTCRPKCS7CONTENTINFO;
/** Pointer to the const IPRT representation of a PKCS \#7 ContentInfo. */
typedef RTCRPKCS7CONTENTINFO const *PCRTCRPKCS7CONTENTINFO;
RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7CONTENTINFO, RTDECL, RTCrPkcs7ContentInfo, SeqCore.Asn1Core);
RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFCONTENTINFOS, RTCRPKCS7CONTENTINFO, RTDECL, RTCrPkcs7SetOfContentInfos);

RTDECL(bool) RTCrPkcs7ContentInfo_IsSignedData(PCRTCRPKCS7CONTENTINFO pThis);


/**
 * PKCS \#7 Certificate choice.
 */
typedef enum RTCRPKCS7CERTCHOICE
{
    RTCRPKCS7CERTCHOICE_INVALID = 0,
    RTCRPKCS7CERTCHOICE_X509,
    RTCRPKCS7CERTCHOICE_EXTENDED_PKCS6,
    RTCRPKCS7CERTCHOICE_AC_V1,
    RTCRPKCS7CERTCHOICE_AC_V2,
    RTCRPKCS7CERTCHOICE_OTHER,
    RTCRPKCS7CERTCHOICE_END,
    RTCRPKCS7CERTCHOICE_32BIT_HACK = 0x7fffffff
} RTCRPKCS7CERTCHOICE;


/**
 * Common representation for PKCS \#7 ExtendedCertificateOrCertificate and the
 * CMS CertificateChoices types.
 */
typedef struct RTCRPKCS7CERT
{
    /** Dummy ASN.1 record, not encoded. */
    RTASN1DUMMY                         Dummy;
    /** The value allocation. */
    RTASN1ALLOCATION                    Allocation;
    /** The choice of value.   */
    RTCRPKCS7CERTCHOICE                 enmChoice;
    /** The value union. */
    union
    {
        /** Standard X.509 certificate (RTCRCMSCERTIFICATECHOICE_X509). */
        PRTCRX509CERTIFICATE            pX509Cert;
        /** Extended PKCS \#6 certificate (RTCRCMSCERTIFICATECHOICE_EXTENDED_PKCS6). */
        PRTASN1CORE                     pExtendedCert;
        /** Attribute certificate version 1 (RTCRCMSCERTIFICATECHOICE_AC_V1). */
        PRTASN1CORE                     pAcV1;
        /** Attribute certificate version 2 (RTCRCMSCERTIFICATECHOICE_AC_V2). */
        PRTASN1CORE                     pAcV2;
        /** Other certificate (RTCRCMSCERTIFICATECHOICE_OTHER). */
        PRTASN1CORE                     pOtherCert;
    } u;
} RTCRPKCS7CERT;
/** Pointer to the IPRT representation of PKCS \#7 or CMS certificate. */
typedef RTCRPKCS7CERT *PRTCRPKCS7CERT;
/** Pointer to the const IPRT representation of PKCS \#7 or CMS certificate. */
typedef RTCRPKCS7CERT const *PCRTCRPKCS7CERT;
RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7CERT, RTDECL, RTCrPkcs7Cert, Dummy.Asn1Core);
RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFCERTS, RTCRPKCS7CERT, RTDECL, RTCrPkcs7SetOfCerts);

RTDECL(int) RTCrPkcs7Cert_SetX509Cert(PRTCRPKCS7CERT pThis, PCRTCRX509CERTIFICATE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Cert_SetExtendedCert(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Cert_SetAcV1(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Cert_SetAcV2(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7Cert_SetOtherCert(PRTCRPKCS7CERT pThis, PCRTASN1CORE pToClone, PCRTASN1ALLOCATORVTABLE pAllocator);

RTDECL(PCRTCRX509CERTIFICATE) RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(PCRTCRPKCS7SETOFCERTS pCertificates,
                                                                                  PCRTCRX509NAME pIssuer,
                                                                                  PCRTASN1INTEGER pSerialNumber);


/**
 * PKCS \#7 SignedData (IPRT representation).
 */
typedef struct RTCRPKCS7SIGNEDDATA
{
    /** Sequence core. */
    RTASN1SEQUENCECORE                  SeqCore;
    /** The structure version value (1). */
    RTASN1INTEGER                       Version;
    /** The digest algorithms that are used to signed the content (ContentInfo). */
    RTCRX509ALGORITHMIDENTIFIERS        DigestAlgorithms;
    /** The content that's being signed. */
    RTCRPKCS7CONTENTINFO                ContentInfo;
    /** Certificates, optional, implicit tag 0. (Required by Authenticode.) */
    RTCRPKCS7SETOFCERTS                 Certificates;
    /** Certificate revocation lists, optional, implicit tag 1.
     * Not used by Authenticode, so currently stubbed. */
    RTASN1CORE                          Crls;
    /** Signer infos. */
    RTCRPKCS7SIGNERINFOS                SignerInfos;
} RTCRPKCS7SIGNEDDATA;
/** Pointer to the IPRT representation of a PKCS \#7 SignedData. */
typedef RTCRPKCS7SIGNEDDATA *PRTCRPKCS7SIGNEDDATA;
/** Pointer to the const IPRT representation of a PKCS \#7 SignedData. */
typedef RTCRPKCS7SIGNEDDATA const *PCRTCRPKCS7SIGNEDDATA;
RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7SIGNEDDATA, RTDECL, RTCrPkcs7SignedData, SeqCore.Asn1Core);
RTASN1_IMPL_GEN_SET_OF_TYPEDEFS_AND_PROTOS(RTCRPKCS7SETOFSIGNEDDATA, RTCRPKCS7SIGNEDDATA, RTDECL, RTCrPkcs7SetOfSignedData);

/** PKCS \#7 SignedData object ID.  */
#define RTCRPKCS7SIGNEDDATA_OID   RTCR_PKCS7_SIGNED_DATA_OID

/** PKCS \#7 SignedData version number 1.  */
#define RTCRPKCS7SIGNEDDATA_V1    1
/* No version 2 seems to exist. */
/** CMS SignedData version number 3.
 * This should only be used if there are version 1 attribute certificates
 * present, or if there are version 3 SignerInfo items present, or if
 * enmcCountInfo is not id-data (RFC-5652, section 5.1). */
#define RTCRPKCS7SIGNEDDATA_V3    3
/** CMS SignedData version number 4.
 * This should only be used if there are version 2 attribute certificates
 * present (RFC-5652, section 5.1). */
#define RTCRPKCS7SIGNEDDATA_V4    4
/** CMS SignedData version number 5.
 * This should only be used if there are certificates or/and CRLs of the
 * OTHER type present (RFC-5652, section 5.1). */
#define RTCRPKCS7SIGNEDDATA_V5    5

RTDECL(int) RTCrPkcs7SignedData_SetCertificates(PRTCRPKCS7SIGNEDDATA pThis, PCRTCRPKCS7SETOFCERTS pCerts, PCRTASN1ALLOCATORVTABLE pAllocator);
RTDECL(int) RTCrPkcs7SignedData_SetCrls(PRTCRPKCS7SIGNEDDATA pThis, PCRTASN1CORE pCerts, PCRTASN1ALLOCATORVTABLE pAllocator);

/** @name RTCRPKCS7SIGNEDDATA_SANITY_F_XXX - Flags for RTPkcs7SignedDataCheckSantiy.
 * @{ */
/** Check for authenticode restrictions. */
#define RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE         RT_BIT_32(0)
/** Check that all the hash algorithms are known to IPRT. */
#define RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH      RT_BIT_32(1)
/** Require signing certificate to be present. */
#define RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT RT_BIT_32(2)
/** @} */

/** PKCS\#7/CMS (content info) markers. */
extern RTDATADECL(RTCRPEMMARKER const) g_aRTCrPkcs7Markers[];
/** Number of entries in g_aRTCrPkcs7Markers. */
extern RTDATADECL(uint32_t const)      g_cRTCrPkcs7Markers;

/** @name Flags for RTCrPkcs7ContentInfo_ReadFromBuffer
 * @{ */
/** Only allow PEM certificates, not binary ones.
 * @sa RTCRPEMREADFILE_F_ONLY_PEM  */
#define RTCRPKCS7_READ_F_PEM_ONLY        RT_BIT(1)
/** @} */

RTDECL(int) RTCrPkcs7_ReadFromBuffer(PRTCRPKCS7CONTENTINFO pContentInfo, const void *pvBuf, size_t cbBuf,
                                     uint32_t fFlags, PCRTASN1ALLOCATORVTABLE pAllocator,
                                     bool *pfCmsLabeled, PRTERRINFO pErrInfo, const char *pszErrorTag);


/**
 * PKCS \#7 DigestInfo (IPRT representation).
 */
typedef struct RTCRPKCS7DIGESTINFO
{
    /** Sequence core. */
    RTASN1SEQUENCECORE                  SeqCore;
    /** The digest algorithm use to digest the signed content. */
    RTCRX509ALGORITHMIDENTIFIER         DigestAlgorithm;
    /** The digest. */
    RTASN1OCTETSTRING                   Digest;
} RTCRPKCS7DIGESTINFO;
/** Pointer to the IPRT representation of a PKCS \#7 DigestInfo object. */
typedef RTCRPKCS7DIGESTINFO *PRTCRPKCS7DIGESTINFO;
/** Pointer to the const IPRT representation of a PKCS \#7 DigestInfo object. */
typedef RTCRPKCS7DIGESTINFO const *PCRTCRPKCS7DIGESTINFO;
RTASN1TYPE_STANDARD_PROTOTYPES(RTCRPKCS7DIGESTINFO, RTDECL, RTCrPkcs7DigestInfo, SeqCore.Asn1Core);


/**
 * Callback function for use with RTCrPkcs7VerifySignedData.
 *
 * @returns IPRT status code.
 * @param   pCert               The certificate to verify.
 * @param   hCertPaths          Unless the certificate is trusted directly, this
 *                              is a reference to the certificate path builder
 *                              and verifier instance that we used to establish
 *                              at least valid trusted path to @a pCert.  The
 *                              callback can use this to enforce additional
 *                              certificate lineage requirements, effective
 *                              policy checks and whatnot.
 *                              This is NIL_RTCRX509CERTPATHS if the certificate
 *                              is directly trusted.
 * @param   fFlags              Mix of the RTCRPKCS7VCC_F_XXX flags.
 * @param   pvUser              The user argument.
 * @param   pErrInfo            Optional error info buffer.
 */
typedef DECLCALLBACKTYPE(int, FNRTCRPKCS7VERIFYCERTCALLBACK,(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths,
                                                             uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo));
/** Pointer to a FNRTCRPKCS7VERIFYCERTCALLBACK callback. */
typedef FNRTCRPKCS7VERIFYCERTCALLBACK *PFNRTCRPKCS7VERIFYCERTCALLBACK;

/** @name RTCRPKCS7VCC_F_XXX - Flags for FNRTCRPKCS7VERIFYCERTCALLBACK.
 * @{ */
/** Normal callback for a direct signatory of the signed data. */
#define RTCRPKCS7VCC_F_SIGNED_DATA                      RT_BIT_32(0)
/** Check that the signatory can be trusted for timestamps. */
#define RTCRPKCS7VCC_F_TIMESTAMP                        RT_BIT_32(1)
/** @} */

/**
 * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
 *  Default implementation that checks for the DigitalSignature KeyUsage bit.}
 */
RTDECL(int) RTCrPkcs7VerifyCertCallbackDefault(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags,
                                               void *pvUser, PRTERRINFO pErrInfo);

/**
 * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
 * Standard code signing.  Use this for Microsoft SPC.}
 */
RTDECL(int) RTCrPkcs7VerifyCertCallbackCodeSigning(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags,
                                                   void *pvUser, PRTERRINFO pErrInfo);

/**
 * Verifies PKCS \#7 SignedData.
 *
 * For compatability with alternative crypto providers, the user must work on
 * the top level PKCS \#7 structure instead directly on the SignedData.
 *
 * @returns IPRT status code.
 * @param   pContentInfo        PKCS \#7 content info structure.
 * @param   fFlags              RTCRPKCS7VERIFY_SD_F_XXX.
 * @param   hAdditionalCerts    Store containing additional certificates to
 *                              supplement those mentioned in the signed data.
 * @param   hTrustedCerts       Store containing trusted certificates.
 * @param   pValidationTime     The time we're supposed to validate the
 *                              certificates chains at.  Ignored for signatures
 *                              with valid signing time attributes.
 *                              When RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME
 *                              is set, this is updated to the actual validation
 *                              time used.
 * @param   pfnVerifyCert       Callback for checking that a certificate used
 *                              for signing the data is suitable.
 * @param   pvUser              User argument for the callback.
 * @param   pErrInfo            Optional error info buffer.
 * @sa      RTCrPkcs7VerifySignedDataWithExternalData
 */
RTDECL(int) RTCrPkcs7VerifySignedData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags,
                                      RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts,
                                      PCRTTIMESPEC pValidationTime, PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser,
                                      PRTERRINFO pErrInfo);


/**
 * Verifies PKCS \#7 SignedData with external data.
 *
 * For compatability with alternative crypto providers, the user must work on
 * the top level PKCS \#7 structure instead directly on the SignedData.
 *
 * @returns IPRT status code.
 * @param   pContentInfo        PKCS \#7 content info structure.
 * @param   fFlags              RTCRPKCS7VERIFY_SD_F_XXX.
 * @param   hAdditionalCerts    Store containing additional certificates to
 *                              supplement those mentioned in the signed data.
 * @param   hTrustedCerts       Store containing trusted certificates.
 * @param   pValidationTime     The time we're supposed to validate the
 *                              certificates chains at.  Ignored for signatures
 *                              with valid signing time attributes.
 *                              When RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME
 *                              is set, this is updated to the actual validation
 *                              time used.
 * @param   pfnVerifyCert       Callback for checking that a certificate used
 *                              for signing the data is suitable.
 * @param   pvUser              User argument for the callback.
 * @param   pvData              The signed external data.
 * @param   cbData              The size of the signed external data.
 * @param   pErrInfo            Optional error info buffer.
 * @sa      RTCrPkcs7VerifySignedData
 */
RTDECL(int) RTCrPkcs7VerifySignedDataWithExternalData(PCRTCRPKCS7CONTENTINFO pContentInfo, uint32_t fFlags,
                                                      RTCRSTORE hAdditionalCerts, RTCRSTORE hTrustedCerts,
                                                      PCRTTIMESPEC pValidationTime,
                                                      PFNRTCRPKCS7VERIFYCERTCALLBACK pfnVerifyCert, void *pvUser,
                                                      void const *pvData, size_t cbData, PRTERRINFO pErrInfo);

/** @name RTCRPKCS7VERIFY_SD_F_XXX - Flags for RTCrPkcs7VerifySignedData and
 *                                   RTCrPkcs7VerifySignedDataWithExternalData
 * @{ */
/** Always use the signing time attribute if present, requiring it to be
 * verified as valid.  The default behavior is to ignore unverifiable
 * signing time attributes and use the @a pValidationTime instead. */
#define RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT     RT_BIT_32(0)
/** Same as RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT for the MS
 *  timestamp counter signatures. */
#define RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT     RT_BIT_32(1)
/** Only use signing time attributes from counter signatures. */
#define RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY    RT_BIT_32(2)
/** Don't validate the counter signature containing the signing time, just use
 * it unverified.  This is useful if we don't necessarily have the root
 * certificates for the timestamp server handy, but use with great care.
 * @sa RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED */
#define RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED            RT_BIT_32(3)
/** Don't validate the MS counter signature containing the signing timestamp.
 * @sa RTCRPKCS7VERIFY_SD_F_USE_SIGNING_TIME_UNVERIFIED */
#define RTCRPKCS7VERIFY_SD_F_USE_MS_TIMESTAMP_UNVERIFIED            RT_BIT_32(4)
/** Do not consider timestamps in microsoft counter signatures. */
#define RTCRPKCS7VERIFY_SD_F_IGNORE_MS_TIMESTAMP                    RT_BIT_32(5)
/** The signed data requires certificates to have the timestamp extended
 * usage bit present.  This is used for recursivly verifying MS timestamp
 * signatures. */
#define RTCRPKCS7VERIFY_SD_F_USAGE_TIMESTAMPING                     RT_BIT_32(6)
/** Skip the verification of the certificate trust paths, taking all
 * certificates to be trustworthy. */
#define RTCRPKCS7VERIFY_SD_F_TRUST_ALL_CERTS                        RT_BIT_32(7)
/** Update @a pValidationTime with the actual validation time used.
 * This requires RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX to get a consistent
 * result.  And yeah, it unconst the parameter, which is patently ugly. */
#define RTCRPKCS7VERIFY_SD_F_UPDATE_VALIDATION_TIME                 RT_BIT_32(8)
/** Check trust anchors (@sa RTCrX509CertPathsSetTrustAnchorChecks). */
#define RTCRPKCS7VERIFY_SD_F_CHECK_TRUST_ANCHORS                    RT_BIT_32(9)

/** This can be used to only verify one given signer info.
 * Max index value is 15.  */
#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX(a_idxSignerInfo) \
    (  RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX \
     | (((a_idxSignerInfo) & RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MAX) << RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT) )
/** Has a valid value in RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK. */
#define RTCRPKCS7VERIFY_SD_F_HAS_SIGNER_INDEX                       RT_BIT_32(23)
/** Signer index shift value. */
#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT                     24
/** Signer index mask. */
#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK                      UINT32_C(0x0f000000)
/** Max signer index value (inclusive). */
#define RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MAX \
    (RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_MASK >> RTCRPKCS7VERIFY_SD_F_SIGNER_INDEX_SHIFT)

/** Indicates internally that we're validating a counter signature and should
 * use different rules when checking out the authenticated attributes.
 * @internal  */
#define RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE                      RT_BIT_32(31)
/** @} */


RTDECL(int) RTCrPkcs7SimpleSignSignedData(uint32_t fFlags, PCRTCRX509CERTIFICATE pSigner, RTCRKEY hPrivateKey,
                                          void const *pvData, size_t cbData, RTDIGESTTYPE enmDigestType,
                                          RTCRSTORE hAdditionalCerts, PCRTCRPKCS7ATTRIBUTES pAdditionalAuthenticatedAttribs,
                                          void *pvResult, size_t *pcbResult, PRTERRINFO pErrInfo);

/** @name RTCRPKCS7SIGN_SD_F_XXX - Flags for RTCrPkcs7SimpleSign.
 * @{ */
/** Detached data. */
#define RTCRPKCS7SIGN_SD_F_DEATCHED         RT_BIT_32(0)
/** No SMIME capabilities attribute. */
#define RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP     RT_BIT_32(1)
/** Produce version 1 output (PKCS\#7), rather than version 3 (CMS). */
#define RTCRPKCS7SIGN_SD_F_USE_V1           RT_BIT_32(2)
/** Avoid extra OCTET STRING encapsulation around the data blob.
 * This is needed for Authenticode signatures.  This requires that the
 * content type is supplied via the additional authenticated attributes.
 * @note Currently only works with RTCRPKCS7SIGN_SD_F_USE_V1.  */
#define RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP    RT_BIT_32(3)
/** Valid flag mask.   */
#define RTCRPKCS7SIGN_SD_F_VALID_MASK       UINT32_C(0x0000000f)
/** @} */

/** @} */

RT_C_DECLS_END

#endif /* !IPRT_INCLUDED_crypto_pkcs7_h */