mirror of
https://github.com/saltstack/salt.git
synced 2025-04-16 09:40:20 +00:00
1890 lines
68 KiB
Python
1890 lines
68 KiB
Python
import datetime
|
|
import ipaddress
|
|
|
|
import pytest
|
|
|
|
import salt.exceptions
|
|
import salt.utils.x509 as x509
|
|
from tests.support.mock import ANY, Mock, patch
|
|
|
|
cryptography = pytest.importorskip(
|
|
"cryptography", reason="Needs cryptography library", minversion="37.0"
|
|
)
|
|
cx509 = pytest.importorskip("cryptography.x509", reason="Needs cryptography library")
|
|
|
|
|
|
@pytest.fixture
|
|
def single_pem():
|
|
return """\
|
|
-----BEGIN RSA PRIVATE KEY-----
|
|
MIIEogIBAAKCAQEAu4FN2FAbh06p0SalHsN0uyvEK/pmxoJqgnPll+NIyUtyEKms
|
|
GXuRzZ6hF++a74dkk6/YbmyGAHECuS1WPm1iqaO7KASFEB3daeLg9r3jlFP4cxZI
|
|
n3UnEZF+GDYHdox00JyW0CLp6VUouXxc1gogkVGmeyi52b4LsOlGXdO8/8Nbcjhu
|
|
V9GZvdvvp6CwTLZabPni6nL/WWl5EwRqYnVTcX323tsObRliGsP6FYy1lQQLiy0A
|
|
PNIU+sxdQFeIdsR5FZ2JyquyKGD4REGrNGp2VuxzPrOmzr46AKTHRdDUaCedzUDO
|
|
wwK/sE4+b2DKEvyhYI1O5K5rERAFG4voZGwVTQIDAQABAoIBAGdu1LpWtljVk+fE
|
|
IaHuwB3f7r8zyi4HEyoTNLusrSIddDas4jrMZ4m9z6+chSNM1LaDcii3xNPJg28T
|
|
C1g0jxB1OXDBzYUudE1M0jxKU5gnGg6iZD1SKtMOJzjD1SoYIPhS6P63w8DrMSPg
|
|
7nVD8OM431VhCeSLaXeVtzNa8g9DirSHQD8zHHb3H7jnPJ4SeFKYv8URl3lsN84A
|
|
frP64nO64OGYgmIPU5IgVpKmK0rjXll4zNRxx5UwO2BglJ2lR6EIZ6oBA8ooCrPd
|
|
qOKrfiVTHoV9sKVwUtBvP3mqC1WZ6CWmX9EdnrSG0jgUZezezonHfcg8eBtoOPpR
|
|
0shrbwECgYEA6Ey8OGK3N3LNYewMuvv9gl66+TSbQY8Dh5iASHppvYFh6rWpdqo6
|
|
tRJORHbPn01fb2p48Pne8XBqDZNkG5u0gfX+v0yq2W5U0ezd0plP/uirLTuUm5if
|
|
hP525ShnHW6DYGsc26brCwRDINx4jYDqEiCq+1DcgoTavWBsUq+59aUCgYEAzqKc
|
|
TB5R/O6iwjCuJeIXddiIxHNFCwoaXSdorkCw2A7VJWUeh8SOpYuE//rfxW7pJbIS
|
|
kDc7rbdr/oyE7EYA6nIonWHJdXQ6V23SHARFWDX+LEn10OWOpSQnigSlcd1zFXLO
|
|
UDBVronmstqFriTugZfDAJZo7x6zsPfU/2X3IIkCgYBPaYweqoB/0BsuEof3lBWB
|
|
7+hzMOyyaLWIMTYJkO98/TIADsIz8tXG+M8Q0J0BlG2/pOJbXtA8MXXP1kcuuPfo
|
|
RbQkqYzub61HZnYefJLATcHW4LtYxcAisurqQ/mcMh9vYq6m2FUZmwdnwHblyOA7
|
|
+jb5WxdG9yvf+YqOacxkkQKBgE6AlKSOeFOBTbA80kxuIr+QrhUEPdy9z9pIGIrq
|
|
5MSQjgWQ7xJhaFgYM0UUyGK3ijfZ+Rd1BGUw5ARm2jDxP3PSPv/boK/QokGI5WPj
|
|
c3zZtmCZEJx2OcUfgS38KeaiXRBu91abplGS7mRQhKzuNvZg86KLgf4mSdoXrYIB
|
|
+OsRAoGANP4NjqBAEzsIFszGvaXmslyzfdWY6XI5N1GgzbEW/K7UECiPxWxmWcCm
|
|
n7mpiv/r8zkskgfAua84Fe8qIr2f6UjNeIzJ7LwI0zSB2uuiS4oP3xqCEyb+J3F4
|
|
bQdPnxzSwrf6edD2AmIT9L8IwiCYiplC+JvqSlqDP2pxIQbilmw=
|
|
-----END RSA PRIVATE KEY-----
|
|
"""
|
|
|
|
|
|
@pytest.fixture
|
|
def multi_pem():
|
|
return """\
|
|
-----BEGIN CERTIFICATE-----
|
|
MIIDKDCCAhCgAwIBAgIIEmd4S33OHDEwDQYJKoZIhvcNAQELBQAwKzELMAkGA1UE
|
|
BhMCVVMxDTALBgNVBAMMBFRlc3QxDTALBgNVBAoMBFNhbHQwHhcNMjIxMTE1MTQw
|
|
OTQ0WhcNMzIxMTEyMTQwOTQ0WjAuMQswCQYDVQQGEwJVUzEQMA4GA1UEAwwHVGVz
|
|
dENydDENMAsGA1UECgwEU2FsdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
|
ggEBAOGTScvrjcEt6vsJcG9RUp6fKaDNDWZnJET0omanK9ZwaoGpJPp8UDYe/8AD
|
|
eI7N10wdyB4oDM9gRDjInBtdQO/PsrmKZF6LzqVFgLMxu2up+PHMi9z6B2P4esIA
|
|
zMu9PYxc9zH4HzLImHqscVD2HCabsjp9X134Af7hVY5NN/W/4qTP7uOM20wSG2TP
|
|
I6+BtA9VyPbEPMPRzXzrqc45rVYe6kb2bT84GE93Vcu/e5JZ/k2AKD8Hoa2cxLPs
|
|
TLq5igl+D+k+dfUtiABiKPvVQiYBsD1fyHDn2m7B6pCgvrGqHjsoAKufgFnXy6PJ
|
|
Rg7nvQfaxSiusM5s+VS+fjlvgwsCAwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4E
|
|
FgQUXPLx9FMpI57uQFqSo7QqLvWmi2cwHwYDVR0jBBgwFoAUXPLx9FMpI57uQFqS
|
|
o7QqLvWmi2cwDQYJKoZIhvcNAQELBQADggEBAFkYke/32PEmCDcs8YFDp5PDVwhv
|
|
8ZlfCtgRChaPcwoc+QpBeNhUEMhQ/v77Ojj6VNXzNDP7X1MCc7432Xo3VHCiCI8c
|
|
CMVNiyDWJNlEEll3eUIguNWRnkIfsCeHVs5/76M9tgwcrPOltQliI4UJ7Wy5pnXA
|
|
ywQFn43TqzNdU7HRIdX7QRUHeMOpe7Y4o7vjSOseQJcL2pQadho/BqK5rWuwZ8x/
|
|
Jsl40YjjXyLOnOCUYYpC13KC8iHOZKHVvA8eDtiuuLSgIk9DBD/ClU4cMCF2mvuQ
|
|
dtV9rM6byvPUJaIxKznODAUbZPGuFI/FWP9VheO17s7mDs/B12/UKXcTkvs=
|
|
-----END CERTIFICATE-----
|
|
|
|
-----BEGIN CERTIFICATE-----
|
|
MIIDODCCAiCgAwIBAgIIbfpgqP0VGPgwDQYJKoZIhvcNAQELBQAwKzELMAkGA1UE
|
|
BhMCVVMxDTALBgNVBAMMBFRlc3QxDTALBgNVBAoMBFNhbHQwHhcNMjIxMTE1MTQw
|
|
NDMzWhcNMzIxMTEyMTQwNDMzWjArMQswCQYDVQQGEwJVUzENMAsGA1UEAwwEVGVz
|
|
dDENMAsGA1UECgwEU2FsdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
|
AOGTScvrjcEt6vsJcG9RUp6fKaDNDWZnJET0omanK9ZwaoGpJPp8UDYe/8ADeI7N
|
|
10wdyB4oDM9gRDjInBtdQO/PsrmKZF6LzqVFgLMxu2up+PHMi9z6B2P4esIAzMu9
|
|
PYxc9zH4HzLImHqscVD2HCabsjp9X134Af7hVY5NN/W/4qTP7uOM20wSG2TPI6+B
|
|
tA9VyPbEPMPRzXzrqc45rVYe6kb2bT84GE93Vcu/e5JZ/k2AKD8Hoa2cxLPsTLq5
|
|
igl+D+k+dfUtiABiKPvVQiYBsD1fyHDn2m7B6pCgvrGqHjsoAKufgFnXy6PJRg7n
|
|
vQfaxSiusM5s+VS+fjlvgwsCAwEAAaNgMF4wDwYDVR0TBAgwBgEB/wIBATALBgNV
|
|
HQ8EBAMCAQYwHQYDVR0OBBYEFFzy8fRTKSOe7kBakqO0Ki71potnMB8GA1UdIwQY
|
|
MBaAFFzy8fRTKSOe7kBakqO0Ki71potnMA0GCSqGSIb3DQEBCwUAA4IBAQBZS4MP
|
|
fXYPoGZ66seM+0eikScZHirbRe8vHxHkujnTBUjQITKm86WeQgeBCD2pobgBGZtt
|
|
5YFozM4cERqY7/1BdemUxFvPmMFFznt0TM5w+DfGWVK8un6SYwHnmBbnkWgX4Srm
|
|
GsL0HHWxVXkGnFGFk6Sbo3vnN7CpkpQTWFqeQQ5rHOw91pt7KnNZwc6I3ZjrCUHJ
|
|
+UmKKrga16a4Q+8FBpYdphQU609npo/0zuaE6FyiJYlW3tG+mlbbNgzY/+eUaxt2
|
|
9Bp9mtA+Hkox551Mfpq45Oi+ehwMt0xjZCjuFCM78oiUdHCGO+EmcT7ogiYALiOF
|
|
LN1w5sybsYwIw6QN
|
|
-----END CERTIFICATE-----
|
|
"""
|
|
|
|
|
|
def test_split_pems_single(single_pem):
|
|
res = x509.split_pems(single_pem)
|
|
assert len(res) == 1
|
|
assert res[0].startswith(b"-----BEGIN RSA PRIVATE KEY-----\n")
|
|
assert res[0].endswith(b"-----END RSA PRIVATE KEY-----\n")
|
|
assert len(res[0].splitlines()) == 27
|
|
|
|
|
|
def test_split_pems_multi(multi_pem):
|
|
res = x509.split_pems(multi_pem)
|
|
assert len(res) == 2
|
|
for x in res:
|
|
assert x.startswith(b"-----BEGIN CERTIFICATE-----\n")
|
|
assert x.endswith(b"-----END CERTIFICATE-----\n")
|
|
assert len(res[0].splitlines()) == 19
|
|
assert len(res[1].splitlines()) == 20
|
|
|
|
|
|
def test_split_pems_garbage_between(single_pem):
|
|
garbage_pem = (
|
|
single_pem
|
|
+ "\nI like turtles\nIntroduce a little anarchy. Upset the established order, and everything becomes chaos. I'm an agent of chaos.\n"
|
|
+ single_pem
|
|
)
|
|
res = x509.split_pems(garbage_pem)
|
|
assert len(res) == 2
|
|
for x in res:
|
|
assert x.startswith(b"-----BEGIN RSA PRIVATE KEY-----\n")
|
|
assert x.endswith(b"-----END RSA PRIVATE KEY-----\n")
|
|
assert len(x.splitlines()) == 27
|
|
|
|
|
|
class TestCreateExtension:
|
|
@pytest.fixture
|
|
def aki(self):
|
|
with patch("cryptography.x509.AuthorityKeyIdentifier", autospec=True) as ext:
|
|
yield ext
|
|
|
|
@pytest.fixture
|
|
def ca_crt(self):
|
|
ca = Mock(spec=cx509.Certificate)
|
|
return ca
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
("critical,CA:FALSE", (False, None), True),
|
|
("critical, CA:TRUE, pathlen:2", (True, 2), True),
|
|
("CA:TRUE", (True, None), False),
|
|
({"ca": False, "critical": True}, (False, None), True),
|
|
({"ca": True, "pathlen": 3}, (True, 3), False),
|
|
],
|
|
)
|
|
def test_create_basic_constraints(self, val, expected, critical):
|
|
with patch("cryptography.x509.BasicConstraints", autospec=True) as ext:
|
|
_, crit = x509._create_extension("basicConstraints", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(*expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign, encipherOnly, decipherOnly",
|
|
{
|
|
"digital_signature": True,
|
|
"content_commitment": True,
|
|
"key_encipherment": True,
|
|
"data_encipherment": True,
|
|
"key_agreement": True,
|
|
"key_cert_sign": True,
|
|
"crl_sign": True,
|
|
"encipher_only": True,
|
|
"decipher_only": True,
|
|
},
|
|
False,
|
|
),
|
|
(
|
|
"critical, keyCertSign, cRLSign",
|
|
{
|
|
"digital_signature": False,
|
|
"content_commitment": False,
|
|
"key_encipherment": False,
|
|
"data_encipherment": False,
|
|
"key_agreement": False,
|
|
"key_cert_sign": True,
|
|
"crl_sign": True,
|
|
"encipher_only": False,
|
|
"decipher_only": False,
|
|
},
|
|
True,
|
|
),
|
|
(
|
|
["critical", "digitalSignature"],
|
|
{
|
|
"digital_signature": True,
|
|
"content_commitment": False,
|
|
"key_encipherment": False,
|
|
"data_encipherment": False,
|
|
"key_agreement": False,
|
|
"key_cert_sign": False,
|
|
"crl_sign": False,
|
|
"encipher_only": False,
|
|
"decipher_only": False,
|
|
},
|
|
True,
|
|
),
|
|
(
|
|
["nonRepudiation"],
|
|
{
|
|
"digital_signature": False,
|
|
"content_commitment": True,
|
|
"key_encipherment": False,
|
|
"data_encipherment": False,
|
|
"key_agreement": False,
|
|
"key_cert_sign": False,
|
|
"crl_sign": False,
|
|
"encipher_only": False,
|
|
"decipher_only": False,
|
|
},
|
|
False,
|
|
),
|
|
],
|
|
)
|
|
def test_create_key_usage(self, val, expected, critical):
|
|
with patch("cryptography.x509.KeyUsage", autospec=True) as ext:
|
|
_, crit = x509._create_extension("keyUsage", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(**expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"critical,serverAuth,clientAuth,codeSigning,emailProtection,timeStamping,OCSPSigning,msSmartcardLogin,pkInitKDC,ipsecIKE,msCodeInd,msCodeCom,msCTLSign,msEFS",
|
|
list(x509.EXTENDED_KEY_USAGE_OID.values()),
|
|
True,
|
|
),
|
|
("serverAuth", [x509.EXTENDED_KEY_USAGE_OID["serverAuth"]], False),
|
|
(
|
|
"timeStamping,1.2.3.4",
|
|
[
|
|
x509.EXTENDED_KEY_USAGE_OID["timeStamping"],
|
|
cx509.ObjectIdentifier("1.2.3.4"),
|
|
],
|
|
False,
|
|
),
|
|
(
|
|
["critical", "OCSPSigning", "msCodeCom", "2.3.4.55"],
|
|
[
|
|
x509.EXTENDED_KEY_USAGE_OID["OCSPSigning"],
|
|
x509.EXTENDED_KEY_USAGE_OID["msCodeCom"],
|
|
cx509.ObjectIdentifier("2.3.4.55"),
|
|
],
|
|
True,
|
|
),
|
|
(["clientAuth"], [x509.EXTENDED_KEY_USAGE_OID["clientAuth"]], False),
|
|
],
|
|
)
|
|
def test_create_extended_key_usage(self, val, expected, critical):
|
|
with patch("cryptography.x509.ExtendedKeyUsage", autospec=True) as ext:
|
|
_, crit = x509._create_extension("extendedKeyUsage", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected",
|
|
[
|
|
("hash", None),
|
|
(
|
|
"BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4",
|
|
b"\xbb\xaf~\x02=\xfa\xa6\xf1<\x84\x8e\xad\xee8\x98\xec\xd922\xd4",
|
|
),
|
|
(
|
|
"bbaf7e023dfaa6f13c848eadee3898ecd93232d4",
|
|
b"\xbb\xaf~\x02=\xfa\xa6\xf1<\x84\x8e\xad\xee8\x98\xec\xd922\xd4",
|
|
),
|
|
],
|
|
)
|
|
def test_create_subject_key_identifier(self, val, expected):
|
|
with patch("cryptography.x509.SubjectKeyIdentifier", autospec=True) as ext:
|
|
_, crit = x509._create_extension(
|
|
"subjectKeyIdentifier", val, subject_pubkey="testpub"
|
|
)
|
|
assert crit is False
|
|
if val == "hash":
|
|
ext.from_public_key.assert_called_once_with("testpub")
|
|
else:
|
|
ext.from_public_key.assert_not_called()
|
|
ext.assert_called_once_with(expected)
|
|
|
|
def test_create_authority_key_identifier_from_ski(self, aki, ca_crt):
|
|
ca_crt.extensions.get_extension_for_class.return_value.value.digest = (
|
|
b"\xde\xad\xbe\xef"
|
|
)
|
|
_, crit = x509._create_extension(
|
|
"authorityKeyIdentifier", "keyid:always", ca_crt=ca_crt
|
|
)
|
|
assert crit is False
|
|
aki.assert_called_once_with(
|
|
key_identifier=b"\xde\xad\xbe\xef",
|
|
authority_cert_issuer=None,
|
|
authority_cert_serial_number=None,
|
|
)
|
|
|
|
def test_create_authority_key_identifier_from_pubkey(self, aki, ca_crt):
|
|
def raise_notfound(*args, **kwargs):
|
|
raise cx509.ExtensionNotFound("f", cx509.ObjectIdentifier("1.2.3.4"))
|
|
|
|
ca_crt.extensions.get_extension_for_class.side_effect = raise_notfound
|
|
aki.from_issuer_public_key.return_value.key_identifier = b"\xde\xad\xbe\xef"
|
|
_, crit = x509._create_extension(
|
|
"authorityKeyIdentifier", "keyid:always", ca_crt=ca_crt
|
|
)
|
|
assert crit is False
|
|
aki.assert_called_once_with(
|
|
key_identifier=b"\xde\xad\xbe\xef",
|
|
authority_cert_issuer=None,
|
|
authority_cert_serial_number=None,
|
|
)
|
|
|
|
def test_create_authority_key_identifier_from_ca_pub(self, aki):
|
|
aki.from_issuer_public_key.return_value.key_identifier = b"\xde\xad\xbe\xef"
|
|
_, crit = x509._create_extension(
|
|
"authorityKeyIdentifier", "keyid:always", ca_pub="testpub"
|
|
)
|
|
assert crit is False
|
|
aki.assert_called_once_with(
|
|
key_identifier=b"\xde\xad\xbe\xef",
|
|
authority_cert_issuer=None,
|
|
authority_cert_serial_number=None,
|
|
)
|
|
|
|
@pytest.mark.parametrize(
|
|
"ca_crt,ca_pub",
|
|
[
|
|
(Mock(), None),
|
|
(None, Mock()),
|
|
(Mock(), Mock()),
|
|
],
|
|
)
|
|
def test_create_authority_key_identifier_always(self, aki, ca_crt, ca_pub):
|
|
aki.from_issuer_public_key.side_effect = RuntimeError
|
|
if ca_crt is not None:
|
|
ca_crt.extensions.get_extension_for_class.side_effect = RuntimeError
|
|
elif ca_pub is not None:
|
|
ca_pub.side_effect = RuntimeError
|
|
with pytest.raises(salt.exceptions.CommandExecutionError):
|
|
x509._create_extension(
|
|
"authorityKeyIdentifier", "keyid:always", ca_crt=ca_crt, ca_pub=ca_pub
|
|
)
|
|
|
|
def test_create_authority_key_identifier_issuer(self, aki, ca_crt):
|
|
ca_crt.issuer = "testissuer"
|
|
ca_crt.serial_number = 1337
|
|
with patch("cryptography.x509.DirectoryName") as dirname:
|
|
_, crit = x509._create_extension(
|
|
"authorityKeyIdentifier", "issuer", ca_crt=ca_crt
|
|
)
|
|
assert crit is False
|
|
dirname.assert_called_once_with(ca_crt.issuer)
|
|
aki.assert_called_once_with(
|
|
key_identifier=None,
|
|
authority_cert_issuer=ANY,
|
|
authority_cert_serial_number=1337,
|
|
)
|
|
|
|
def test_create_authority_key_identifier_issuer_always(self, aki, ca_crt):
|
|
with patch("cryptography.x509.DirectoryName") as dirname:
|
|
dirname.side_effect = ValueError
|
|
with pytest.raises(salt.exceptions.CommandExecutionError):
|
|
x509._create_extension(
|
|
"authorityKeyIdentifier", "issuer:always", ca_crt=ca_crt
|
|
)
|
|
|
|
def test_create_authority_key_identifier_from_both(self, aki, ca_crt):
|
|
ca_crt.issuer = "testissuer"
|
|
ca_crt.serial_number = 1337
|
|
ca_crt.extensions.get_extension_for_class.return_value.value.digest = (
|
|
b"\xde\xad\xbe\xef"
|
|
)
|
|
with patch("cryptography.x509.DirectoryName"):
|
|
_, crit = x509._create_extension(
|
|
"authorityKeyIdentifier", "keyid:always,issuer:always", ca_crt=ca_crt
|
|
)
|
|
assert crit is False
|
|
aki.assert_called_once_with(
|
|
key_identifier=b"\xde\xad\xbe\xef",
|
|
authority_cert_issuer=ANY,
|
|
authority_cert_serial_number=1337,
|
|
)
|
|
|
|
def test_create_authority_key_identifier_from_both_issuer_fail(self, aki, ca_crt):
|
|
ca_crt.issuer = "testissuer"
|
|
ca_crt.serial_number = 1337
|
|
ca_crt.extensions.get_extension_for_class.return_value.value.digest = (
|
|
b"\xde\xad\xbe\xef"
|
|
)
|
|
with patch("cryptography.x509.DirectoryName") as dirname:
|
|
dirname.side_effect = ValueError
|
|
_, crit = x509._create_extension(
|
|
"authorityKeyIdentifier", "keyid:always,issuer", ca_crt=ca_crt
|
|
)
|
|
assert crit is False
|
|
aki.assert_called_once_with(
|
|
key_identifier=b"\xde\xad\xbe\xef",
|
|
authority_cert_issuer=None,
|
|
authority_cert_serial_number=None,
|
|
)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,ca_sub,expected,critical",
|
|
[
|
|
(
|
|
["email:ca@example.com", "dns:example.com"],
|
|
None,
|
|
[
|
|
cx509.RFC822Name("ca@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
],
|
|
False,
|
|
),
|
|
(
|
|
["issuer:copy"],
|
|
[
|
|
cx509.RFC822Name("me@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
],
|
|
[
|
|
cx509.RFC822Name("me@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
],
|
|
False,
|
|
),
|
|
(
|
|
["critical", "issuer:copy", "dns:example.io"],
|
|
[
|
|
cx509.RFC822Name("ca@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
],
|
|
[
|
|
cx509.RFC822Name("ca@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
cx509.DNSName("example.io"),
|
|
],
|
|
True,
|
|
),
|
|
(
|
|
"critical,issuer:copy,dns:example.io",
|
|
[
|
|
cx509.RFC822Name("ca@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
],
|
|
[
|
|
cx509.RFC822Name("ca@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
cx509.DNSName("example.io"),
|
|
],
|
|
True,
|
|
),
|
|
(
|
|
"DNS:salt.ca",
|
|
None,
|
|
[
|
|
cx509.DNSName("salt.ca"),
|
|
],
|
|
False,
|
|
),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"tgt,extname",
|
|
[
|
|
("IssuerAlternativeName", "issuerAltName"),
|
|
("CertificateIssuer", "certificateIssuer"),
|
|
],
|
|
)
|
|
def test_create_issuer_alt_name(
|
|
self, val, ca_sub, expected, critical, ca_crt, tgt, extname
|
|
):
|
|
ca_crt.extensions.get_extension_for_class.return_value._general_names._general_names = (
|
|
ca_sub
|
|
)
|
|
with patch(f"cryptography.x509.{tgt}", autospec=True) as ext:
|
|
res, crit = x509._create_extension(extname, val, ca_crt=ca_crt)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected",
|
|
[
|
|
(
|
|
"OCSP;URI:http://ocsp.example.com/,caIssuers;URI:http://myca.example.com/ca.cer",
|
|
[
|
|
cx509.AccessDescription(
|
|
access_method=x509.ACCESS_OID["OCSP"],
|
|
access_location=cx509.UniformResourceIdentifier(
|
|
"http://ocsp.example.com/"
|
|
),
|
|
),
|
|
cx509.AccessDescription(
|
|
access_method=x509.ACCESS_OID["caIssuers"],
|
|
access_location=cx509.UniformResourceIdentifier(
|
|
"http://myca.example.com/ca.cer"
|
|
),
|
|
),
|
|
],
|
|
),
|
|
(
|
|
{
|
|
"OCSP": "URI:http://ocsp.example.com/",
|
|
},
|
|
[
|
|
cx509.AccessDescription(
|
|
access_method=x509.ACCESS_OID["OCSP"],
|
|
access_location=cx509.UniformResourceIdentifier(
|
|
"http://ocsp.example.com/"
|
|
),
|
|
),
|
|
],
|
|
),
|
|
(
|
|
[
|
|
{"OCSP": "URI:http://ocsp.example.com/"},
|
|
{"OCSP": "URI:http://ocsp2.example.com/"},
|
|
],
|
|
[
|
|
cx509.AccessDescription(
|
|
access_method=x509.ACCESS_OID["OCSP"],
|
|
access_location=cx509.UniformResourceIdentifier(
|
|
"http://ocsp.example.com/"
|
|
),
|
|
),
|
|
cx509.AccessDescription(
|
|
access_method=x509.ACCESS_OID["OCSP"],
|
|
access_location=cx509.UniformResourceIdentifier(
|
|
"http://ocsp2.example.com/"
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
def test_create_authority_info_access(self, val, expected):
|
|
with patch(
|
|
"cryptography.x509.AuthorityInformationAccess", autospec=True
|
|
) as ext:
|
|
res, crit = x509._create_extension("authorityInfoAccess", val)
|
|
assert crit is False
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
["email:user@example.com", "dns:example.com"],
|
|
[
|
|
cx509.RFC822Name("user@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
],
|
|
False,
|
|
),
|
|
(
|
|
["critical", "dns:example.io"],
|
|
[cx509.DNSName("example.io")],
|
|
True,
|
|
),
|
|
(
|
|
"critical,dns:example.io,email:hello@example.io",
|
|
[
|
|
cx509.DNSName("example.io"),
|
|
cx509.RFC822Name("hello@example.io"),
|
|
],
|
|
True,
|
|
),
|
|
],
|
|
)
|
|
def test_create_subject_alt_name(self, val, expected, critical):
|
|
with patch("cryptography.x509.SubjectAlternativeName", autospec=True) as ext:
|
|
res, crit = x509._create_extension("subjectAltName", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"URI:http://example.com/myca.crl, URI:http://example.org/my.crl",
|
|
[
|
|
cx509.DistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier(
|
|
"http://example.com/myca.crl"
|
|
)
|
|
],
|
|
relative_name=None,
|
|
reasons=None,
|
|
crl_issuer=None,
|
|
),
|
|
cx509.DistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier("http://example.org/my.crl")
|
|
],
|
|
relative_name=None,
|
|
reasons=None,
|
|
crl_issuer=None,
|
|
),
|
|
],
|
|
False,
|
|
),
|
|
(
|
|
"critical,URI:http://example.com/myca.crl",
|
|
[
|
|
cx509.DistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier(
|
|
"http://example.com/myca.crl"
|
|
)
|
|
],
|
|
relative_name=None,
|
|
reasons=None,
|
|
crl_issuer=None,
|
|
)
|
|
],
|
|
True,
|
|
),
|
|
(
|
|
[
|
|
{
|
|
"fullname": [
|
|
"URI:http://example.com/myca.crl",
|
|
"URI:http://example.org/my.crl",
|
|
]
|
|
}
|
|
],
|
|
[
|
|
cx509.DistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier(
|
|
"http://example.com/myca.crl"
|
|
),
|
|
cx509.UniformResourceIdentifier(
|
|
"http://example.org/my.crl"
|
|
),
|
|
],
|
|
relative_name=None,
|
|
reasons=None,
|
|
crl_issuer=None,
|
|
)
|
|
],
|
|
False,
|
|
),
|
|
(
|
|
[
|
|
{
|
|
"fullname": "URI:http://example.com/myca.crl",
|
|
"crlissuer": "DNS:example.org",
|
|
"reasons": ["keyCompromise"],
|
|
}
|
|
],
|
|
[
|
|
cx509.DistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier(
|
|
"http://example.com/myca.crl"
|
|
)
|
|
],
|
|
relative_name=None,
|
|
reasons=frozenset([cx509.ReasonFlags("keyCompromise")]),
|
|
crl_issuer=[cx509.DNSName("example.org")],
|
|
)
|
|
],
|
|
False,
|
|
),
|
|
pytest.param(
|
|
[
|
|
"critical",
|
|
{
|
|
"relativename": "OU=foo+CN=Smith",
|
|
"crlissuer": ["DNS:example.org"],
|
|
},
|
|
],
|
|
[
|
|
cx509.DistributionPoint(
|
|
full_name=None,
|
|
relative_name=cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.11"), value="foo"
|
|
),
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.3"), value="Smith"
|
|
),
|
|
]
|
|
),
|
|
reasons=None,
|
|
crl_issuer=[cx509.DNSName("example.org")],
|
|
)
|
|
],
|
|
True,
|
|
),
|
|
],
|
|
)
|
|
@pytest.mark.parametrize(
|
|
"tgt,extname",
|
|
[
|
|
("CRLDistributionPoints", "crlDistributionPoints"),
|
|
("FreshestCRL", "freshestCRL"),
|
|
],
|
|
)
|
|
def test_create_crl_distribution_points_freshest_crl(
|
|
self, val, expected, critical, tgt, extname
|
|
):
|
|
with patch(f"cryptography.x509.{tgt}", autospec=True) as ext:
|
|
res, crit = x509._create_extension(extname, val)
|
|
if tgt == "FreshestCRL":
|
|
assert crit is False
|
|
else:
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
{
|
|
"critical": True,
|
|
"fullname": [
|
|
"URI:http://example.com/myca.crl",
|
|
"URI:http://example.org/my.crl",
|
|
],
|
|
},
|
|
{
|
|
"full_name": [
|
|
cx509.UniformResourceIdentifier("http://example.com/myca.crl"),
|
|
cx509.UniformResourceIdentifier("http://example.org/my.crl"),
|
|
],
|
|
"relative_name": None,
|
|
"only_some_reasons": None,
|
|
"only_contains_user_certs": False,
|
|
"only_contains_ca_certs": False,
|
|
"only_contains_attribute_certs": False,
|
|
"indirect_crl": False,
|
|
},
|
|
True,
|
|
),
|
|
(
|
|
{
|
|
"fullname": "URI:http://example.com/myca.crl",
|
|
"onlysomereasons": ["keyCompromise"],
|
|
"onlyuser": True,
|
|
"onlyCA": False,
|
|
"onlyAA": False,
|
|
"indirectCRL": False,
|
|
},
|
|
{
|
|
"full_name": [
|
|
cx509.UniformResourceIdentifier("http://example.com/myca.crl")
|
|
],
|
|
"relative_name": None,
|
|
"only_some_reasons": frozenset(
|
|
[cx509.ReasonFlags("keyCompromise")]
|
|
),
|
|
"only_contains_user_certs": True,
|
|
"only_contains_ca_certs": False,
|
|
"only_contains_attribute_certs": False,
|
|
"indirect_crl": False,
|
|
},
|
|
False,
|
|
),
|
|
],
|
|
)
|
|
def test_create_issuing_distribution_point(self, val, expected, critical):
|
|
with patch("cryptography.x509.IssuingDistributionPoint", autospec=True) as ext:
|
|
res, crit = x509._create_extension("issuingDistributionPoint", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(**expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"critical, 1.2.4.5, 1.1.3.4",
|
|
[
|
|
cx509.PolicyInformation(
|
|
policy_identifier=cx509.ObjectIdentifier("1.2.4.5"),
|
|
policy_qualifiers=None,
|
|
),
|
|
cx509.PolicyInformation(
|
|
policy_identifier=cx509.ObjectIdentifier("1.1.3.4"),
|
|
policy_qualifiers=None,
|
|
),
|
|
],
|
|
True,
|
|
),
|
|
(
|
|
{
|
|
"critical": True,
|
|
"1.2.3.4.5": ["https://my.ca.com/pratice_statement"],
|
|
},
|
|
[
|
|
cx509.PolicyInformation(
|
|
policy_identifier=cx509.ObjectIdentifier("1.2.3.4.5"),
|
|
policy_qualifiers=["https://my.ca.com/pratice_statement"],
|
|
)
|
|
],
|
|
True,
|
|
),
|
|
(
|
|
{
|
|
"1.2.3.4.5": [
|
|
"https://my.ca.com/pratice_statement",
|
|
{
|
|
"organization": "myorg",
|
|
"noticeNumbers": [1, 2, 3],
|
|
"text": "mytext",
|
|
},
|
|
]
|
|
},
|
|
[
|
|
cx509.PolicyInformation(
|
|
policy_identifier=cx509.ObjectIdentifier("1.2.3.4.5"),
|
|
policy_qualifiers=[
|
|
"https://my.ca.com/pratice_statement",
|
|
cx509.UserNotice(
|
|
notice_reference=cx509.NoticeReference(
|
|
organization="myorg", notice_numbers=[1, 2, 3]
|
|
),
|
|
explicit_text="mytext",
|
|
),
|
|
],
|
|
)
|
|
],
|
|
False,
|
|
),
|
|
],
|
|
)
|
|
def test_create_certificate_policies(self, val, expected, critical):
|
|
with patch("cryptography.x509.CertificatePolicies", autospec=True) as ext:
|
|
res, crit = x509._create_extension("certificatePolicies", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"requireExplicitPolicy:3",
|
|
{"require_explicit_policy": 3, "inhibit_policy_mapping": None},
|
|
False,
|
|
),
|
|
(
|
|
"critical,requireExplicitPolicy:2,inhibitPolicyMapping:1",
|
|
{"require_explicit_policy": 2, "inhibit_policy_mapping": 1},
|
|
True,
|
|
),
|
|
(
|
|
{
|
|
"critical": True,
|
|
"requireExplicitPolicy": 4,
|
|
"inhibitPolicyMapping": 2,
|
|
},
|
|
{"require_explicit_policy": 4, "inhibit_policy_mapping": 2},
|
|
True,
|
|
),
|
|
],
|
|
)
|
|
def test_create_policy_constraints(self, val, expected, critical):
|
|
with patch("cryptography.x509.PolicyConstraints", autospec=True) as ext:
|
|
res, crit = x509._create_extension("policyConstraints", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(**expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(1, 1, False),
|
|
("critical, 1", 1, True),
|
|
({"critical": True, "value": 1}, 1, True),
|
|
],
|
|
)
|
|
def test_create_inhibit_any_policy(self, val, expected, critical):
|
|
with patch("cryptography.x509.InhibitAnyPolicy", autospec=True) as ext:
|
|
res, crit = x509._create_extension("inhibitAnyPolicy", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,excluded,permitted,critical",
|
|
[
|
|
(
|
|
"critical,permitted;IP:192.168.0.0/255.255.0.0,permitted;email:.example.com,excluded;email:.com",
|
|
[cx509.RFC822Name(".com")],
|
|
[
|
|
cx509.IPAddress(ipaddress.ip_network("192.168.0.0/16")),
|
|
cx509.RFC822Name(".example.com"),
|
|
],
|
|
True,
|
|
),
|
|
(
|
|
{
|
|
"critical": True,
|
|
"permitted": ["IP:192.168.0.0/255.255.0.0", "email:.example.com"],
|
|
"excluded": ["email:.com"],
|
|
},
|
|
[cx509.RFC822Name(".com")],
|
|
[
|
|
cx509.IPAddress(ipaddress.ip_network("192.168.0.0/16")),
|
|
cx509.RFC822Name(".example.com"),
|
|
],
|
|
True,
|
|
),
|
|
],
|
|
)
|
|
def test_create_name_constraints(self, val, excluded, permitted, critical):
|
|
with patch("cryptography.x509.NameConstraints", autospec=True) as ext:
|
|
res, crit = x509._create_extension("nameConstraints", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(
|
|
permitted_subtrees=permitted, excluded_subtrees=excluded
|
|
)
|
|
|
|
def test_create_name_constraints_requires_at_least_one_definition(self):
|
|
with patch("cryptography.x509.NameConstraints", autospec=True):
|
|
with pytest.raises(salt.exceptions.SaltInvocationError):
|
|
x509._create_extension("nameConstraints", {"permitted": []})
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,critical", [([], False), ("critical", True), (["critical"], True)]
|
|
)
|
|
def test_create_no_check(self, val, critical):
|
|
with patch("cryptography.x509.OCSPNoCheck", autospec=True):
|
|
res, crit = x509._create_extension("noCheck", val)
|
|
assert crit == critical
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"critical, status_request, status_request_v2",
|
|
[
|
|
cx509.TLSFeatureType.status_request,
|
|
cx509.TLSFeatureType.status_request_v2,
|
|
],
|
|
True,
|
|
),
|
|
(
|
|
["critical", "status_request"],
|
|
[cx509.TLSFeatureType.status_request],
|
|
True,
|
|
),
|
|
],
|
|
)
|
|
def test_create_tlsfeature(self, val, expected, critical):
|
|
with patch("cryptography.x509.TLSFeature", autospec=True) as ext:
|
|
res, crit = x509._create_extension("tlsfeature", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
def test_create_crl_number(self):
|
|
with patch("cryptography.x509.CRLNumber", autospec=True) as ext:
|
|
res, crit = x509._create_extension("cRLNumber", 3)
|
|
assert crit is False
|
|
ext.assert_called_once_with(3)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"critical, 3",
|
|
3,
|
|
True,
|
|
),
|
|
(
|
|
"3",
|
|
3,
|
|
False,
|
|
),
|
|
(
|
|
3,
|
|
3,
|
|
False,
|
|
),
|
|
],
|
|
)
|
|
def test_create_delta_crl_indicator(self, val, expected, critical):
|
|
with patch("cryptography.x509.DeltaCRLIndicator", autospec=True) as ext:
|
|
res, crit = x509._create_extension("deltaCRLIndicator", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"critical, keyCompromise",
|
|
cx509.ReasonFlags("keyCompromise"),
|
|
True,
|
|
),
|
|
(
|
|
"aACompromise",
|
|
cx509.ReasonFlags("aACompromise"),
|
|
False,
|
|
),
|
|
(
|
|
{"critical": True, "superseded": True},
|
|
cx509.ReasonFlags("superseded"),
|
|
True,
|
|
),
|
|
(
|
|
["critical", "privilegeWithdrawn"],
|
|
cx509.ReasonFlags("privilegeWithdrawn"),
|
|
True,
|
|
),
|
|
],
|
|
)
|
|
def test_create_crl_reason(self, val, expected, critical):
|
|
with patch("cryptography.x509.CRLReason", autospec=True) as ext:
|
|
res, crit = x509._create_extension("CRLReason", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
@pytest.mark.parametrize(
|
|
"val,expected,critical",
|
|
[
|
|
(
|
|
"critical, 2022-10-11 13:37:42",
|
|
datetime.datetime.strptime("2022-10-11 13:37:42", "%Y-%m-%d %H:%M:%S"),
|
|
True,
|
|
),
|
|
(
|
|
"2022-10-11 13:37:42",
|
|
datetime.datetime.strptime("2022-10-11 13:37:42", "%Y-%m-%d %H:%M:%S"),
|
|
False,
|
|
),
|
|
],
|
|
)
|
|
def test_create_invalidity_date(self, val, expected, critical):
|
|
with patch("cryptography.x509.InvalidityDate", autospec=True) as ext:
|
|
res, crit = x509._create_extension("invalidityDate", val)
|
|
assert crit == critical
|
|
ext.assert_called_once_with(expected)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"inpt,cls,parsed",
|
|
[
|
|
(("email", "me@example.com"), cx509.RFC822Name, "me@example.com"),
|
|
(("email", ".example.com"), cx509.RFC822Name, ".example.com"),
|
|
(
|
|
("email", "me@überexample.com"),
|
|
cx509.RFC822Name,
|
|
"me@xn--berexample-8db.com",
|
|
),
|
|
(
|
|
("URI", "https://www.example.com"),
|
|
cx509.UniformResourceIdentifier,
|
|
"https://www.example.com",
|
|
),
|
|
(
|
|
("URI", "https://www.überexample.com"),
|
|
cx509.UniformResourceIdentifier,
|
|
"https://www.xn--berexample-8db.com",
|
|
),
|
|
(("URI", "some/path/only"), cx509.UniformResourceIdentifier, "some/path/only"),
|
|
(("DNS", "example.com"), cx509.DNSName, "example.com"),
|
|
(("DNS", "überexample.com"), cx509.DNSName, "xn--berexample-8db.com"),
|
|
(("DNS", "*.überexample.com"), cx509.DNSName, "*.xn--berexample-8db.com"),
|
|
(("DNS", ".überexample.com"), cx509.DNSName, ".xn--berexample-8db.com"),
|
|
(
|
|
("DNS", "γνῶθι.σεαυτόν.gr"),
|
|
cx509.DNSName,
|
|
"xn--oxakdo9327a.xn--mxahzvhf4c.gr",
|
|
),
|
|
(("RID", "1.2.3.4"), cx509.RegisteredID, cx509.ObjectIdentifier("1.2.3.4")),
|
|
(
|
|
("IP", "13.37.13.37"),
|
|
cx509.IPAddress,
|
|
ipaddress.ip_address("13.37.13.37"),
|
|
),
|
|
(
|
|
("IP", "13.37.13.0/24"),
|
|
cx509.IPAddress,
|
|
ipaddress.ip_network("13.37.13.0/24"),
|
|
),
|
|
(
|
|
("IP", "13.37.13.0/255.255.255.0"),
|
|
cx509.IPAddress,
|
|
ipaddress.ip_network("13.37.13.0/255.255.255.0"),
|
|
),
|
|
(
|
|
("IP", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
|
|
cx509.IPAddress,
|
|
ipaddress.ip_address("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
|
|
),
|
|
(
|
|
("IP", "2001:db8:abcd:0012::0/64"),
|
|
cx509.IPAddress,
|
|
ipaddress.ip_network("2001:db8:abcd:0012::0/64"),
|
|
),
|
|
pytest.param(
|
|
(
|
|
"dirName",
|
|
"CN=mysite.com,O=My Company,L=San Francisco,ST=California,C=US",
|
|
),
|
|
cx509.Name,
|
|
[
|
|
cx509.RelativeDistinguishedName(
|
|
[cx509.NameAttribute(cx509.ObjectIdentifier("2.5.4.6"), value="US")]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.8"), value="California"
|
|
)
|
|
]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.7"), value="San Francisco"
|
|
)
|
|
]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.10"), value="My Company"
|
|
)
|
|
]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.3"), value="mysite.com"
|
|
)
|
|
]
|
|
),
|
|
],
|
|
),
|
|
(
|
|
(
|
|
"dirName",
|
|
{
|
|
"C": "US",
|
|
"ST": "California",
|
|
"L": "San Francisco",
|
|
"O": "My Company",
|
|
"CN": "mysite.com",
|
|
},
|
|
),
|
|
cx509.Name,
|
|
[
|
|
cx509.RelativeDistinguishedName(
|
|
[cx509.NameAttribute(cx509.ObjectIdentifier("2.5.4.6"), value="US")]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.8"), value="California"
|
|
)
|
|
]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.7"), value="San Francisco"
|
|
)
|
|
]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.10"), value="My Company"
|
|
)
|
|
]
|
|
),
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.3"), value="mysite.com"
|
|
)
|
|
]
|
|
),
|
|
],
|
|
),
|
|
(
|
|
("DNS", "some.invalid_doma.in"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"at position 8.*not allowed$",
|
|
),
|
|
(
|
|
("DNS", "some..invalid-doma.in"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Empty Label",
|
|
),
|
|
(
|
|
("DNS", "invalid*.wild.card"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"at position 8.*not allowed",
|
|
),
|
|
(
|
|
("DNS", "invalid.*.wild.card"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"at position 1.*not allowed",
|
|
),
|
|
(
|
|
("DNS", "*..whats.this"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Empty label",
|
|
),
|
|
(
|
|
("DNS", 42),
|
|
salt.exceptions.SaltInvocationError,
|
|
"Expected string value, got int",
|
|
),
|
|
(
|
|
("DNS", ""),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Empty domain",
|
|
),
|
|
(
|
|
("DNS", "ἀνεῤῥίφθω.κύβος͵.gr"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"not allowed at position 6 in 'κύβος͵'$",
|
|
),
|
|
(
|
|
("DNS", "می\u200cخواهم\u200c.iran"),
|
|
salt.exceptions.CommandExecutionError,
|
|
r"Joiner U\+200C not allowed at position 9 in '.*'",
|
|
),
|
|
(
|
|
("DNS", ".*.wildcard-dot.test"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Wildcards and leading dots cannot be present together",
|
|
),
|
|
(
|
|
("email", "invalid@*.mail.address"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Wildcards are not allowed in this context",
|
|
),
|
|
(
|
|
("email", "invalid@.mail.address"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Leading dots are not allowed in this context",
|
|
),
|
|
(
|
|
("email", "Invalid Email <invalid@mail.address>"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"not allowed$",
|
|
),
|
|
(
|
|
("IP", "this is not an IP address"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"does not seem to be an IP address or network range.",
|
|
),
|
|
(
|
|
("URI", "https://*.χάος.σκάλα.gr"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Wildcards are not allowed in this context",
|
|
),
|
|
(
|
|
("URI", "https://.invalid.host"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Leading dots are not allowed in this context",
|
|
),
|
|
(
|
|
("dirName", "Et tu, Brute?"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Failed parsing rfc4514 dirName string",
|
|
),
|
|
(
|
|
("otherName", "otherName:1.2.3.4;UTF8:some other identifier"),
|
|
salt.exceptions.SaltInvocationError,
|
|
"otherName is currently not implemented",
|
|
),
|
|
(
|
|
("invalidType", "L'état c'est moi!"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"GeneralName type invalidtype is invalid",
|
|
),
|
|
],
|
|
)
|
|
def test_parse_general_names(inpt, cls, parsed):
|
|
if issubclass(cls, Exception):
|
|
with pytest.raises(cls, match=parsed):
|
|
x509._parse_general_names([inpt])
|
|
return
|
|
expected = cls(parsed)
|
|
res = x509._parse_general_names([inpt])
|
|
if inpt[0] == "dirName":
|
|
assert res[0].value == expected
|
|
else:
|
|
assert res[0] == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"inpt,cls,parsed",
|
|
[
|
|
(("email", "me@example.com"), cx509.RFC822Name, "me@example.com"),
|
|
(
|
|
("URI", "https://www.example.com"),
|
|
cx509.UniformResourceIdentifier,
|
|
"https://www.example.com",
|
|
),
|
|
(("DNS", "example.com"), cx509.DNSName, "example.com"),
|
|
(("DNS", "*.example.com"), cx509.DNSName, "*.example.com"),
|
|
(("DNS", ".example.com"), cx509.DNSName, ".example.com"),
|
|
(
|
|
("DNS", "invalid*.wild.card"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"at position 8.*not allowed",
|
|
),
|
|
(
|
|
("DNS", "invalid.*.wild.card"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"at position 1.*not allowed",
|
|
),
|
|
(
|
|
("DNS", ".*.wildcard-dot.test"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Wildcards and leading dots cannot be present together",
|
|
),
|
|
(
|
|
("DNS", "gott.würfelt.nicht"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Cannot encode non-ASCII strings",
|
|
),
|
|
(
|
|
("DNS", "some.invalid_doma.in"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"at position 8.*not allowed$",
|
|
),
|
|
(
|
|
("DNS", "some..invalid-doma.in"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Empty Label",
|
|
),
|
|
(
|
|
("DNS", 42),
|
|
salt.exceptions.SaltInvocationError,
|
|
"Expected string value, got int",
|
|
),
|
|
(
|
|
("DNS", ""),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Empty domain",
|
|
),
|
|
(
|
|
("DNS", "*..whats.this"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Empty label",
|
|
),
|
|
(
|
|
("email", "invalid@*.mail.address"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Wildcards are not allowed in this context",
|
|
),
|
|
(
|
|
("email", "invalid@.mail.address"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Leading dots are not allowed in this context",
|
|
),
|
|
(
|
|
("email", "Invalid Email <invalid@mail.address>"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"not allowed$",
|
|
),
|
|
(
|
|
("URI", "https://.invalid.host"),
|
|
salt.exceptions.CommandExecutionError,
|
|
"Leading dots are not allowed in this context",
|
|
),
|
|
],
|
|
)
|
|
def test_parse_general_names_without_idna(inpt, cls, parsed):
|
|
with patch("salt.utils.x509.HAS_IDNA", False):
|
|
if issubclass(cls, Exception):
|
|
with pytest.raises(cls, match=parsed):
|
|
x509._parse_general_names([inpt])
|
|
return
|
|
expected = cls(parsed)
|
|
res = x509._parse_general_names([inpt])
|
|
if inpt[0] == "dirName":
|
|
assert res[0].value == expected
|
|
else:
|
|
assert res[0] == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"inpt",
|
|
[
|
|
(("RID", "3.2.3.4")),
|
|
(("RID", "1.2.3.4a")),
|
|
(("IP", "13.37.1337.37")),
|
|
(("IP", "13a.37.13.0/24")),
|
|
(("IP", "13.37.13.0:255.255.255.0")),
|
|
(("IP", "20010db8:85a3:0000:0000:8a2e:0370:7334")),
|
|
(("IP", "2001:db8:abcd:0012::0.64")),
|
|
(("dirName", "CC=US,ST=California,L=San Francisco,O=My Company,CN=mysite.com")),
|
|
],
|
|
)
|
|
def test_parse_general_names_rejects_invalid(inpt):
|
|
with pytest.raises(salt.exceptions.CommandExecutionError):
|
|
x509._parse_general_names([inpt])
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"inpt,expected",
|
|
[
|
|
pytest.param(
|
|
"CN=example.com,O=Example Inc,C=US",
|
|
[
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["C"], "US"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["O"], "Example Inc"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["CN"], "example.com"),
|
|
],
|
|
),
|
|
pytest.param(
|
|
["C=US", "O=Example Inc", "CN=example.com"],
|
|
[
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["C"], "US"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["O"], "Example Inc"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["CN"], "example.com"),
|
|
],
|
|
),
|
|
pytest.param(
|
|
["C=US", "O=Example Inc", "OU=foo+CN=example.com"],
|
|
[
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["C"], "US"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["O"], "Example Inc"),
|
|
cx509.RelativeDistinguishedName(
|
|
{
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["CN"], "example.com"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["OU"], "foo"),
|
|
}
|
|
),
|
|
],
|
|
),
|
|
(
|
|
{"CN": "example.com", "O": "Example Inc", "C": "US", "irrelevant": "bar"},
|
|
[
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["C"], "US"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["O"], "Example Inc"),
|
|
cx509.NameAttribute(x509.NAME_ATTRS_OID["CN"], "example.com"),
|
|
],
|
|
),
|
|
],
|
|
)
|
|
def test_get_dn(inpt, expected):
|
|
expected_parsed = [
|
|
(
|
|
cx509.RelativeDistinguishedName({x})
|
|
if not isinstance(x, cx509.RelativeDistinguishedName)
|
|
else x
|
|
)
|
|
for x in expected
|
|
]
|
|
res = x509._get_dn(inpt)
|
|
assert res.rdns == expected_parsed
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"inpt,expected",
|
|
[
|
|
(
|
|
cx509.Extension(
|
|
cx509.BasicConstraints.oid,
|
|
value=cx509.BasicConstraints(ca=True, path_length=2),
|
|
critical=True,
|
|
),
|
|
{"ca": True, "critical": True, "pathlen": 2},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.KeyUsage.oid,
|
|
value=cx509.KeyUsage(
|
|
digital_signature=True,
|
|
content_commitment=False,
|
|
key_encipherment=False,
|
|
data_encipherment=False,
|
|
key_agreement=False,
|
|
key_cert_sign=False,
|
|
crl_sign=False,
|
|
encipher_only=False,
|
|
decipher_only=False,
|
|
),
|
|
critical=True,
|
|
),
|
|
{
|
|
"cRLSign": False,
|
|
"critical": True,
|
|
"dataEncipherment": False,
|
|
"decipherOnly": False,
|
|
"digitalSignature": True,
|
|
"encipherOnly": False,
|
|
"keyAgreement": False,
|
|
"keyCertSign": False,
|
|
"keyEncipherment": False,
|
|
"nonRepudiation": False,
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.ExtendedKeyUsage.oid,
|
|
value=cx509.ExtendedKeyUsage(
|
|
[
|
|
x509.EXTENDED_KEY_USAGE_OID["OCSPSigning"],
|
|
x509.EXTENDED_KEY_USAGE_OID["msCodeCom"],
|
|
cx509.ObjectIdentifier("2.3.4.55"),
|
|
]
|
|
),
|
|
critical=True,
|
|
),
|
|
{
|
|
"critical": True,
|
|
"value": ["OCSPSigning", "1.3.6.1.4.1.311.2.1.22", "2.3.4.55"],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.SubjectKeyIdentifier.oid,
|
|
value=cx509.SubjectKeyIdentifier(
|
|
b"\xbb\xaf~\x02=\xfa\xa6\xf1<\x84\x8e\xad\xee8\x98\xec\xd922\xd4"
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"value": "BB:AF:7E:02:3D:FA:A6:F1:3C:84:8E:AD:EE:38:98:EC:D9:32:32:D4",
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.AuthorityKeyIdentifier.oid,
|
|
value=cx509.AuthorityKeyIdentifier(
|
|
key_identifier=b"\xde\xad\xbe\xef",
|
|
authority_cert_issuer=[
|
|
cx509.DirectoryName(
|
|
cx509.Name(
|
|
[
|
|
cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.3"),
|
|
value="foo",
|
|
)
|
|
]
|
|
)
|
|
]
|
|
)
|
|
)
|
|
],
|
|
authority_cert_serial_number=1337,
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"issuer": ["dirName:CN=foo"],
|
|
"issuer_sn": "05:39",
|
|
"keyid": "DE:AD:BE:EF",
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.IssuerAlternativeName.oid,
|
|
value=cx509.IssuerAlternativeName(
|
|
[
|
|
cx509.RFC822Name("ca@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
cx509.DNSName("example.io"),
|
|
]
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"value": ["mail:ca@example.com", "DNS:example.com", "DNS:example.io"],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.CertificateIssuer.oid,
|
|
value=cx509.CertificateIssuer(
|
|
[
|
|
cx509.RFC822Name("ca@example.com"),
|
|
cx509.DNSName("example.com"),
|
|
cx509.DNSName("example.io"),
|
|
]
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"value": ["mail:ca@example.com", "DNS:example.com", "DNS:example.io"],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.AuthorityInformationAccess.oid,
|
|
value=cx509.AuthorityInformationAccess(
|
|
[
|
|
cx509.AccessDescription(
|
|
access_method=x509.ACCESS_OID["OCSP"],
|
|
access_location=cx509.UniformResourceIdentifier(
|
|
"http://ocsp.example.com/"
|
|
),
|
|
),
|
|
cx509.AccessDescription(
|
|
access_method=x509.ACCESS_OID["OCSP"],
|
|
access_location=cx509.UniformResourceIdentifier(
|
|
"http://ocsp2.example.com/"
|
|
),
|
|
),
|
|
]
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"value": [
|
|
{"OCSP": "http://ocsp.example.com/"},
|
|
{"OCSP": "http://ocsp2.example.com/"},
|
|
],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.SubjectAlternativeName.oid,
|
|
value=cx509.SubjectAlternativeName(
|
|
[cx509.DNSName("example.io"), cx509.RFC822Name("hello@example.io")]
|
|
),
|
|
critical=False,
|
|
),
|
|
{"critical": False, "value": ["DNS:example.io", "mail:hello@example.io"]},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.CRLDistributionPoints.oid,
|
|
value=cx509.CRLDistributionPoints(
|
|
[
|
|
cx509.DistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier(
|
|
"http://example.com/myca.crl"
|
|
)
|
|
],
|
|
relative_name=None,
|
|
reasons=frozenset([cx509.ReasonFlags("keyCompromise")]),
|
|
crl_issuer=[cx509.DNSName("example.org")],
|
|
),
|
|
cx509.DistributionPoint(
|
|
full_name=None,
|
|
relative_name=cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.11"), value="foo"
|
|
),
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.3"), value="Smith"
|
|
),
|
|
]
|
|
),
|
|
reasons=None,
|
|
crl_issuer=[cx509.DNSName("example.org")],
|
|
),
|
|
]
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"value": [
|
|
{
|
|
"crlissuer": ["DNS:example.org"],
|
|
"fullname": ["URI:http://example.com/myca.crl"],
|
|
"reasons": ["keyCompromise"],
|
|
"relativename": None,
|
|
},
|
|
{
|
|
"crlissuer": ["DNS:example.org"],
|
|
"fullname": [],
|
|
"reasons": [],
|
|
"relativename": "OU=foo+CN=Smith",
|
|
},
|
|
],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.FreshestCRL.oid,
|
|
value=cx509.FreshestCRL(
|
|
[
|
|
cx509.DistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier(
|
|
"http://example.com/myca.crl"
|
|
)
|
|
],
|
|
relative_name=None,
|
|
reasons=frozenset([cx509.ReasonFlags("keyCompromise")]),
|
|
crl_issuer=[cx509.DNSName("example.org")],
|
|
),
|
|
cx509.DistributionPoint(
|
|
full_name=None,
|
|
relative_name=cx509.RelativeDistinguishedName(
|
|
[
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.11"), value="foo"
|
|
),
|
|
cx509.NameAttribute(
|
|
cx509.ObjectIdentifier("2.5.4.3"), value="Smith"
|
|
),
|
|
]
|
|
),
|
|
reasons=None,
|
|
crl_issuer=[cx509.DNSName("example.org")],
|
|
),
|
|
]
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"value": [
|
|
{
|
|
"crlissuer": ["DNS:example.org"],
|
|
"fullname": ["URI:http://example.com/myca.crl"],
|
|
"reasons": ["keyCompromise"],
|
|
"relativename": None,
|
|
},
|
|
{
|
|
"crlissuer": ["DNS:example.org"],
|
|
"fullname": [],
|
|
"reasons": [],
|
|
"relativename": "OU=foo+CN=Smith",
|
|
},
|
|
],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.IssuingDistributionPoint.oid,
|
|
value=cx509.IssuingDistributionPoint(
|
|
full_name=[
|
|
cx509.UniformResourceIdentifier("http://example.com/myca.crl")
|
|
],
|
|
relative_name=None,
|
|
only_some_reasons=frozenset([cx509.ReasonFlags("keyCompromise")]),
|
|
only_contains_user_certs=True,
|
|
only_contains_ca_certs=False,
|
|
only_contains_attribute_certs=False,
|
|
indirect_crl=False,
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"fullname": ["URI:http://example.com/myca.crl"],
|
|
"indirectCRL": False,
|
|
"onlyAA": False,
|
|
"onlyCA": False,
|
|
"onlyuser": True,
|
|
"onysomereasons": ["keyCompromise"],
|
|
"relativename": None,
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.CertificatePolicies.oid,
|
|
value=cx509.CertificatePolicies(
|
|
[
|
|
cx509.PolicyInformation(
|
|
policy_identifier=cx509.ObjectIdentifier("1.2.3.4.5"),
|
|
policy_qualifiers=[
|
|
"https://my.ca.com/pratice_statement",
|
|
cx509.UserNotice(
|
|
notice_reference=cx509.NoticeReference(
|
|
organization="myorg", notice_numbers=[1, 2, 3]
|
|
),
|
|
explicit_text="mytext",
|
|
),
|
|
],
|
|
)
|
|
]
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"value": [
|
|
{
|
|
"1.2.3.4.5": [
|
|
{
|
|
"practice_statement": "https://my.ca.com/pratice_statement"
|
|
},
|
|
{
|
|
"explicit_text": "mytext",
|
|
"notice_numbers": [1, 2, 3],
|
|
"organizataion": "myorg",
|
|
},
|
|
]
|
|
}
|
|
],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.PolicyConstraints.oid,
|
|
value=cx509.PolicyConstraints(
|
|
require_explicit_policy=4, inhibit_policy_mapping=2
|
|
),
|
|
critical=False,
|
|
),
|
|
{"critical": False, "inhibitPolicyMapping": 2, "requireExplicitPolicy": 4},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.InhibitAnyPolicy.oid,
|
|
value=cx509.InhibitAnyPolicy(1),
|
|
critical=False,
|
|
),
|
|
{"critical": False, "value": 1},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.NameConstraints.oid,
|
|
value=cx509.NameConstraints(
|
|
[
|
|
cx509.IPAddress(ipaddress.ip_network("192.168.0.0/16")),
|
|
cx509.RFC822Name(".example.com"),
|
|
],
|
|
[cx509.RFC822Name(".com")],
|
|
),
|
|
critical=False,
|
|
),
|
|
{
|
|
"critical": False,
|
|
"excluded": ["mail:.com"],
|
|
"permitted": ["IP:192.168.0.0/16", "mail:.example.com"],
|
|
},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.OCSPNoCheck.oid, value=cx509.OCSPNoCheck(), critical=False
|
|
),
|
|
{"critical": False, "value": True},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.TLSFeature.oid,
|
|
value=cx509.TLSFeature([cx509.TLSFeatureType.status_request]),
|
|
critical=False,
|
|
),
|
|
{"critical": False, "value": ["status_request"]},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.CRLNumber.oid, value=cx509.CRLNumber(3), critical=False
|
|
),
|
|
{"critical": False, "value": 3},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.DeltaCRLIndicator.oid,
|
|
value=cx509.DeltaCRLIndicator(3),
|
|
critical=False,
|
|
),
|
|
{"critical": False, "value": 3},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.CRLReason.oid,
|
|
value=cx509.CRLReason(cx509.ReasonFlags("superseded")),
|
|
critical=False,
|
|
),
|
|
{"critical": False, "value": "superseded"},
|
|
),
|
|
(
|
|
cx509.Extension(
|
|
cx509.InvalidityDate.oid,
|
|
value=cx509.InvalidityDate(
|
|
datetime.datetime.strptime(
|
|
"2022-10-11 13:37:42", "%Y-%m-%d %H:%M:%S"
|
|
)
|
|
),
|
|
critical=False,
|
|
),
|
|
{"critical": False, "value": "2022-10-11 13:37:42"},
|
|
),
|
|
],
|
|
)
|
|
def test_render_extension(inpt, expected):
|
|
ret = x509.render_extension(inpt)
|
|
assert ret == expected
|