mirror of
https://github.com/saymrwulf/cryptography.git
synced 2026-05-14 20:37:55 +00:00
add SubjectInformationAccess extension support (#5295)
* add SubjectInformationAccess extension support * fixes
This commit is contained in:
parent
63d337e5cc
commit
13fae162da
11 changed files with 406 additions and 21 deletions
|
|
@ -35,6 +35,8 @@ Changelog
|
|||
* Added :meth:`~cryptography.fernet.Fernet.encrypt_at_time` and
|
||||
:meth:`~cryptography.fernet.Fernet.decrypt_at_time` to
|
||||
:class:`~cryptography.fernet.Fernet`.
|
||||
* Added support for the :class:`~cryptography.x509.SubjectInformationAccess`
|
||||
X.509 extension.
|
||||
|
||||
.. _v2-9-2:
|
||||
|
||||
|
|
|
|||
|
|
@ -401,6 +401,9 @@ Custom X.509 Vectors
|
|||
a ``policyConstraints`` extension with a ``requireExplicitPolicy`` value.
|
||||
* ``freshestcrl.pem`` - A self-signed certificate containing a ``freshestCRL``
|
||||
extension.
|
||||
* ``sia.pem`` - An RSA 2048 bit self-signed certificate containing a subject
|
||||
information access extension with both a CA repository entry and a custom
|
||||
OID entry.
|
||||
* ``ca/ca.pem`` - A self-signed certificate with ``basicConstraints`` set to
|
||||
true. Its private key is ``ca/ca_key.pem``. This certificate is encoded in
|
||||
several of the PKCS12 custom vectors.
|
||||
|
|
|
|||
|
|
@ -2146,6 +2146,29 @@ X.509 Extensions
|
|||
:attr:`~cryptography.x509.oid.ExtensionOID.AUTHORITY_INFORMATION_ACCESS`.
|
||||
|
||||
|
||||
.. class:: SubjectInformationAccess(descriptions)
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
The subject information access extension indicates how to access
|
||||
information and services for the subject of the certificate in which
|
||||
the extension appears. When the subject is a CA, information and
|
||||
services may include certificate validation services and CA policy
|
||||
data. When the subject is an end entity, the information describes
|
||||
the type of services offered and how to access them. It is an iterable,
|
||||
containing one or more :class:`~cryptography.x509.AccessDescription`
|
||||
instances.
|
||||
|
||||
:param list descriptions: A list of :class:`AccessDescription` objects.
|
||||
|
||||
.. attribute:: oid
|
||||
|
||||
:type: :class:`ObjectIdentifier`
|
||||
|
||||
Returns
|
||||
:attr:`~cryptography.x509.oid.ExtensionOID.SUBJECT_INFORMATION_ACCESS`.
|
||||
|
||||
|
||||
.. class:: AccessDescription(access_method, access_location)
|
||||
|
||||
.. versionadded:: 0.9
|
||||
|
|
@ -2155,16 +2178,23 @@ X.509 Extensions
|
|||
:type: :class:`ObjectIdentifier`
|
||||
|
||||
The access method defines what the ``access_location`` means. It must
|
||||
be either
|
||||
be
|
||||
:attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.OCSP` or
|
||||
:attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.CA_ISSUERS`.
|
||||
:attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.CA_ISSUERS`
|
||||
when used with :class:`~cryptography.x509.AuthorityInformationAccess`
|
||||
or
|
||||
:attr:`~cryptography.x509.oid.SubjectInformationAccessOID.CA_REPOSITORY`
|
||||
when used with :class:`~cryptography.x509.SubjectInformationAccess`.
|
||||
|
||||
If it is
|
||||
:attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.OCSP`
|
||||
the access location will be where to obtain OCSP
|
||||
information for the certificate. If it is
|
||||
:attr:`~cryptography.x509.oid.AuthorityInformationAccessOID.CA_ISSUERS`
|
||||
the access location will provide additional information about the
|
||||
issuing certificate.
|
||||
issuing certificate. Finally, if it is
|
||||
:attr:`~cryptography.x509.oid.SubjectInformationAccessOID.CA_REPOSITORY`
|
||||
the access location will be the location of the CA's repository.
|
||||
|
||||
.. attribute:: access_location
|
||||
|
||||
|
|
@ -2973,6 +3003,17 @@ instances. The following common OIDs are available as constants.
|
|||
:class:`~cryptography.x509.AccessDescription` objects.
|
||||
|
||||
|
||||
.. class:: SubjectInformationAccessOID
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
.. attribute:: CA_REPOSITORY
|
||||
|
||||
Corresponds to the dotted string ``"1.3.6.1.5.5.7.48.5"``. Used as the
|
||||
identifier for CA repository data in
|
||||
:class:`~cryptography.x509.AccessDescription` objects.
|
||||
|
||||
|
||||
.. class:: CertificatePoliciesOID
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
|
@ -3050,6 +3091,14 @@ instances. The following common OIDs are available as constants.
|
|||
for the :class:`~cryptography.x509.AuthorityInformationAccess` extension
|
||||
type.
|
||||
|
||||
.. attribute:: SUBJECT_INFORMATION_ACCESS
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
Corresponds to the dotted string ``"1.3.6.1.5.5.7.1.11"``. The
|
||||
identifier for the :class:`~cryptography.x509.SubjectInformationAccess`
|
||||
extension type.
|
||||
|
||||
.. attribute:: INHIBIT_ANY_POLICY
|
||||
|
||||
Corresponds to the dotted string ``"2.5.29.54"``. The identifier
|
||||
|
|
|
|||
|
|
@ -377,29 +377,39 @@ def _decode_authority_key_identifier(backend, akid):
|
|||
)
|
||||
|
||||
|
||||
def _decode_authority_information_access(backend, aia):
|
||||
aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
|
||||
aia = backend._ffi.gc(
|
||||
aia,
|
||||
def _decode_information_access(backend, ia):
|
||||
ia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", ia)
|
||||
ia = backend._ffi.gc(
|
||||
ia,
|
||||
lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
|
||||
x, backend._ffi.addressof(
|
||||
backend._lib._original_lib, "ACCESS_DESCRIPTION_free"
|
||||
)
|
||||
)
|
||||
)
|
||||
num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
|
||||
num = backend._lib.sk_ACCESS_DESCRIPTION_num(ia)
|
||||
access_descriptions = []
|
||||
for i in range(num):
|
||||
ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
|
||||
ad = backend._lib.sk_ACCESS_DESCRIPTION_value(ia, i)
|
||||
backend.openssl_assert(ad.method != backend._ffi.NULL)
|
||||
oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
|
||||
backend.openssl_assert(ad.location != backend._ffi.NULL)
|
||||
gn = _decode_general_name(backend, ad.location)
|
||||
access_descriptions.append(x509.AccessDescription(oid, gn))
|
||||
|
||||
return access_descriptions
|
||||
|
||||
|
||||
def _decode_authority_information_access(backend, aia):
|
||||
access_descriptions = _decode_information_access(backend, aia)
|
||||
return x509.AuthorityInformationAccess(access_descriptions)
|
||||
|
||||
|
||||
def _decode_subject_information_access(backend, aia):
|
||||
access_descriptions = _decode_information_access(backend, aia)
|
||||
return x509.SubjectInformationAccess(access_descriptions)
|
||||
|
||||
|
||||
def _decode_key_usage(backend, bit_string):
|
||||
bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string)
|
||||
bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free)
|
||||
|
|
@ -816,6 +826,9 @@ _EXTENSION_HANDLERS_NO_SCT = {
|
|||
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
|
||||
_decode_authority_information_access
|
||||
),
|
||||
ExtensionOID.SUBJECT_INFORMATION_ACCESS: (
|
||||
_decode_subject_information_access
|
||||
),
|
||||
ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies,
|
||||
ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points,
|
||||
ExtensionOID.FRESHEST_CRL: _decode_freshest_crl,
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ def _encode_basic_constraints(backend, basic_constraints):
|
|||
return constraints
|
||||
|
||||
|
||||
def _encode_authority_information_access(backend, authority_info_access):
|
||||
def _encode_information_access(backend, info_access):
|
||||
aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null()
|
||||
backend.openssl_assert(aia != backend._ffi.NULL)
|
||||
aia = backend._ffi.gc(
|
||||
|
|
@ -354,7 +354,7 @@ def _encode_authority_information_access(backend, authority_info_access):
|
|||
)
|
||||
)
|
||||
)
|
||||
for access_description in authority_info_access:
|
||||
for access_description in info_access:
|
||||
ad = backend._lib.ACCESS_DESCRIPTION_new()
|
||||
method = _txt2obj(
|
||||
backend, access_description.access_method.dotted_string
|
||||
|
|
@ -622,9 +622,8 @@ _EXTENSION_ENCODE_HANDLERS = {
|
|||
ExtensionOID.EXTENDED_KEY_USAGE: _encode_extended_key_usage,
|
||||
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
|
||||
ExtensionOID.CERTIFICATE_POLICIES: _encode_certificate_policies,
|
||||
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
|
||||
_encode_authority_information_access
|
||||
),
|
||||
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access,
|
||||
ExtensionOID.SUBJECT_INFORMATION_ACCESS: _encode_information_access,
|
||||
ExtensionOID.CRL_DISTRIBUTION_POINTS: _encode_cdps_freshest_crl,
|
||||
ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl,
|
||||
ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy,
|
||||
|
|
@ -636,9 +635,7 @@ _EXTENSION_ENCODE_HANDLERS = {
|
|||
_CRL_EXTENSION_ENCODE_HANDLERS = {
|
||||
ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
|
||||
ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
|
||||
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
|
||||
_encode_authority_information_access
|
||||
),
|
||||
ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access,
|
||||
ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator,
|
||||
ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator,
|
||||
ExtensionOID.ISSUING_DISTRIBUTION_POINT: _encode_issuing_dist_point,
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ from cryptography.x509.extensions import (
|
|||
IssuingDistributionPoint, KeyUsage, NameConstraints, NoticeReference,
|
||||
OCSPNoCheck, OCSPNonce, PolicyConstraints, PolicyInformation,
|
||||
PrecertPoison, PrecertificateSignedCertificateTimestamps, ReasonFlags,
|
||||
SubjectAlternativeName, SubjectKeyIdentifier, TLSFeature, TLSFeatureType,
|
||||
UnrecognizedExtension, UserNotice
|
||||
SubjectAlternativeName, SubjectInformationAccess, SubjectKeyIdentifier,
|
||||
TLSFeature, TLSFeatureType, UnrecognizedExtension, UserNotice
|
||||
)
|
||||
from cryptography.x509.general_name import (
|
||||
DNSName, DirectoryName, GeneralName, IPAddress, OtherName, RFC822Name,
|
||||
|
|
@ -142,6 +142,7 @@ __all__ = [
|
|||
"CRLNumber",
|
||||
"KeyUsage",
|
||||
"AuthorityInformationAccess",
|
||||
"SubjectInformationAccess",
|
||||
"AccessDescription",
|
||||
"CertificatePolicies",
|
||||
"PolicyInformation",
|
||||
|
|
|
|||
|
|
@ -317,6 +317,38 @@ class AuthorityInformationAccess(object):
|
|||
return hash(tuple(self._descriptions))
|
||||
|
||||
|
||||
@utils.register_interface(ExtensionType)
|
||||
class SubjectInformationAccess(object):
|
||||
oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS
|
||||
|
||||
def __init__(self, descriptions):
|
||||
descriptions = list(descriptions)
|
||||
if not all(isinstance(x, AccessDescription) for x in descriptions):
|
||||
raise TypeError(
|
||||
"Every item in the descriptions list must be an "
|
||||
"AccessDescription"
|
||||
)
|
||||
|
||||
self._descriptions = descriptions
|
||||
|
||||
__len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
|
||||
|
||||
def __repr__(self):
|
||||
return "<SubjectInformationAccess({})>".format(self._descriptions)
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, SubjectInformationAccess):
|
||||
return NotImplemented
|
||||
|
||||
return self._descriptions == other._descriptions
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
||||
def __hash__(self):
|
||||
return hash(tuple(self._descriptions))
|
||||
|
||||
|
||||
class AccessDescription(object):
|
||||
def __init__(self, access_method, access_location):
|
||||
if not isinstance(access_method, ObjectIdentifier):
|
||||
|
|
|
|||
|
|
@ -149,6 +149,10 @@ class AuthorityInformationAccessOID(object):
|
|||
OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1")
|
||||
|
||||
|
||||
class SubjectInformationAccessOID(object):
|
||||
CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5")
|
||||
|
||||
|
||||
class CertificatePoliciesOID(object):
|
||||
CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1")
|
||||
CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2")
|
||||
|
|
@ -251,6 +255,7 @@ _OID_NAMES = {
|
|||
ExtensionOID.TLS_FEATURE: "TLSFeature",
|
||||
AuthorityInformationAccessOID.OCSP: "OCSP",
|
||||
AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers",
|
||||
SubjectInformationAccessOID.CA_REPOSITORY: "caRepository",
|
||||
CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps",
|
||||
CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice",
|
||||
OCSPExtensionOID.NONCE: "OCSPNonce",
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ from cryptography.hazmat.primitives.asymmetric.utils import (
|
|||
from cryptography.x509.name import _ASN1Type
|
||||
from cryptography.x509.oid import (
|
||||
AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID,
|
||||
NameOID, SignatureAlgorithmOID
|
||||
NameOID, SignatureAlgorithmOID, SubjectInformationAccessOID,
|
||||
)
|
||||
|
||||
from ..hazmat.primitives.fixtures_dsa import DSA_KEY_2048
|
||||
|
|
@ -1718,6 +1718,40 @@ class TestCertificateBuilder(object):
|
|||
|
||||
builder.sign(private_key, hashes.SHA256(), backend)
|
||||
|
||||
@pytest.mark.requires_backend_interface(interface=RSABackend)
|
||||
@pytest.mark.requires_backend_interface(interface=X509Backend)
|
||||
def test_encode_nonstandard_sia(self, backend):
|
||||
private_key = RSA_KEY_2048.private_key(backend)
|
||||
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
x509.ObjectIdentifier("2.999.7"),
|
||||
x509.UniformResourceIdentifier(u"http://example.com")
|
||||
),
|
||||
])
|
||||
|
||||
builder = x509.CertificateBuilder().subject_name(x509.Name([
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'),
|
||||
])).issuer_name(x509.Name([
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'),
|
||||
])).public_key(
|
||||
private_key.public_key()
|
||||
).serial_number(
|
||||
777
|
||||
).not_valid_before(
|
||||
datetime.datetime(2015, 1, 1)
|
||||
).not_valid_after(
|
||||
datetime.datetime(2040, 1, 1)
|
||||
).add_extension(
|
||||
sia, False
|
||||
)
|
||||
|
||||
cert = builder.sign(private_key, hashes.SHA256(), backend)
|
||||
ext = cert.extensions.get_extension_for_oid(
|
||||
ExtensionOID.SUBJECT_INFORMATION_ACCESS
|
||||
)
|
||||
assert ext.value == sia
|
||||
|
||||
@pytest.mark.requires_backend_interface(interface=RSABackend)
|
||||
@pytest.mark.requires_backend_interface(interface=X509Backend)
|
||||
def test_subject_dn_asn1_types(self, backend):
|
||||
|
|
@ -3708,6 +3742,45 @@ class TestCertificateSigningRequestBuilder(object):
|
|||
)
|
||||
assert ext.value == aia
|
||||
|
||||
@pytest.mark.requires_backend_interface(interface=RSABackend)
|
||||
@pytest.mark.requires_backend_interface(interface=X509Backend)
|
||||
def test_build_cert_with_sia(self, backend):
|
||||
issuer_private_key = RSA_KEY_2048.private_key(backend)
|
||||
subject_private_key = RSA_KEY_2048.private_key(backend)
|
||||
|
||||
not_valid_before = datetime.datetime(2002, 1, 1, 12, 1)
|
||||
not_valid_after = datetime.datetime(2030, 12, 31, 8, 30)
|
||||
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
])
|
||||
|
||||
builder = x509.CertificateBuilder().serial_number(
|
||||
777
|
||||
).issuer_name(x509.Name([
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'),
|
||||
])).subject_name(x509.Name([
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, u'US'),
|
||||
])).public_key(
|
||||
subject_private_key.public_key()
|
||||
).add_extension(
|
||||
sia, critical=False
|
||||
).not_valid_before(
|
||||
not_valid_before
|
||||
).not_valid_after(
|
||||
not_valid_after
|
||||
)
|
||||
|
||||
cert = builder.sign(issuer_private_key, hashes.SHA256(), backend)
|
||||
|
||||
ext = cert.extensions.get_extension_for_oid(
|
||||
ExtensionOID.SUBJECT_INFORMATION_ACCESS
|
||||
)
|
||||
assert ext.value == sia
|
||||
|
||||
@pytest.mark.requires_backend_interface(interface=RSABackend)
|
||||
@pytest.mark.requires_backend_interface(interface=X509Backend)
|
||||
def test_build_cert_with_ski(self, backend):
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ from cryptography.x509.extensions import _key_identifier_from_public_key
|
|||
from cryptography.x509.general_name import _lazy_import_idna
|
||||
from cryptography.x509.oid import (
|
||||
AuthorityInformationAccessOID, ExtendedKeyUsageOID, ExtensionOID,
|
||||
NameOID, ObjectIdentifier, _OID_NAMES
|
||||
NameOID, ObjectIdentifier, SubjectInformationAccessOID, _OID_NAMES
|
||||
)
|
||||
|
||||
from .test_x509 import _load_cert
|
||||
|
|
@ -3052,6 +3052,198 @@ class TestAuthorityInformationAccess(object):
|
|||
assert hash(aia) != hash(aia3)
|
||||
|
||||
|
||||
class TestSubjectInformationAccess(object):
|
||||
def test_invalid_descriptions(self):
|
||||
with pytest.raises(TypeError):
|
||||
x509.SubjectInformationAccess(["notanAccessDescription"])
|
||||
|
||||
def test_iter_len(self):
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
)
|
||||
])
|
||||
assert len(sia) == 2
|
||||
assert list(sia) == [
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
)
|
||||
]
|
||||
|
||||
def test_iter_input(self):
|
||||
desc = [
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
)
|
||||
]
|
||||
sia = x509.SubjectInformationAccess(iter(desc))
|
||||
assert list(sia) == desc
|
||||
|
||||
def test_repr(self):
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
)
|
||||
])
|
||||
if not six.PY2:
|
||||
assert repr(sia) == (
|
||||
"<SubjectInformationAccess([<AccessDescription(access_method"
|
||||
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.5, name=caRepositor"
|
||||
"y)>, access_location=<UniformResourceIdentifier(value='http"
|
||||
"://ca.domain.com')>)>])>"
|
||||
)
|
||||
else:
|
||||
assert repr(sia) == (
|
||||
"<SubjectInformationAccess([<AccessDescription(access_method"
|
||||
"=<ObjectIdentifier(oid=1.3.6.1.5.5.7.48.5, name=caRepositor"
|
||||
"y)>, access_location=<UniformResourceIdentifier(value=u'htt"
|
||||
"p://ca.domain.com')>)>])>"
|
||||
)
|
||||
|
||||
def test_eq(self):
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
)
|
||||
])
|
||||
sia2 = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
)
|
||||
])
|
||||
assert sia == sia2
|
||||
|
||||
def test_ne(self):
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
)
|
||||
])
|
||||
sia2 = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
])
|
||||
|
||||
assert sia != sia2
|
||||
assert sia != object()
|
||||
|
||||
def test_indexing(self):
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca3.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca4.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca5.domain.com")
|
||||
),
|
||||
])
|
||||
assert sia[-1] == sia[4]
|
||||
assert sia[2:6:2] == [sia[2], sia[4]]
|
||||
|
||||
def test_hash(self):
|
||||
sia = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
),
|
||||
])
|
||||
sia2 = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca2.domain.com")
|
||||
),
|
||||
])
|
||||
sia3 = x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca.domain.com")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"http://ca3.domain.com")
|
||||
),
|
||||
])
|
||||
assert hash(sia) == hash(sia2)
|
||||
assert hash(sia) != hash(sia3)
|
||||
|
||||
|
||||
@pytest.mark.requires_backend_interface(interface=RSABackend)
|
||||
@pytest.mark.requires_backend_interface(interface=X509Backend)
|
||||
class TestSubjectInformationAccessExtension(object):
|
||||
def test_sia(self, backend):
|
||||
cert = _load_cert(
|
||||
os.path.join("x509", "custom", "sia.pem"),
|
||||
x509.load_pem_x509_certificate,
|
||||
backend
|
||||
)
|
||||
ext = cert.extensions.get_extension_for_oid(
|
||||
ExtensionOID.SUBJECT_INFORMATION_ACCESS
|
||||
)
|
||||
assert ext is not None
|
||||
assert ext.critical is False
|
||||
|
||||
assert ext.value == x509.SubjectInformationAccess([
|
||||
x509.AccessDescription(
|
||||
SubjectInformationAccessOID.CA_REPOSITORY,
|
||||
x509.UniformResourceIdentifier(u"https://my.ca.issuer/")
|
||||
),
|
||||
x509.AccessDescription(
|
||||
x509.ObjectIdentifier("2.999.7"),
|
||||
x509.UniformResourceIdentifier(u"gopher://info-mac-archive")
|
||||
),
|
||||
])
|
||||
|
||||
|
||||
@pytest.mark.requires_backend_interface(interface=RSABackend)
|
||||
@pytest.mark.requires_backend_interface(interface=X509Backend)
|
||||
class TestAuthorityInformationAccessExtension(object):
|
||||
|
|
|
|||
18
vectors/cryptography_vectors/x509/custom/sia.pem
Normal file
18
vectors/cryptography_vectors/x509/custom/sia.pem
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIC7TCCAdWgAwIBAgICAwkwDQYJKoZIhvcNAQELBQAwDTELMAkGA1UEBhMCVVMw
|
||||
HhcNMTUwMTAxMDAwMDAwWhcNNDAwMTAxMDAwMDAwWjANMQswCQYDVQQGEwJVUzCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMF6/H53R0yqWqgwNhWKP/v3
|
||||
tSFoUboiMOXWq/zBxs/vWekj6hMwvFk7c4Aqtgim5KMwZSOjEWulqjlmFFF04Tts
|
||||
Sem3gGLkSdcu+xD9SekfoIuW0FHngun1q8W1pveYSCetuOc9oA8isu/c23bqtG7a
|
||||
2Y7WVmJ0P9xsDjNqXQzbqn3CnlNjXiTIelssQhWWgGPN62ipcrq7wePP8A+5qA43
|
||||
Kk0MLJINHozuMzzkcNwugUWtsFvymu4dJPFB6Mx4SYnFh/xvus2Xnz8hY8HXKZs2
|
||||
W8cv/ihI6Weu0eSNzFFbOlDtTeBP0FOEbKEKIjsQzIQcyA/evuRPMRTBPohq9YMC
|
||||
AwEAAaNXMFUwUwYIKwYBBQUHAQsERzBFMCEGCCsGAQUFBzAFhhVodHRwczovL215
|
||||
LmNhLmlzc3Vlci8wIAYDiDcHhhlnb3BoZXI6Ly9pbmZvLW1hYy1hcmNoaXZlMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQB4AdYx02aXDJURPbZNi3j7FnK3LRVvJcq8vRHaG9b4
|
||||
soD/7qA8RJX11WTFNDY7g5OQhYT+WBc8OUinJaqJOPvEzgp5Prgq5AlAtcImvNX7
|
||||
dI3lr9esZ5gBWbsMK9saNEERhEZDUCSYW/GRMN4yxdUgTDPsfNr8N6bwfnGRR0xM
|
||||
EBr+p+fT1xth4uren7J/edYrY9a171y6bMdZQ1iVnFH2dFO25D+3k9sM6FRWWsWu
|
||||
mmrcg79QAl6jqC/6SkqVzpBPzi7dgGYluaKJjREC8e/cMcpphW1TP+8rZ161BmDk
|
||||
hk5/PrWguFuguWUyEkPH5oqFqoZuqeM0fULxHh2JiqOx
|
||||
-----END CERTIFICATE-----
|
||||
Loading…
Reference in a new issue