Files @ 5e176c2a3067
Branch filter:

Location: gimmecert/tests/test_storage.py - annotation

branko
GC-37: Parametrise a couple of storage test functions to cover ECDSA as well.
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
84ba90064e85
9f09715ce550
7a2919409da2
7a2919409da2
7a2919409da2
9f09715ce550
9f09715ce550
71e316da896f
9f09715ce550
a7af49f9e2c3
a7af49f9e2c3
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
7a2919409da2
a6b448968a50
9f09715ce550
9f09715ce550
5e176c2a3067
5e176c2a3067
5e176c2a3067
5e176c2a3067
5e176c2a3067
9f09715ce550
9f09715ce550
5e176c2a3067
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
5e176c2a3067
5e176c2a3067
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
89d391511fdb
89d391511fdb
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
9f09715ce550
71e316da896f
71e316da896f
71e316da896f
71e316da896f
de1cc2505a56
71e316da896f
71e316da896f
71e316da896f
1b16b8ce67df
1b16b8ce67df
71e316da896f
71e316da896f
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
988ac40d5cec
7a2919409da2
7a2919409da2
a7af49f9e2c3
a7af49f9e2c3
a7af49f9e2c3
a7af49f9e2c3
a7af49f9e2c3
7a2919409da2
a7af49f9e2c3
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
a7af49f9e2c3
7a2919409da2
7a2919409da2
7a2919409da2
5e176c2a3067
5e176c2a3067
5e176c2a3067
5e176c2a3067
5e176c2a3067
7a2919409da2
5e176c2a3067
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
5e176c2a3067
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
89d391511fdb
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
a7af49f9e2c3
a7af49f9e2c3
a7af49f9e2c3
a7af49f9e2c3
5e176c2a3067
5e176c2a3067
7a2919409da2
a7af49f9e2c3
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
7a2919409da2
a7af49f9e2c3
7a2919409da2
7a2919409da2
a7af49f9e2c3
7a2919409da2
7a2919409da2
a7af49f9e2c3
7a2919409da2
7a2919409da2
a7af49f9e2c3
7a2919409da2
7a2919409da2
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
89d391511fdb
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
89d391511fdb
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
647208f5016b
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018 Branko Majic
#
# This file is part of Gimmecert.
#
# Gimmecert is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# Gimmecert is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Gimmecert.  If not, see <http://www.gnu.org/licenses/>.
#

import os
import io

import cryptography

import gimmecert.commands
import gimmecert.crypto
import gimmecert.storage
import gimmecert.utils

import pytest


def test_initialise_storage(tmpdir):
    tmpdir.chdir()

    gimmecert.storage.initialise_storage(tmpdir.strpath)

    assert os.path.exists(tmpdir.join('.gimmecert').strpath)
    assert os.path.exists(tmpdir.join('.gimmecert', 'ca').strpath)
    assert os.path.exists(tmpdir.join('.gimmecert', 'server').strpath)
    assert os.path.exists(tmpdir.join('.gimmecert', 'client').strpath)


@pytest.mark.parametrize("key_specification, key_type_representation", [
    [("rsa", 2048), "RSA"],
    [("ecdsa", cryptography.hazmat.primitives.asymmetric.ec.SECP192R1), "EC"],
])
def test_write_private_key(tmpdir, key_specification, key_type_representation):
    tmpdir.chdir()

    private_key = gimmecert.crypto.KeyGenerator(*key_specification)()
    key_path = tmpdir.join('test.key.pem').strpath

    gimmecert.storage.write_private_key(private_key, key_path)

    assert os.path.exists(key_path)

    with open(key_path, 'r') as key_file:
        content = key_file.read()
        assert 'BEGIN %s PRIVATE KEY' % key_type_representation in content
        assert 'END %s PRIVATE KEY' % key_type_representation in content


def test_write_certificate(tmpdir):
    tmpdir.chdir()

    issuer_dn = gimmecert.crypto.get_dn('My test 1')
    subject_dn = gimmecert.crypto.get_dn('My test 2')
    issuer_private_key = gimmecert.crypto.KeyGenerator('rsa', 2048)()
    subject_private_key = gimmecert.crypto.KeyGenerator('rsa', 2048)()
    not_before, not_after = gimmecert.crypto.get_validity_range()
    certificate = gimmecert.crypto.issue_certificate(issuer_dn, subject_dn, issuer_private_key, subject_private_key.public_key(), not_before, not_after)

    certificate_path = tmpdir.join('test.key.pem').strpath

    gimmecert.storage.write_certificate(certificate, certificate_path)

    assert os.path.exists(certificate_path)

    with open(certificate_path, 'r') as certificate_file:
        content = certificate_file.read()
        assert 'BEGIN CERTIFICATE' in content
        assert 'END CERTIFICATE' in content


def test_write_certificate_chain(tmpdir):
    output_file = tmpdir.join('chain.cert.pem')
    certificate_chain = [certificate for _, certificate in gimmecert.crypto.generate_ca_hierarchy('My Project', 3, gimmecert.crypto.KeyGenerator("rsa", 2048))]
    level1_pem, level2_pem, level3_pem = [gimmecert.utils.certificate_to_pem(certificate) for certificate in certificate_chain]

    gimmecert.storage.write_certificate_chain(certificate_chain, output_file.strpath)
    content = output_file.read(mode='r')
    expected_content = "%s\n%s\n%s" % (level1_pem, level2_pem, level3_pem)

    assert content == expected_content


def test_is_initialised_returns_true_if_directory_is_initialised(tmpdir):
    tmpdir.chdir()

    gimmecert.storage.initialise_storage(tmpdir.strpath)

    assert gimmecert.storage.is_initialised(tmpdir.strpath) is True


def test_is_initialised_returns_false_if_directory_is_not_initialised(tmpdir):
    tmpdir.chdir()

    assert gimmecert.storage.is_initialised(tmpdir.strpath) is False


@pytest.mark.parametrize("key_specification, private_key_instance_type", [
    [("rsa", 1024), cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey],
    [("ecdsa", cryptography.hazmat.primitives.asymmetric.ec.SECP192R1), cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey],
])
def test_read_ca_hierarchy_returns_list_of_ca_private_key_and_certificate_pairs_for_single_ca(tmpdir, key_specification, private_key_instance_type):
    tmpdir.chdir()
    gimmecert.commands.init(io.StringIO(), io.StringIO(), tmpdir.strpath, 'My Project', 1, key_specification)

    ca_hierarchy = gimmecert.storage.read_ca_hierarchy(tmpdir.join('.gimmecert', 'ca').strpath)

    assert len(ca_hierarchy) == 1

    private_key, certificate = ca_hierarchy[0]

    assert isinstance(private_key, private_key_instance_type)
    assert isinstance(certificate, cryptography.x509.Certificate)


@pytest.mark.parametrize("key_specification, private_key_instance_type", [
    [("rsa", 1024), cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey],
    [("ecdsa", cryptography.hazmat.primitives.asymmetric.ec.SECP192R1), cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey],
])
def test_read_private_key_returns_private_key(tmpdir, key_specification, private_key_instance_type):
    private_key_path = tmpdir.join('private.key.pem').strpath
    private_key = gimmecert.crypto.KeyGenerator(*key_specification)()
    gimmecert.storage.write_private_key(private_key, private_key_path)

    my_private_key = gimmecert.storage.read_private_key(private_key_path)

    assert isinstance(my_private_key, private_key_instance_type)
    assert my_private_key.public_key().public_numbers() == private_key.public_key().public_numbers()  # Can't compare private keys directly.


def test_read_certificate_returns_certificate(tmpdir):
    certificate_path = tmpdir.join('certificate.cert.pem').strpath
    dn = gimmecert.crypto.get_dn('mycertificate')
    not_before, not_after = gimmecert.crypto.get_validity_range()

    private_key = gimmecert.crypto.KeyGenerator('rsa', 2048)()
    certificate = gimmecert.crypto.issue_certificate(dn, dn, private_key, private_key.public_key(), not_before, not_after)
    gimmecert.storage.write_certificate(certificate, certificate_path)

    my_certificate = gimmecert.storage.read_certificate(certificate_path)

    assert isinstance(my_certificate, cryptography.x509.Certificate)
    assert my_certificate == certificate


@pytest.mark.parametrize("key_specification, private_key_instance_type", [
    [("rsa", 1024), cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateKey],
    [("ecdsa", cryptography.hazmat.primitives.asymmetric.ec.SECP192R1), cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey],
])
def test_read_ca_hierarchy_returns_list_of_ca_private_key_and_certificate_pairs_in_hierarchy_order_for_multiple_cas(tmpdir, key_specification,
                                                                                                                    private_key_instance_type):
    tmpdir.chdir()
    gimmecert.commands.init(io.StringIO(), io.StringIO(), tmpdir.strpath, 'My Project', 4, key_specification)

    ca_hierarchy = gimmecert.storage.read_ca_hierarchy(tmpdir.join('.gimmecert', 'ca').strpath)

    assert len(ca_hierarchy) == 4

    private_key_1, certificate_1 = ca_hierarchy[0]
    private_key_2, certificate_2 = ca_hierarchy[1]
    private_key_3, certificate_3 = ca_hierarchy[2]
    private_key_4, certificate_4 = ca_hierarchy[3]

    assert isinstance(private_key_1, private_key_instance_type)
    assert isinstance(certificate_1, cryptography.x509.Certificate)
    assert certificate_1.subject == gimmecert.crypto.get_dn("My Project Level 1 CA")
    assert isinstance(private_key_2, private_key_instance_type)
    assert isinstance(certificate_2, cryptography.x509.Certificate)
    assert certificate_2.subject == gimmecert.crypto.get_dn("My Project Level 2 CA")
    assert isinstance(private_key_3, private_key_instance_type)
    assert isinstance(certificate_3, cryptography.x509.Certificate)
    assert certificate_3.subject == gimmecert.crypto.get_dn("My Project Level 3 CA")
    assert isinstance(private_key_4, private_key_instance_type)
    assert isinstance(certificate_4, cryptography.x509.Certificate)
    assert certificate_4.subject == gimmecert.crypto.get_dn("My Project Level 4 CA")


def test_write_csr(tmpdir):
    csr_file = tmpdir.join('test.csr.pem')

    private_key = gimmecert.crypto.KeyGenerator('rsa', 2048)()
    csr = gimmecert.crypto.generate_csr('test', private_key)

    gimmecert.storage.write_csr(csr, csr_file.strpath)

    csr_file_content = csr_file.read()

    assert os.path.exists(csr_file.strpath)
    assert csr_file_content.startswith('-----BEGIN CERTIFICATE REQUEST-----')
    assert csr_file_content.endswith('-----END CERTIFICATE REQUEST-----\n')


def test_read_csr(tmpdir):
    csr_file = tmpdir.join('mycsr.csr.pem')

    private_key = gimmecert.crypto.KeyGenerator('rsa', 2048)()
    original_csr = gimmecert.crypto.generate_csr('mycsr', private_key)

    gimmecert.storage.write_csr(original_csr, csr_file.strpath)

    csr = gimmecert.storage.read_csr(csr_file.strpath)

    assert isinstance(csr, cryptography.x509.CertificateSigningRequest)
    assert csr == original_csr