-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
595 additions
and
1,227 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
pyasn1>=0.4.0,!=0.5.0 | ||
certvalidator>=0.11 | ||
asn1crypto>=1.3,<2 | ||
oscrypto>=1.1,<2 | ||
pyasn1-modules>=0.2.8 | ||
mscerts | ||
typing_extensions>=4.6.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,5 @@ | ||
from __future__ import annotations | ||
|
||
from typing import Any, TypeVar, overload | ||
from . import ctl, spc | ||
|
||
from pyasn1.type.base import Asn1Type | ||
|
||
from . import ctl, oids, pkcs7, spc | ||
|
||
__all__ = ["pkcs7", "spc", "oids", "ctl", "guarded_ber_decode", "guarded_der_decode"] | ||
|
||
|
||
_T = TypeVar("_T", bound=Asn1Type) | ||
|
||
|
||
@overload | ||
def guarded_ber_decode(data: Any, asn1_spec: _T) -> _T: ... | ||
|
||
|
||
@overload | ||
def guarded_ber_decode(data: Any, asn1_spec: None = None) -> Asn1Type: ... | ||
|
||
|
||
def guarded_ber_decode(data: Any, asn1_spec: _T | None = None) -> Asn1Type | _T: | ||
from pyasn1.codec.ber import decoder as ber_decoder | ||
|
||
from signify import _print_type | ||
from signify.exceptions import ParseError | ||
|
||
try: | ||
result, rest = ber_decoder.decode(data, asn1Spec=asn1_spec) | ||
except Exception as e: | ||
raise ParseError(f"Error while parsing {_print_type(asn1_spec)} BER: {e}") | ||
if rest: | ||
raise ParseError( | ||
"Extra information after parsing %s BER" % _print_type(asn1_spec) | ||
) | ||
return result | ||
|
||
|
||
@overload | ||
def guarded_der_decode(data: Any, asn1_spec: _T) -> _T: ... | ||
|
||
|
||
@overload | ||
def guarded_der_decode(data: Any, asn1_spec: None = None) -> Asn1Type: ... | ||
|
||
|
||
def guarded_der_decode(data: Any, asn1_spec: _T | None = None) -> Asn1Type | _T: | ||
from pyasn1.codec.der import decoder as der_decoder | ||
|
||
from signify import _print_type | ||
from signify.exceptions import ParseError | ||
|
||
try: | ||
result, rest = der_decoder.decode(data, asn1Spec=asn1_spec) | ||
except Exception as e: | ||
raise ParseError(f"Error while parsing {_print_type(asn1_spec)} DER: {e}") | ||
if rest: | ||
raise ParseError( | ||
"Extra information after parsing %s DER" % _print_type(asn1_spec) | ||
) | ||
return result | ||
__all__ = ["spc", "ctl"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,98 +1,165 @@ | ||
from pyasn1.type import namedtype, namedval, tag, univ | ||
from pyasn1_modules import rfc2315, rfc5280 | ||
from __future__ import annotations | ||
|
||
import datetime | ||
import struct | ||
from typing import Any, cast | ||
|
||
from asn1crypto.algos import DigestAlgorithm | ||
from asn1crypto.cms import ContentInfo, ContentType, EncapsulatedContentInfo | ||
from asn1crypto.core import ( | ||
Asn1Value, | ||
BMPString, | ||
Integer, | ||
ObjectIdentifier, | ||
OctetString, | ||
Sequence, | ||
SequenceOf, | ||
SetOf, | ||
) | ||
from asn1crypto.util import utc_with_dst | ||
from asn1crypto.x509 import Extensions, ExtKeyUsageSyntax, Time | ||
|
||
# Based on http://download.microsoft.com/download/C/8/8/C8862966-5948-444D-87BD-07B976ADA28C/%5BMS-CAESO%5D.pdf | ||
|
||
|
||
class CTLVersion(univ.Integer): # type: ignore[misc] | ||
namedValues = namedval.NamedValues(("v1", 0)) | ||
class CTLVersion(Integer): # type: ignore[misc] | ||
_map = { | ||
0: "v1", | ||
} | ||
|
||
|
||
class SubjectUsage(rfc5280.ExtKeyUsageSyntax): # type: ignore[misc] | ||
class SubjectUsage(ExtKeyUsageSyntax): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class ListIdentifier(univ.OctetString): # type: ignore[misc] | ||
class ListIdentifier(OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class SubjectIdentifier(univ.OctetString): # type: ignore[misc] | ||
class SubjectIdentifier(OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class TrustedSubject(univ.Sequence): # type: ignore[misc] | ||
componentType = namedtype.NamedTypes( | ||
namedtype.NamedType("subjectIdentifier", SubjectIdentifier()), | ||
namedtype.OptionalNamedType("subjectAttributes", rfc2315.Attributes()), | ||
) | ||
|
||
|
||
class TrustedSubjects(univ.SequenceOf): # type: ignore[misc] | ||
componentType = TrustedSubject() | ||
|
||
|
||
class CertificateTrustList(univ.Sequence): # type: ignore[misc] | ||
componentType = namedtype.NamedTypes( | ||
namedtype.DefaultedNamedType("version", CTLVersion("v1")), | ||
namedtype.NamedType("subjectUsage", SubjectUsage()), | ||
namedtype.OptionalNamedType("listIdentifier", ListIdentifier()), | ||
namedtype.OptionalNamedType("sequenceNumber", univ.Integer()), | ||
namedtype.NamedType("ctlThisUpdate", rfc5280.Time()), | ||
namedtype.OptionalNamedType("ctlNextUpdate", rfc5280.Time()), | ||
namedtype.NamedType("subjectAlgorithm", rfc5280.AlgorithmIdentifier()), | ||
namedtype.OptionalNamedType("trustedSubjects", TrustedSubjects()), | ||
namedtype.OptionalNamedType( | ||
"ctlExtensions", | ||
rfc5280.Extensions().subtype( | ||
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0) | ||
), | ||
), | ||
) | ||
|
||
|
||
# The following are known attributes | ||
|
||
|
||
class EnhkeyUsage(rfc5280.ExtKeyUsageSyntax): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class FriendlyName(univ.OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class KeyIdentifier(univ.OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class SubjectNameMd5Hash(univ.OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class RootProgramCertPolicies(univ.OctetString): # type: ignore[misc] | ||
# TODO: not implemented | ||
pass | ||
|
||
|
||
class AuthRootSha256Hash(univ.OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class DisallowedFiletime(univ.OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class RootProgramChainPolicies(rfc5280.ExtKeyUsageSyntax): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class DisallowedEnhkeyUsage(rfc5280.ExtKeyUsageSyntax): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class NotBeforeFiletime(univ.OctetString): # type: ignore[misc] | ||
pass | ||
|
||
|
||
class NotBeforeEnhkeyUsage(rfc5280.ExtKeyUsageSyntax): # type: ignore[misc] | ||
pass | ||
class SubjectAttributeType(ObjectIdentifier): # type: ignore[misc] | ||
_map = { | ||
"1.3.6.1.4.1.311.10.11.9": "microsoft_ctl_enhkey_usage", | ||
"1.3.6.1.4.1.311.10.11.11": "microsoft_ctl_friendly_name", | ||
"1.3.6.1.4.1.311.10.11.20": "microsoft_ctl_key_identifier", | ||
"1.3.6.1.4.1.311.10.11.29": "microsoft_ctl_subject_name_md5_hash", | ||
"1.3.6.1.4.1.311.10.11.83": "microsoft_ctl_root_program_cert_policies", | ||
"1.3.6.1.4.1.311.10.11.98": "microsoft_ctl_auth_root_sha256_hash", | ||
"1.3.6.1.4.1.311.10.11.104": "microsoft_ctl_disallowed_filetime", | ||
"1.3.6.1.4.1.311.10.11.105": "microsoft_ctl_root_program_chain_policies", | ||
"1.3.6.1.4.1.311.10.11.122": "microsoft_ctl_disallowed_enhkey_usage", | ||
"1.3.6.1.4.1.311.10.11.126": "microsoft_ctl_not_before_filetime", | ||
"1.3.6.1.4.1.311.10.11.127": "microsoft_ctl_not_before_enhkey_usage", | ||
} | ||
|
||
|
||
class SetOfSpecificOctetString(SetOf): # type: ignore[misc] | ||
_child_spec = OctetString | ||
children: Any | ||
|
||
def parse( | ||
self, spec: type[Asn1Value] | None = None, spec_params: Any = None | ||
) -> Any: | ||
if not spec: | ||
return self.children | ||
if issubclass(spec, SequenceOf): | ||
self.children = [spec.load(child.contents) for child in self] | ||
else: | ||
self.children = [spec(contents=child.contents) for child in self] | ||
return self.children | ||
|
||
|
||
class CTLString(BMPString): # type: ignore[misc] | ||
_encoding = "utf-16-le" | ||
|
||
def __unicode__(self) -> str: | ||
return cast(str, super().__unicode__().rstrip("\0")) | ||
|
||
|
||
class FileTime(OctetString): # type: ignore[misc] | ||
_epoch = datetime.datetime(1601, 1, 1, tzinfo=datetime.timezone.utc) | ||
_native: datetime.datetime | None | ||
|
||
@property | ||
def native(self) -> datetime.datetime | None: | ||
if self.contents is None or not self.contents: | ||
return None | ||
|
||
if self._native is None: | ||
value = struct.unpack("<Q", self.contents)[0] | ||
self._native = self._epoch + datetime.timedelta(microseconds=value / 10) | ||
|
||
return self._native | ||
|
||
def set(self, value: Any) -> None: | ||
if isinstance(value, datetime.datetime): | ||
if not value.tzinfo: | ||
raise ValueError("Must be timezone aware") | ||
value = value.astimezone(utc_with_dst) | ||
value = struct.pack("<Q", int((value - self._epoch).total_seconds() * 100)) | ||
OctetString.set(self, value) | ||
self._native = None | ||
|
||
|
||
class SubjectAttribute(Sequence): # type: ignore[misc] | ||
_fields = [ | ||
("type", SubjectAttributeType), | ||
("values", SetOfSpecificOctetString), | ||
] | ||
_oid_specs: dict[str, type[Asn1Value]] = { | ||
"microsoft_ctl_enhkey_usage": ExtKeyUsageSyntax, | ||
"microsoft_ctl_friendly_name": CTLString, | ||
# "microsoft_ctl_key_identifier": OctetString, | ||
# "microsoft_ctl_subject_name_md5_hash": OctetString, | ||
# "microsoft_ctl_root_program_cert_policies": ExtKeyUsageSyntax, | ||
# "microsoft_ctl_auth_root_sha256_hash": OctetString, | ||
"microsoft_ctl_disallowed_filetime": FileTime, | ||
# "microsoft_ctl_root_program_chain_policies": ExtKeyUsageSyntax, | ||
"microsoft_ctl_disallowed_enhkey_usage": ExtKeyUsageSyntax, | ||
"microsoft_ctl_not_before_filetime": FileTime, | ||
"microsoft_ctl_not_before_enhkey_usage": ExtKeyUsageSyntax, | ||
} | ||
|
||
def _values_spec(self) -> type[Asn1Value] | None: | ||
return self._oid_specs.get(self["type"].native, None) | ||
|
||
_spec_callbacks = {"values": _values_spec} | ||
|
||
|
||
class SubjectAttributes(SetOf): # type: ignore[misc] | ||
_child_spec = SubjectAttribute | ||
|
||
|
||
class TrustedSubject(Sequence): # type: ignore[misc] | ||
_fields = [ | ||
("subject_identifier", SubjectIdentifier), | ||
("subject_attributes", SubjectAttributes, {"optional": True}), | ||
] | ||
|
||
|
||
class TrustedSubjects(SequenceOf): # type: ignore[misc] | ||
_child_spec = TrustedSubject | ||
|
||
|
||
class CertificateTrustList(Sequence): # type: ignore[misc] | ||
_fields = [ | ||
("version", CTLVersion, {"default": "v1"}), | ||
("subject_usage", SubjectUsage), | ||
("list_identifier", ListIdentifier, {"optional": True}), | ||
("sequence_number", Integer, {"optional": True}), | ||
("ctl_this_update", Time), | ||
("ctl_next_update", Time, {"optional": True}), | ||
("subject_algorithm", DigestAlgorithm), | ||
("trusted_subjects", TrustedSubjects, {"optional": True}), | ||
("ctl_extensions", Extensions, {"optional": True, "explicit": 0}), | ||
] | ||
|
||
|
||
# Add CTL to acceptable options | ||
ContentType._map["1.3.6.1.4.1.311.10.1"] = "microsoft_ctl" | ||
ContentInfo._oid_specs["microsoft_ctl"] = EncapsulatedContentInfo._oid_specs[ | ||
"microsoft_ctl" | ||
] = CertificateTrustList |
Oops, something went wrong.