示例#1
0
def client_context(ca: CA) -> SSLContext:
    client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
    if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"):
        client_context.options ^= ssl.OP_IGNORE_UNEXPECTED_EOF  # type: ignore[attr-defined]

    ca.configure_trust(client_context)
    return client_context
示例#2
0
def server_context(ca: CA) -> SSLContext:
    server_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"):
        server_context.options ^= ssl.OP_IGNORE_UNEXPECTED_EOF  # type: ignore[attr-defined]

    ca.issue_cert("localhost").configure_cert(server_context)
    return server_context
示例#3
0
def test_identity_variants():
    ca = CA()

    for bad in [b"example.org", bytearray(b"example.org"), 123]:
        with pytest.raises(TypeError):
            ca.issue_cert(bad)

    cases = {
        # Traditional ascii hostname
        u"example.org": x509.DNSName(u"example.org"),

        # Wildcard
        u"*.example.org": x509.DNSName(u"*.example.org"),

        # IDN
        u"éxamplë.org": x509.DNSName(u"xn--xampl-9rat.org"),
        u"xn--xampl-9rat.org": x509.DNSName(u"xn--xampl-9rat.org"),

        # IDN + wildcard
        u"*.éxamplë.org": x509.DNSName(u"*.xn--xampl-9rat.org"),
        u"*.xn--xampl-9rat.org": x509.DNSName(u"*.xn--xampl-9rat.org"),

        # IDN that acts differently in IDNA-2003 vs IDNA-2008
        u"faß.de": x509.DNSName(u"xn--fa-hia.de"),
        u"xn--fa-hia.de": x509.DNSName(u"xn--fa-hia.de"),

        # IDN with non-permissable character (uppercase K)
        # (example taken from idna package docs)
        u"Königsgäßchen.de": x509.DNSName(u"xn--knigsgchen-b4a3dun.de"),

        # IP addresses
        u"127.0.0.1": x509.IPAddress(IPv4Address(u"127.0.0.1")),
        u"::1": x509.IPAddress(IPv6Address(u"::1")),
        # Check normalization
        u"0000::1": x509.IPAddress(IPv6Address(u"::1")),

        # IP networks
        u"127.0.0.0/24": x509.IPAddress(IPv4Network(u"127.0.0.0/24")),
        u"2001::/16": x509.IPAddress(IPv6Network(u"2001::/16")),
        # Check normalization
        u"2001:0000::/16": x509.IPAddress(IPv6Network(u"2001::/16")),

        # Email address
        u"*****@*****.**": x509.RFC822Name(u"*****@*****.**"),
    }

    for hostname, expected in cases.items():
        # Can't repr the got or expected values here, at least until
        # cryptography v2.1 is out, because in v2.0 on py2, DNSName.__repr__
        # blows up on IDNs.
        print("testing: {!r}".format(hostname))
        pem = ca.issue_cert(hostname).cert_chain_pems[0].bytes()
        cert = x509.load_pem_x509_certificate(pem, default_backend())
        san = cert.extensions.get_extension_for_class(
            x509.SubjectAlternativeName
        )
        assert_is_leaf(cert)
        got = san.value[0]
        assert got == expected
示例#4
0
def test_unrecognized_context_type():
    ca = CA()
    server = ca.issue_cert(u"test-1.example.org")

    with pytest.raises(TypeError):
        ca.configure_trust(None)

    with pytest.raises(TypeError):
        server.configure_cert(None)
示例#5
0
def test_CN():
    ca = CA()

    # Since we have to emulate kwonly args here, I guess we should test the
    # emulation logic
    with pytest.raises(TypeError):
        ca.issue_cert(comon_nam=u"wrong kwarg name")

    # Must be unicode
    with pytest.raises(TypeError):
        ca.issue_cert(common_name=b"bad kwarg value")

    # Default is no common name
    pem = ca.issue_cert(u"example.com").cert_chain_pems[0].bytes()
    cert = x509.load_pem_x509_certificate(pem, default_backend())
    common_names = cert.subject.get_attributes_for_oid(
        x509.oid.NameOID.COMMON_NAME)
    assert common_names == []

    # Common name on its own is valid
    pem = ca.issue_cert(common_name=u"woo").cert_chain_pems[0].bytes()
    cert = x509.load_pem_x509_certificate(pem, default_backend())
    common_names = cert.subject.get_attributes_for_oid(
        x509.oid.NameOID.COMMON_NAME)
    assert common_names[0].value == u"woo"

    # Common name + SAN
    pem = ca.issue_cert(u"example.com",
                        common_name=u"woo").cert_chain_pems[0].bytes()
    cert = x509.load_pem_x509_certificate(pem, default_backend())
    san = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName)
    assert san.value[0] == x509.DNSName(u"example.com")
    common_names = cert.subject.get_attributes_for_oid(
        x509.oid.NameOID.COMMON_NAME)
    assert common_names[0].value == u"woo"
示例#6
0
def test_basics():
    ca = CA()

    today = datetime.datetime.today()

    assert b"BEGIN RSA PRIVATE KEY" in ca.private_key_pem.bytes()
    assert b"BEGIN CERTIFICATE" in ca.cert_pem.bytes()

    private_key = load_pem_private_key(ca.private_key_pem.bytes(),
                                       password=None,
                                       backend=default_backend())

    ca_cert = x509.load_pem_x509_certificate(ca.cert_pem.bytes(),
                                             default_backend())
    assert ca_cert.not_valid_before <= today <= ca_cert.not_valid_after

    public_key1 = private_key.public_key().public_bytes(
        Encoding.PEM, PublicFormat.PKCS1)
    public_key2 = ca_cert.public_key().public_bytes(Encoding.PEM,
                                                    PublicFormat.PKCS1)
    assert public_key1 == public_key2

    assert ca_cert.issuer == ca_cert.subject
    assert_is_ca(ca_cert)

    with pytest.raises(ValueError):
        ca.issue_cert()

    server = ca.issue_cert(u"test-1.example.org", u"test-2.example.org")

    assert b"PRIVATE KEY" in server.private_key_pem.bytes()
    assert b"BEGIN CERTIFICATE" in server.cert_chain_pems[0].bytes()
    assert len(server.cert_chain_pems) == 1
    assert server.private_key_pem.bytes(
    ) in server.private_key_and_cert_chain_pem.bytes()
    for blob in server.cert_chain_pems:
        assert blob.bytes() in server.private_key_and_cert_chain_pem.bytes()

    server_cert = x509.load_pem_x509_certificate(
        server.cert_chain_pems[0].bytes(), default_backend())

    assert server_cert.not_valid_before <= today <= server_cert.not_valid_after
    assert server_cert.issuer == ca_cert.subject

    san = server_cert.extensions.get_extension_for_class(
        x509.SubjectAlternativeName)
    hostnames = san.value.get_values_for_type(x509.DNSName)
    assert hostnames == [u"test-1.example.org", u"test-2.example.org"]
示例#7
0
def test_issue_cert_custom_names():
    ca = CA()
    leaf_cert = ca.issue_cert(
        u'example.org',
        organization_name=u'python-trio',
        organization_unit_name=u'trustme',
    )

    cert = x509.load_pem_x509_certificate(
        leaf_cert.cert_chain_pems[0].bytes(),
        default_backend(),
    )

    assert {
        'O=python-trio',
        'OU=trustme',
    }.issubset({rdn.rfc4514_string()
                for rdn in cert.subject.rdns})
示例#8
0
    async def test_send_eof_not_implemented(self,
                                            server_context: ssl.SSLContext,
                                            ca: CA,
                                            force_tlsv12: bool) -> None:
        def serve_sync() -> None:
            conn, addr = server_sock.accept()
            conn.sendall(b"hello")
            conn.unwrap()
            conn.close()

        client_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
        ca.configure_trust(client_context)
        if force_tlsv12:
            expected_pattern = r"send_eof\(\) requires at least TLSv1.3"
            if hasattr(ssl, "TLSVersion"):
                client_context.maximum_version = ssl.TLSVersion.TLSv1_2
            else:  # Python 3.6
                client_context.options |= ssl.OP_NO_TLSv1_3
        else:
            expected_pattern = (
                r"send_eof\(\) has not yet been implemented for TLS streams")

        server_sock = server_context.wrap_socket(socket.socket(),
                                                 server_side=True,
                                                 suppress_ragged_eofs=False)
        server_sock.settimeout(1)
        server_sock.bind(("127.0.0.1", 0))
        server_sock.listen()
        server_thread = Thread(target=serve_sync, daemon=True)
        server_thread.start()

        stream = await connect_tcp(*server_sock.getsockname())
        async with await TLSStream.wrap(stream,
                                        hostname="localhost",
                                        ssl_context=client_context) as wrapper:
            assert await wrapper.receive() == b"hello"
            with pytest.raises(NotImplementedError) as exc:
                await wrapper.send_eof()

            exc.match(expected_pattern)

        server_thread.join()
        server_sock.close()
示例#9
0
def test_issue_cert_custom_not_after():
     now = datetime.datetime.now()
     expires = datetime.datetime(2025, 12, 1, 8, 10, 10)
     ca = CA()

     leaf_cert = ca.issue_cert(
         u'example.org',
         organization_name=u'python-trio',
         organization_unit_name=u'trustme',
         not_after=expires,
     )

     cert = x509.load_pem_x509_certificate(
         leaf_cert.cert_chain_pems[0].bytes(),
         default_backend(),
     )

     for t in ["year", "month", "day", "hour", "minute", "second"]:
         assert getattr(cert.not_valid_after, t) == getattr(expires, t)
示例#10
0
def test_intermediate():
    ca = CA()
    ca_cert = x509.load_pem_x509_certificate(ca.cert_pem.bytes(),
                                             default_backend())
    assert_is_ca(ca_cert)
    assert ca_cert.issuer == ca_cert.subject
    assert _path_length(ca_cert) == 9

    child_ca = ca.create_child_ca()
    child_ca_cert = x509.load_pem_x509_certificate(child_ca.cert_pem.bytes(),
                                                   default_backend())
    assert_is_ca(child_ca_cert)
    assert child_ca_cert.issuer == ca_cert.subject
    assert _path_length(child_ca_cert) == 8

    child_server = child_ca.issue_cert(u"test-host.example.org")
    assert len(child_server.cert_chain_pems) == 2
    child_server_cert = x509.load_pem_x509_certificate(
        child_server.cert_chain_pems[0].bytes(), default_backend())
    assert child_server_cert.issuer == child_ca_cert.subject
示例#11
0
def test_ca_custom_names():
    ca = CA(
        organization_name=u'python-trio',
        organization_unit_name=u'trustme',
    )

    ca_cert = x509.load_pem_x509_certificate(
        ca.cert_pem.bytes(),
        default_backend(),
    )

    assert {
        'O=python-trio',
        'OU=trustme',
    }.issubset({rdn.rfc4514_string()
                for rdn in ca_cert.subject.rdns})
示例#12
0
def test_path_length():
    ca = CA()
    ca_cert = x509.load_pem_x509_certificate(ca.cert_pem.bytes(),
                                             default_backend())
    assert _path_length(ca_cert) == 9

    child_ca = ca
    for i in range(9):
        child_ca = child_ca.create_child_ca()

    # Can't create new child CAs anymore
    child_ca_cert = x509.load_pem_x509_certificate(child_ca.cert_pem.bytes(),
                                                   default_backend())
    assert _path_length(child_ca_cert) == 0
    with pytest.raises(ValueError):
        child_ca.create_child_ca()
示例#13
0
def client_ssl_ctx(tls_certificate_authority: trustme.CA) -> ssl.SSLContext:
    ssl_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
    tls_certificate_authority.configure_trust(ssl_ctx)
    return ssl_ctx
示例#14
0
def test_backcompat():
    ca = CA()
    # We can still use the old name
    ca.issue_server_cert(u"example.com")
示例#15
0
def check_connection_end_to_end(wrap_client, wrap_server):
    # Client side
    def fake_ssl_client(ca, raw_client_sock, hostname):
        try:
            wrapped_client_sock = wrap_client(ca, raw_client_sock, hostname)
            # Send and receive some data to prove the connection is good
            wrapped_client_sock.send(b"x")
            assert wrapped_client_sock.recv(1) == b"y"
        except:  # pragma: no cover
            sys.excepthook(*sys.exc_info())
            raise
        finally:
            raw_client_sock.close()

    # Server side
    def fake_ssl_server(server_cert, raw_server_sock):
        try:
            wrapped_server_sock = wrap_server(server_cert, raw_server_sock)
            # Prove that we're connected
            assert wrapped_server_sock.recv(1) == b"x"
            wrapped_server_sock.send(b"y")
        except:  # pragma: no cover
            sys.excepthook(*sys.exc_info())
            raise
        finally:
            raw_server_sock.close()

    def doit(ca, hostname, server_cert):
        # socketpair and ssl don't work together on py2, because... reasons.
        # So we need to do this the hard way.
        listener = socket.socket()
        listener.bind(("127.0.0.1", 0))
        listener.listen(1)
        raw_client_sock = socket.socket()
        raw_client_sock.connect(listener.getsockname())
        raw_server_sock, _ = listener.accept()
        listener.close()
        with ThreadPoolExecutor(2) as tpe:
            f1 = tpe.submit(fake_ssl_client, ca, raw_client_sock, hostname)
            f2 = tpe.submit(fake_ssl_server, server_cert, raw_server_sock)
            f1.result()
            f2.result()

    ca = CA()
    intermediate_ca = ca.create_child_ca()
    hostname = u"my-test-host.example.org"

    # Should work
    doit(ca, hostname, ca.issue_cert(hostname))

    # Should work
    doit(ca, hostname, intermediate_ca.issue_cert(hostname))

    # To make sure that the above success actually required that the
    # CA and cert logic is all working, make sure that the same code
    # fails if the certs or CA aren't right:

    # Bad hostname fails
    with pytest.raises(Exception):
        doit(ca, u"asdf.example.org", ca.issue_cert(hostname))

    # Bad CA fails
    bad_ca = CA()
    with pytest.raises(Exception):
        doit(bad_ca, hostname, ca.issue_cert(hostname))
示例#16
0
def ca_ssl_context(cert_authority: trustme.CA) -> ssl.SSLContext:
    ctx = ssl.create_default_context()
    cert_authority.configure_trust(ctx)
    return ctx
示例#17
0
def example_org_cert(cert_authority: trustme.CA) -> trustme.LeafCert:
    return cert_authority.issue_cert("example.org")
示例#18
0
def tls_certificate(tls_certificate_authority: trustme.CA) -> trustme.LeafCert:
    return tls_certificate_authority.issue_server_cert(
        "localhost",
        "127.0.0.1",
        "::1",
    )
示例#19
0
def localhost_cert(cert_authority: trustme.CA) -> trustme.LeafCert:
    return cert_authority.issue_cert("localhost")