• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# coding: utf-8
2
3"""
4ASN.1 type classes for cryptographic message syntax (CMS). Structures are also
5compatible with PKCS#7. Exports the following items:
6
7 - AuthenticatedData()
8 - AuthEnvelopedData()
9 - CompressedData()
10 - ContentInfo()
11 - DigestedData()
12 - EncryptedData()
13 - EnvelopedData()
14 - SignedAndEnvelopedData()
15 - SignedData()
16
17Other type classes are defined that help compose the types listed above.
18
19Most CMS structures in the wild are formatted as ContentInfo encapsulating one of the other types.
20"""
21
22from __future__ import unicode_literals, division, absolute_import, print_function
23
24try:
25    import zlib
26except (ImportError):
27    zlib = None
28
29from .algos import (
30    _ForceNullParameters,
31    DigestAlgorithm,
32    EncryptionAlgorithm,
33    HmacAlgorithm,
34    KdfAlgorithm,
35    RSAESOAEPParams,
36    SignedDigestAlgorithm,
37)
38from .core import (
39    Any,
40    BitString,
41    Choice,
42    Enumerated,
43    GeneralizedTime,
44    Integer,
45    ObjectIdentifier,
46    OctetBitString,
47    OctetString,
48    ParsableOctetString,
49    Sequence,
50    SequenceOf,
51    SetOf,
52    UTCTime,
53    UTF8String,
54)
55from .crl import CertificateList
56from .keys import PublicKeyInfo
57from .ocsp import OCSPResponse
58from .x509 import Attributes, Certificate, Extensions, GeneralName, GeneralNames, Name
59
60
61# These structures are taken from
62# ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-6.asc
63
64class ExtendedCertificateInfo(Sequence):
65    _fields = [
66        ('version', Integer),
67        ('certificate', Certificate),
68        ('attributes', Attributes),
69    ]
70
71
72class ExtendedCertificate(Sequence):
73    _fields = [
74        ('extended_certificate_info', ExtendedCertificateInfo),
75        ('signature_algorithm', SignedDigestAlgorithm),
76        ('signature', OctetBitString),
77    ]
78
79
80# These structures are taken from https://tools.ietf.org/html/rfc5652,
81# https://tools.ietf.org/html/rfc5083, http://tools.ietf.org/html/rfc2315,
82# https://tools.ietf.org/html/rfc5940, https://tools.ietf.org/html/rfc3274,
83# https://tools.ietf.org/html/rfc3281
84
85
86class CMSVersion(Integer):
87    _map = {
88        0: 'v0',
89        1: 'v1',
90        2: 'v2',
91        3: 'v3',
92        4: 'v4',
93        5: 'v5',
94    }
95
96
97class CMSAttributeType(ObjectIdentifier):
98    _map = {
99        '1.2.840.113549.1.9.3': 'content_type',
100        '1.2.840.113549.1.9.4': 'message_digest',
101        '1.2.840.113549.1.9.5': 'signing_time',
102        '1.2.840.113549.1.9.6': 'counter_signature',
103        # https://tools.ietf.org/html/rfc2633#page-26
104        '1.2.840.113549.1.9.16.2.11': 'encrypt_key_pref',
105        # https://tools.ietf.org/html/rfc3161#page-20
106        '1.2.840.113549.1.9.16.2.14': 'signature_time_stamp_token',
107        # https://tools.ietf.org/html/rfc6211#page-5
108        '1.2.840.113549.1.9.52': 'cms_algorithm_protection',
109        # https://docs.microsoft.com/en-us/previous-versions/hh968145(v%3Dvs.85)
110        '1.3.6.1.4.1.311.2.4.1': 'microsoft_nested_signature',
111        # Some places refer to this as SPC_RFC3161_OBJID, others szOID_RFC3161_counterSign.
112        # https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-crypt_algorithm_identifier
113        # refers to szOID_RFC3161_counterSign as "1.2.840.113549.1.9.16.1.4",
114        # but that OID is also called szOID_TIMESTAMP_TOKEN. Because of there being
115        # no canonical source for this OID, we give it our own name
116        '1.3.6.1.4.1.311.3.3.1': 'microsoft_time_stamp_token',
117    }
118
119
120class Time(Choice):
121    _alternatives = [
122        ('utc_time', UTCTime),
123        ('generalized_time', GeneralizedTime),
124    ]
125
126
127class ContentType(ObjectIdentifier):
128    _map = {
129        '1.2.840.113549.1.7.1': 'data',
130        '1.2.840.113549.1.7.2': 'signed_data',
131        '1.2.840.113549.1.7.3': 'enveloped_data',
132        '1.2.840.113549.1.7.4': 'signed_and_enveloped_data',
133        '1.2.840.113549.1.7.5': 'digested_data',
134        '1.2.840.113549.1.7.6': 'encrypted_data',
135        '1.2.840.113549.1.9.16.1.2': 'authenticated_data',
136        '1.2.840.113549.1.9.16.1.9': 'compressed_data',
137        '1.2.840.113549.1.9.16.1.23': 'authenticated_enveloped_data',
138    }
139
140
141class CMSAlgorithmProtection(Sequence):
142    _fields = [
143        ('digest_algorithm', DigestAlgorithm),
144        ('signature_algorithm', SignedDigestAlgorithm, {'implicit': 1, 'optional': True}),
145        ('mac_algorithm', HmacAlgorithm, {'implicit': 2, 'optional': True}),
146    ]
147
148
149class SetOfContentType(SetOf):
150    _child_spec = ContentType
151
152
153class SetOfOctetString(SetOf):
154    _child_spec = OctetString
155
156
157class SetOfTime(SetOf):
158    _child_spec = Time
159
160
161class SetOfAny(SetOf):
162    _child_spec = Any
163
164
165class SetOfCMSAlgorithmProtection(SetOf):
166    _child_spec = CMSAlgorithmProtection
167
168
169class CMSAttribute(Sequence):
170    _fields = [
171        ('type', CMSAttributeType),
172        ('values', None),
173    ]
174
175    _oid_specs = {}
176
177    def _values_spec(self):
178        return self._oid_specs.get(self['type'].native, SetOfAny)
179
180    _spec_callbacks = {
181        'values': _values_spec
182    }
183
184
185class CMSAttributes(SetOf):
186    _child_spec = CMSAttribute
187
188
189class IssuerSerial(Sequence):
190    _fields = [
191        ('issuer', GeneralNames),
192        ('serial', Integer),
193        ('issuer_uid', OctetBitString, {'optional': True}),
194    ]
195
196
197class AttCertVersion(Integer):
198    _map = {
199        0: 'v1',
200        1: 'v2',
201    }
202
203
204class AttCertSubject(Choice):
205    _alternatives = [
206        ('base_certificate_id', IssuerSerial, {'explicit': 0}),
207        ('subject_name', GeneralNames, {'explicit': 1}),
208    ]
209
210
211class AttCertValidityPeriod(Sequence):
212    _fields = [
213        ('not_before_time', GeneralizedTime),
214        ('not_after_time', GeneralizedTime),
215    ]
216
217
218class AttributeCertificateInfoV1(Sequence):
219    _fields = [
220        ('version', AttCertVersion, {'default': 'v1'}),
221        ('subject', AttCertSubject),
222        ('issuer', GeneralNames),
223        ('signature', SignedDigestAlgorithm),
224        ('serial_number', Integer),
225        ('att_cert_validity_period', AttCertValidityPeriod),
226        ('attributes', Attributes),
227        ('issuer_unique_id', OctetBitString, {'optional': True}),
228        ('extensions', Extensions, {'optional': True}),
229    ]
230
231
232class AttributeCertificateV1(Sequence):
233    _fields = [
234        ('ac_info', AttributeCertificateInfoV1),
235        ('signature_algorithm', SignedDigestAlgorithm),
236        ('signature', OctetBitString),
237    ]
238
239
240class DigestedObjectType(Enumerated):
241    _map = {
242        0: 'public_key',
243        1: 'public_key_cert',
244        2: 'other_objy_types',
245    }
246
247
248class ObjectDigestInfo(Sequence):
249    _fields = [
250        ('digested_object_type', DigestedObjectType),
251        ('other_object_type_id', ObjectIdentifier, {'optional': True}),
252        ('digest_algorithm', DigestAlgorithm),
253        ('object_digest', OctetBitString),
254    ]
255
256
257class Holder(Sequence):
258    _fields = [
259        ('base_certificate_id', IssuerSerial, {'implicit': 0, 'optional': True}),
260        ('entity_name', GeneralNames, {'implicit': 1, 'optional': True}),
261        ('object_digest_info', ObjectDigestInfo, {'implicit': 2, 'optional': True}),
262    ]
263
264
265class V2Form(Sequence):
266    _fields = [
267        ('issuer_name', GeneralNames, {'optional': True}),
268        ('base_certificate_id', IssuerSerial, {'explicit': 0, 'optional': True}),
269        ('object_digest_info', ObjectDigestInfo, {'explicit': 1, 'optional': True}),
270    ]
271
272
273class AttCertIssuer(Choice):
274    _alternatives = [
275        ('v1_form', GeneralNames),
276        ('v2_form', V2Form, {'explicit': 0}),
277    ]
278
279
280class IetfAttrValue(Choice):
281    _alternatives = [
282        ('octets', OctetString),
283        ('oid', ObjectIdentifier),
284        ('string', UTF8String),
285    ]
286
287
288class IetfAttrValues(SequenceOf):
289    _child_spec = IetfAttrValue
290
291
292class IetfAttrSyntax(Sequence):
293    _fields = [
294        ('policy_authority', GeneralNames, {'implicit': 0, 'optional': True}),
295        ('values', IetfAttrValues),
296    ]
297
298
299class SetOfIetfAttrSyntax(SetOf):
300    _child_spec = IetfAttrSyntax
301
302
303class SvceAuthInfo(Sequence):
304    _fields = [
305        ('service', GeneralName),
306        ('ident', GeneralName),
307        ('auth_info', OctetString, {'optional': True}),
308    ]
309
310
311class SetOfSvceAuthInfo(SetOf):
312    _child_spec = SvceAuthInfo
313
314
315class RoleSyntax(Sequence):
316    _fields = [
317        ('role_authority', GeneralNames, {'implicit': 0, 'optional': True}),
318        ('role_name', GeneralName, {'implicit': 1}),
319    ]
320
321
322class SetOfRoleSyntax(SetOf):
323    _child_spec = RoleSyntax
324
325
326class ClassList(BitString):
327    _map = {
328        0: 'unmarked',
329        1: 'unclassified',
330        2: 'restricted',
331        3: 'confidential',
332        4: 'secret',
333        5: 'top_secret',
334    }
335
336
337class SecurityCategory(Sequence):
338    _fields = [
339        ('type', ObjectIdentifier, {'implicit': 0}),
340        ('value', Any, {'implicit': 1}),
341    ]
342
343
344class SetOfSecurityCategory(SetOf):
345    _child_spec = SecurityCategory
346
347
348class Clearance(Sequence):
349    _fields = [
350        ('policy_id', ObjectIdentifier, {'implicit': 0}),
351        ('class_list', ClassList, {'implicit': 1, 'default': 'unclassified'}),
352        ('security_categories', SetOfSecurityCategory, {'implicit': 2, 'optional': True}),
353    ]
354
355
356class SetOfClearance(SetOf):
357    _child_spec = Clearance
358
359
360class BigTime(Sequence):
361    _fields = [
362        ('major', Integer),
363        ('fractional_seconds', Integer),
364        ('sign', Integer, {'optional': True}),
365    ]
366
367
368class LeapData(Sequence):
369    _fields = [
370        ('leap_time', BigTime),
371        ('action', Integer),
372    ]
373
374
375class SetOfLeapData(SetOf):
376    _child_spec = LeapData
377
378
379class TimingMetrics(Sequence):
380    _fields = [
381        ('ntp_time', BigTime),
382        ('offset', BigTime),
383        ('delay', BigTime),
384        ('expiration', BigTime),
385        ('leap_event', SetOfLeapData, {'optional': True}),
386    ]
387
388
389class SetOfTimingMetrics(SetOf):
390    _child_spec = TimingMetrics
391
392
393class TimingPolicy(Sequence):
394    _fields = [
395        ('policy_id', SequenceOf, {'spec': ObjectIdentifier}),
396        ('max_offset', BigTime, {'explicit': 0, 'optional': True}),
397        ('max_delay', BigTime, {'explicit': 1, 'optional': True}),
398    ]
399
400
401class SetOfTimingPolicy(SetOf):
402    _child_spec = TimingPolicy
403
404
405class AttCertAttributeType(ObjectIdentifier):
406    _map = {
407        '1.3.6.1.5.5.7.10.1': 'authentication_info',
408        '1.3.6.1.5.5.7.10.2': 'access_identity',
409        '1.3.6.1.5.5.7.10.3': 'charging_identity',
410        '1.3.6.1.5.5.7.10.4': 'group',
411        '2.5.4.72': 'role',
412        '2.5.4.55': 'clearance',
413        '1.3.6.1.4.1.601.10.4.1': 'timing_metrics',
414        '1.3.6.1.4.1.601.10.4.2': 'timing_policy',
415    }
416
417
418class AttCertAttribute(Sequence):
419    _fields = [
420        ('type', AttCertAttributeType),
421        ('values', None),
422    ]
423
424    _oid_specs = {
425        'authentication_info': SetOfSvceAuthInfo,
426        'access_identity': SetOfSvceAuthInfo,
427        'charging_identity': SetOfIetfAttrSyntax,
428        'group': SetOfIetfAttrSyntax,
429        'role': SetOfRoleSyntax,
430        'clearance': SetOfClearance,
431        'timing_metrics': SetOfTimingMetrics,
432        'timing_policy': SetOfTimingPolicy,
433    }
434
435    def _values_spec(self):
436        return self._oid_specs.get(self['type'].native, SetOfAny)
437
438    _spec_callbacks = {
439        'values': _values_spec
440    }
441
442
443class AttCertAttributes(SequenceOf):
444    _child_spec = AttCertAttribute
445
446
447class AttributeCertificateInfoV2(Sequence):
448    _fields = [
449        ('version', AttCertVersion),
450        ('holder', Holder),
451        ('issuer', AttCertIssuer),
452        ('signature', SignedDigestAlgorithm),
453        ('serial_number', Integer),
454        ('att_cert_validity_period', AttCertValidityPeriod),
455        ('attributes', AttCertAttributes),
456        ('issuer_unique_id', OctetBitString, {'optional': True}),
457        ('extensions', Extensions, {'optional': True}),
458    ]
459
460
461class AttributeCertificateV2(Sequence):
462    # Handle the situation where a V2 cert is encoded as V1
463    _bad_tag = 1
464
465    _fields = [
466        ('ac_info', AttributeCertificateInfoV2),
467        ('signature_algorithm', SignedDigestAlgorithm),
468        ('signature', OctetBitString),
469    ]
470
471
472class OtherCertificateFormat(Sequence):
473    _fields = [
474        ('other_cert_format', ObjectIdentifier),
475        ('other_cert', Any),
476    ]
477
478
479class CertificateChoices(Choice):
480    _alternatives = [
481        ('certificate', Certificate),
482        ('extended_certificate', ExtendedCertificate, {'implicit': 0}),
483        ('v1_attr_cert', AttributeCertificateV1, {'implicit': 1}),
484        ('v2_attr_cert', AttributeCertificateV2, {'implicit': 2}),
485        ('other', OtherCertificateFormat, {'implicit': 3}),
486    ]
487
488    def validate(self, class_, tag, contents):
489        """
490        Ensures that the class and tag specified exist as an alternative. This
491        custom version fixes parsing broken encodings there a V2 attribute
492        # certificate is encoded as a V1
493
494        :param class_:
495            The integer class_ from the encoded value header
496
497        :param tag:
498            The integer tag from the encoded value header
499
500        :param contents:
501            A byte string of the contents of the value - used when the object
502            is explicitly tagged
503
504        :raises:
505            ValueError - when value is not a valid alternative
506        """
507
508        super(CertificateChoices, self).validate(class_, tag, contents)
509        if self._choice == 2:
510            if AttCertVersion.load(Sequence.load(contents)[0].dump()).native == 'v2':
511                self._choice = 3
512
513
514class CertificateSet(SetOf):
515    _child_spec = CertificateChoices
516
517
518class ContentInfo(Sequence):
519    _fields = [
520        ('content_type', ContentType),
521        ('content', Any, {'explicit': 0, 'optional': True}),
522    ]
523
524    _oid_pair = ('content_type', 'content')
525    _oid_specs = {}
526
527
528class SetOfContentInfo(SetOf):
529    _child_spec = ContentInfo
530
531
532class EncapsulatedContentInfo(Sequence):
533    _fields = [
534        ('content_type', ContentType),
535        ('content', ParsableOctetString, {'explicit': 0, 'optional': True}),
536    ]
537
538    _oid_pair = ('content_type', 'content')
539    _oid_specs = {}
540
541
542class IssuerAndSerialNumber(Sequence):
543    _fields = [
544        ('issuer', Name),
545        ('serial_number', Integer),
546    ]
547
548
549class SignerIdentifier(Choice):
550    _alternatives = [
551        ('issuer_and_serial_number', IssuerAndSerialNumber),
552        ('subject_key_identifier', OctetString, {'implicit': 0}),
553    ]
554
555
556class DigestAlgorithms(SetOf):
557    _child_spec = DigestAlgorithm
558
559
560class CertificateRevocationLists(SetOf):
561    _child_spec = CertificateList
562
563
564class SCVPReqRes(Sequence):
565    _fields = [
566        ('request', ContentInfo, {'explicit': 0, 'optional': True}),
567        ('response', ContentInfo),
568    ]
569
570
571class OtherRevInfoFormatId(ObjectIdentifier):
572    _map = {
573        '1.3.6.1.5.5.7.16.2': 'ocsp_response',
574        '1.3.6.1.5.5.7.16.4': 'scvp',
575    }
576
577
578class OtherRevocationInfoFormat(Sequence):
579    _fields = [
580        ('other_rev_info_format', OtherRevInfoFormatId),
581        ('other_rev_info', Any),
582    ]
583
584    _oid_pair = ('other_rev_info_format', 'other_rev_info')
585    _oid_specs = {
586        'ocsp_response': OCSPResponse,
587        'scvp': SCVPReqRes,
588    }
589
590
591class RevocationInfoChoice(Choice):
592    _alternatives = [
593        ('crl', CertificateList),
594        ('other', OtherRevocationInfoFormat, {'implicit': 1}),
595    ]
596
597
598class RevocationInfoChoices(SetOf):
599    _child_spec = RevocationInfoChoice
600
601
602class SignerInfo(Sequence):
603    _fields = [
604        ('version', CMSVersion),
605        ('sid', SignerIdentifier),
606        ('digest_algorithm', DigestAlgorithm),
607        ('signed_attrs', CMSAttributes, {'implicit': 0, 'optional': True}),
608        ('signature_algorithm', SignedDigestAlgorithm),
609        ('signature', OctetString),
610        ('unsigned_attrs', CMSAttributes, {'implicit': 1, 'optional': True}),
611    ]
612
613
614class SignerInfos(SetOf):
615    _child_spec = SignerInfo
616
617
618class SignedData(Sequence):
619    _fields = [
620        ('version', CMSVersion),
621        ('digest_algorithms', DigestAlgorithms),
622        ('encap_content_info', None),
623        ('certificates', CertificateSet, {'implicit': 0, 'optional': True}),
624        ('crls', RevocationInfoChoices, {'implicit': 1, 'optional': True}),
625        ('signer_infos', SignerInfos),
626    ]
627
628    def _encap_content_info_spec(self):
629        # If the encap_content_info is version v1, then this could be a PKCS#7
630        # structure, or a CMS structure. CMS wraps the encoded value in an
631        # Octet String tag.
632
633        # If the version is greater than 1, it is definite CMS
634        if self['version'].native != 'v1':
635            return EncapsulatedContentInfo
636
637        # Otherwise, the ContentInfo spec from PKCS#7 will be compatible with
638        # CMS v1 (which only allows Data, an Octet String) and PKCS#7, which
639        # allows Any
640        return ContentInfo
641
642    _spec_callbacks = {
643        'encap_content_info': _encap_content_info_spec
644    }
645
646
647class OriginatorInfo(Sequence):
648    _fields = [
649        ('certs', CertificateSet, {'implicit': 0, 'optional': True}),
650        ('crls', RevocationInfoChoices, {'implicit': 1, 'optional': True}),
651    ]
652
653
654class RecipientIdentifier(Choice):
655    _alternatives = [
656        ('issuer_and_serial_number', IssuerAndSerialNumber),
657        ('subject_key_identifier', OctetString, {'implicit': 0}),
658    ]
659
660
661class KeyEncryptionAlgorithmId(ObjectIdentifier):
662    _map = {
663        '1.2.840.113549.1.1.1': 'rsaes_pkcs1v15',
664        '1.2.840.113549.1.1.7': 'rsaes_oaep',
665        '2.16.840.1.101.3.4.1.5': 'aes128_wrap',
666        '2.16.840.1.101.3.4.1.8': 'aes128_wrap_pad',
667        '2.16.840.1.101.3.4.1.25': 'aes192_wrap',
668        '2.16.840.1.101.3.4.1.28': 'aes192_wrap_pad',
669        '2.16.840.1.101.3.4.1.45': 'aes256_wrap',
670        '2.16.840.1.101.3.4.1.48': 'aes256_wrap_pad',
671    }
672
673    _reverse_map = {
674        'rsa': '1.2.840.113549.1.1.1',
675        'rsaes_pkcs1v15': '1.2.840.113549.1.1.1',
676        'rsaes_oaep': '1.2.840.113549.1.1.7',
677        'aes128_wrap': '2.16.840.1.101.3.4.1.5',
678        'aes128_wrap_pad': '2.16.840.1.101.3.4.1.8',
679        'aes192_wrap': '2.16.840.1.101.3.4.1.25',
680        'aes192_wrap_pad': '2.16.840.1.101.3.4.1.28',
681        'aes256_wrap': '2.16.840.1.101.3.4.1.45',
682        'aes256_wrap_pad': '2.16.840.1.101.3.4.1.48',
683    }
684
685
686class KeyEncryptionAlgorithm(_ForceNullParameters, Sequence):
687    _fields = [
688        ('algorithm', KeyEncryptionAlgorithmId),
689        ('parameters', Any, {'optional': True}),
690    ]
691
692    _oid_pair = ('algorithm', 'parameters')
693    _oid_specs = {
694        'rsaes_oaep': RSAESOAEPParams,
695    }
696
697
698class KeyTransRecipientInfo(Sequence):
699    _fields = [
700        ('version', CMSVersion),
701        ('rid', RecipientIdentifier),
702        ('key_encryption_algorithm', KeyEncryptionAlgorithm),
703        ('encrypted_key', OctetString),
704    ]
705
706
707class OriginatorIdentifierOrKey(Choice):
708    _alternatives = [
709        ('issuer_and_serial_number', IssuerAndSerialNumber),
710        ('subject_key_identifier', OctetString, {'implicit': 0}),
711        ('originator_key', PublicKeyInfo, {'implicit': 1}),
712    ]
713
714
715class OtherKeyAttribute(Sequence):
716    _fields = [
717        ('key_attr_id', ObjectIdentifier),
718        ('key_attr', Any),
719    ]
720
721
722class RecipientKeyIdentifier(Sequence):
723    _fields = [
724        ('subject_key_identifier', OctetString),
725        ('date', GeneralizedTime, {'optional': True}),
726        ('other', OtherKeyAttribute, {'optional': True}),
727    ]
728
729
730class KeyAgreementRecipientIdentifier(Choice):
731    _alternatives = [
732        ('issuer_and_serial_number', IssuerAndSerialNumber),
733        ('r_key_id', RecipientKeyIdentifier, {'implicit': 0}),
734    ]
735
736
737class RecipientEncryptedKey(Sequence):
738    _fields = [
739        ('rid', KeyAgreementRecipientIdentifier),
740        ('encrypted_key', OctetString),
741    ]
742
743
744class RecipientEncryptedKeys(SequenceOf):
745    _child_spec = RecipientEncryptedKey
746
747
748class KeyAgreeRecipientInfo(Sequence):
749    _fields = [
750        ('version', CMSVersion),
751        ('originator', OriginatorIdentifierOrKey, {'explicit': 0}),
752        ('ukm', OctetString, {'explicit': 1, 'optional': True}),
753        ('key_encryption_algorithm', KeyEncryptionAlgorithm),
754        ('recipient_encrypted_keys', RecipientEncryptedKeys),
755    ]
756
757
758class KEKIdentifier(Sequence):
759    _fields = [
760        ('key_identifier', OctetString),
761        ('date', GeneralizedTime, {'optional': True}),
762        ('other', OtherKeyAttribute, {'optional': True}),
763    ]
764
765
766class KEKRecipientInfo(Sequence):
767    _fields = [
768        ('version', CMSVersion),
769        ('kekid', KEKIdentifier),
770        ('key_encryption_algorithm', KeyEncryptionAlgorithm),
771        ('encrypted_key', OctetString),
772    ]
773
774
775class PasswordRecipientInfo(Sequence):
776    _fields = [
777        ('version', CMSVersion),
778        ('key_derivation_algorithm', KdfAlgorithm, {'implicit': 0, 'optional': True}),
779        ('key_encryption_algorithm', KeyEncryptionAlgorithm),
780        ('encrypted_key', OctetString),
781    ]
782
783
784class OtherRecipientInfo(Sequence):
785    _fields = [
786        ('ori_type', ObjectIdentifier),
787        ('ori_value', Any),
788    ]
789
790
791class RecipientInfo(Choice):
792    _alternatives = [
793        ('ktri', KeyTransRecipientInfo),
794        ('kari', KeyAgreeRecipientInfo, {'implicit': 1}),
795        ('kekri', KEKRecipientInfo, {'implicit': 2}),
796        ('pwri', PasswordRecipientInfo, {'implicit': 3}),
797        ('ori', OtherRecipientInfo, {'implicit': 4}),
798    ]
799
800
801class RecipientInfos(SetOf):
802    _child_spec = RecipientInfo
803
804
805class EncryptedContentInfo(Sequence):
806    _fields = [
807        ('content_type', ContentType),
808        ('content_encryption_algorithm', EncryptionAlgorithm),
809        ('encrypted_content', OctetString, {'implicit': 0, 'optional': True}),
810    ]
811
812
813class EnvelopedData(Sequence):
814    _fields = [
815        ('version', CMSVersion),
816        ('originator_info', OriginatorInfo, {'implicit': 0, 'optional': True}),
817        ('recipient_infos', RecipientInfos),
818        ('encrypted_content_info', EncryptedContentInfo),
819        ('unprotected_attrs', CMSAttributes, {'implicit': 1, 'optional': True}),
820    ]
821
822
823class SignedAndEnvelopedData(Sequence):
824    _fields = [
825        ('version', CMSVersion),
826        ('recipient_infos', RecipientInfos),
827        ('digest_algorithms', DigestAlgorithms),
828        ('encrypted_content_info', EncryptedContentInfo),
829        ('certificates', CertificateSet, {'implicit': 0, 'optional': True}),
830        ('crls', CertificateRevocationLists, {'implicit': 1, 'optional': True}),
831        ('signer_infos', SignerInfos),
832    ]
833
834
835class DigestedData(Sequence):
836    _fields = [
837        ('version', CMSVersion),
838        ('digest_algorithm', DigestAlgorithm),
839        ('encap_content_info', None),
840        ('digest', OctetString),
841    ]
842
843    def _encap_content_info_spec(self):
844        # If the encap_content_info is version v1, then this could be a PKCS#7
845        # structure, or a CMS structure. CMS wraps the encoded value in an
846        # Octet String tag.
847
848        # If the version is greater than 1, it is definite CMS
849        if self['version'].native != 'v1':
850            return EncapsulatedContentInfo
851
852        # Otherwise, the ContentInfo spec from PKCS#7 will be compatible with
853        # CMS v1 (which only allows Data, an Octet String) and PKCS#7, which
854        # allows Any
855        return ContentInfo
856
857    _spec_callbacks = {
858        'encap_content_info': _encap_content_info_spec
859    }
860
861
862class EncryptedData(Sequence):
863    _fields = [
864        ('version', CMSVersion),
865        ('encrypted_content_info', EncryptedContentInfo),
866        ('unprotected_attrs', CMSAttributes, {'implicit': 1, 'optional': True}),
867    ]
868
869
870class AuthenticatedData(Sequence):
871    _fields = [
872        ('version', CMSVersion),
873        ('originator_info', OriginatorInfo, {'implicit': 0, 'optional': True}),
874        ('recipient_infos', RecipientInfos),
875        ('mac_algorithm', HmacAlgorithm),
876        ('digest_algorithm', DigestAlgorithm, {'implicit': 1, 'optional': True}),
877        # This does not require the _spec_callbacks approach of SignedData and
878        # DigestedData since AuthenticatedData was not part of PKCS#7
879        ('encap_content_info', EncapsulatedContentInfo),
880        ('auth_attrs', CMSAttributes, {'implicit': 2, 'optional': True}),
881        ('mac', OctetString),
882        ('unauth_attrs', CMSAttributes, {'implicit': 3, 'optional': True}),
883    ]
884
885
886class AuthEnvelopedData(Sequence):
887    _fields = [
888        ('version', CMSVersion),
889        ('originator_info', OriginatorInfo, {'implicit': 0, 'optional': True}),
890        ('recipient_infos', RecipientInfos),
891        ('auth_encrypted_content_info', EncryptedContentInfo),
892        ('auth_attrs', CMSAttributes, {'implicit': 1, 'optional': True}),
893        ('mac', OctetString),
894        ('unauth_attrs', CMSAttributes, {'implicit': 2, 'optional': True}),
895    ]
896
897
898class CompressionAlgorithmId(ObjectIdentifier):
899    _map = {
900        '1.2.840.113549.1.9.16.3.8': 'zlib',
901    }
902
903
904class CompressionAlgorithm(Sequence):
905    _fields = [
906        ('algorithm', CompressionAlgorithmId),
907        ('parameters', Any, {'optional': True}),
908    ]
909
910
911class CompressedData(Sequence):
912    _fields = [
913        ('version', CMSVersion),
914        ('compression_algorithm', CompressionAlgorithm),
915        ('encap_content_info', EncapsulatedContentInfo),
916    ]
917
918    _decompressed = None
919
920    @property
921    def decompressed(self):
922        if self._decompressed is None:
923            if zlib is None:
924                raise SystemError('The zlib module is not available')
925            self._decompressed = zlib.decompress(self['encap_content_info']['content'].native)
926        return self._decompressed
927
928
929class RecipientKeyIdentifier(Sequence):
930    _fields = [
931        ('subjectKeyIdentifier', OctetString),
932        ('date', GeneralizedTime, {'optional': True}),
933        ('other', OtherKeyAttribute, {'optional': True}),
934    ]
935
936
937class SMIMEEncryptionKeyPreference(Choice):
938    _alternatives = [
939        ('issuer_and_serial_number', IssuerAndSerialNumber, {'implicit': 0}),
940        ('recipientKeyId', RecipientKeyIdentifier, {'implicit': 1}),
941        ('subjectAltKeyIdentifier', PublicKeyInfo, {'implicit': 2}),
942    ]
943
944
945class SMIMEEncryptionKeyPreferences(SetOf):
946    _child_spec = SMIMEEncryptionKeyPreference
947
948
949ContentInfo._oid_specs = {
950    'data': OctetString,
951    'signed_data': SignedData,
952    'enveloped_data': EnvelopedData,
953    'signed_and_enveloped_data': SignedAndEnvelopedData,
954    'digested_data': DigestedData,
955    'encrypted_data': EncryptedData,
956    'authenticated_data': AuthenticatedData,
957    'compressed_data': CompressedData,
958    'authenticated_enveloped_data': AuthEnvelopedData,
959}
960
961
962EncapsulatedContentInfo._oid_specs = {
963    'signed_data': SignedData,
964    'enveloped_data': EnvelopedData,
965    'signed_and_enveloped_data': SignedAndEnvelopedData,
966    'digested_data': DigestedData,
967    'encrypted_data': EncryptedData,
968    'authenticated_data': AuthenticatedData,
969    'compressed_data': CompressedData,
970    'authenticated_enveloped_data': AuthEnvelopedData,
971}
972
973
974CMSAttribute._oid_specs = {
975    'content_type': SetOfContentType,
976    'message_digest': SetOfOctetString,
977    'signing_time': SetOfTime,
978    'counter_signature': SignerInfos,
979    'signature_time_stamp_token': SetOfContentInfo,
980    'cms_algorithm_protection': SetOfCMSAlgorithmProtection,
981    'microsoft_nested_signature': SetOfContentInfo,
982    'microsoft_time_stamp_token': SetOfContentInfo,
983    'encrypt_key_pref': SMIMEEncryptionKeyPreferences,
984}
985