Changeset - 07ff7da6d41f
[Not reviewed]
0 3 0
Branko Majic (branko) - 4 years ago 2020-06-11 15:14:24
branko@majic.rs
GC-37: Added support for showing key algorithms to the status command:

- Updated functional test for the status command to include a variety
of key algorithms and to test for their representation in the
output.
- Added unit tests.
- Updated the status command to extract key algorithm information from
the issued certificates and output the information.
3 files changed with 75 insertions and 37 deletions:
0 comments (0 inline, 0 general)
functional_tests/test_status.py
Show inline comments
 
@@ -76,13 +76,13 @@ def test_status_on_initialised_directory(tmpdir):
 

	
 
    run_command('gimmecert', 'init', '-d', '3', '-b', 'My Project')
 

	
 
    run_command('gimmecert', 'server', 'myserver1')
 
    run_command('gimmecert', 'server', 'myserver1', '-k', 'rsa:1024')
 
    run_command('gimmecert', 'server', 'myserver2', 'myservice.example.com', 'myotherservice.example.com')
 
    run_command("openssl", "req", "-new", "-newkey", "rsa:2048", "-nodes", "-keyout", "myserver3.key.pem",
 
                "-subj", "/CN=myserver3", "-out", "myserver3.csr.pem")
 
    run_command('gimmecert', 'server', '--csr', 'myserver3.csr.pem', 'myserver3')
 

	
 
    run_command('gimmecert', 'client', 'myclient1')
 
    run_command('gimmecert', 'client', 'myclient1', '-k', 'rsa:1024')
 
    run_command('gimmecert', 'client', 'myclient2')
 
    run_command("openssl", "req", "-new", "-newkey", "rsa:2048", "-nodes", "-keyout", "myclient3.key.pem",
 
                "-subj", "/CN=myclient3", "-out", "myclient3.csr.pem")
 
@@ -108,14 +108,18 @@ def test_status_on_initialised_directory(tmpdir):
 
    assert "Client certificates" in stdout
 

	
 
    # John first has a look at information about the CA
 
    # hierarchy. Hierarchy tree is presented using indentation. Each
 
    # CA is listed with its full subject DN, as well as not before and
 
    # not after dates. In addition, the final CA in chain is marked as
 
    # end entity issuing CA.
 
    # hierarchy. First thing he can see is information about the
 
    # default key algorithm in use. This is followed by the hierarchy
 
    # tree presented using indentation. Each CA is listed with its
 
    # full subject DN, as well as not before and not after dates. In
 
    # addition, the final CA in chain is marked as end entity issuing
 
    # CA.
 
    index_default_key_algorithm = stdout_lines.index("Default key algorithm: 2048-bit RSA")  # Should not raise
 
    index_ca_1 = stdout_lines.index("CN=My Project Level 1 CA")  # Should not raise
 
    index_ca_2 = stdout_lines.index("CN=My Project Level 2 CA")  # Should not raise
 
    index_ca_3 = stdout_lines.index("CN=My Project Level 3 CA [END ENTITY ISSUING CA]")  # Should not raise
 

	
 
    assert index_default_key_algorithm < index_ca_1
 
    assert index_ca_1 < index_ca_2
 
    assert index_ca_2 < index_ca_3
 

	
 
@@ -135,41 +139,49 @@ def test_status_on_initialised_directory(tmpdir):
 
    # John then has a look at server certificates. These are presented
 
    # in a list, and for each certificate is listed with subject DN,
 
    # not before, not after, and included DNS names. Information for
 
    # each server is followed by paths to private key and certificate.
 
    # each server is followed by key algorithm information, and paths
 
    # to private key and certificate.
 
    index_myserver1 = stdout_lines.index("CN=myserver1")  # Should not raise
 
    index_myserver2 = stdout_lines.index("CN=myserver2")  # Should not raise
 
    index_myserver3 = stdout_lines.index("CN=myserver3")  # Should not raise
 

	
 
    assert stdout_lines[index_myserver1+1].startswith("    Validity: ")
 
    assert stdout_lines[index_myserver1+2] == "    DNS: myserver1"
 
    assert stdout_lines[index_myserver1+3] == "    Private key: .gimmecert/server/myserver1.key.pem"
 
    assert stdout_lines[index_myserver1+4] == "    Certificate: .gimmecert/server/myserver1.cert.pem"
 
    assert stdout_lines[index_myserver1+3] == "    Key algorithm: 1024-bit RSA"
 
    assert stdout_lines[index_myserver1+4] == "    Private key: .gimmecert/server/myserver1.key.pem"
 
    assert stdout_lines[index_myserver1+5] == "    Certificate: .gimmecert/server/myserver1.cert.pem"
 

	
 
    assert stdout_lines[index_myserver2+1].startswith("    Validity: ")
 
    assert stdout_lines[index_myserver2+2] == "    DNS: myserver2, myservice.example.com, myotherservice.example.com"
 
    assert stdout_lines[index_myserver2+3] == "    Private key: .gimmecert/server/myserver2.key.pem"
 
    assert stdout_lines[index_myserver2+4] == "    Certificate: .gimmecert/server/myserver2.cert.pem"
 
    assert stdout_lines[index_myserver2+3] == "    Key algorithm: 2048-bit RSA"
 
    assert stdout_lines[index_myserver2+4] == "    Private key: .gimmecert/server/myserver2.key.pem"
 
    assert stdout_lines[index_myserver2+5] == "    Certificate: .gimmecert/server/myserver2.cert.pem"
 

	
 
    assert stdout_lines[index_myserver3+1].startswith("    Validity: ")
 
    assert stdout_lines[index_myserver3+2] == "    DNS: myserver3"
 
    assert stdout_lines[index_myserver3+3] == "    CSR: .gimmecert/server/myserver3.csr.pem"
 
    assert stdout_lines[index_myserver3+4] == "    Certificate: .gimmecert/server/myserver3.cert.pem"
 
    assert stdout_lines[index_myserver3+3] == "    Key algorithm: 2048-bit RSA"
 
    assert stdout_lines[index_myserver3+4] == "    CSR: .gimmecert/server/myserver3.csr.pem"
 
    assert stdout_lines[index_myserver3+5] == "    Certificate: .gimmecert/server/myserver3.cert.pem"
 

	
 
    # For client certificates, John can see that for each certificate
 
    # he can see its subject DN and validity. Information for each
 
    # server is followed by paths to private key and certificate.
 
    # client is followed by key algorithm and paths to private key and
 
    # certificate.
 
    index_myclient1 = stdout_lines.index("CN=myclient1")  # Should not raise
 
    index_myclient2 = stdout_lines.index("CN=myclient2")  # Should not raise
 
    index_myclient3 = stdout_lines.index("CN=myclient3")  # Should not raise
 

	
 
    assert stdout_lines[index_myclient1+1].startswith("    Validity: ")
 
    assert stdout_lines[index_myclient1+2] == "    Private key: .gimmecert/client/myclient1.key.pem"
 
    assert stdout_lines[index_myclient1+3] == "    Certificate: .gimmecert/client/myclient1.cert.pem"
 
    assert stdout_lines[index_myclient1+2] == "    Key algorithm: 1024-bit RSA"
 
    assert stdout_lines[index_myclient1+3] == "    Private key: .gimmecert/client/myclient1.key.pem"
 
    assert stdout_lines[index_myclient1+4] == "    Certificate: .gimmecert/client/myclient1.cert.pem"
 

	
 
    assert stdout_lines[index_myclient2+1].startswith("    Validity: ")
 
    assert stdout_lines[index_myclient2+2] == "    Private key: .gimmecert/client/myclient2.key.pem"
 
    assert stdout_lines[index_myclient2+3] == "    Certificate: .gimmecert/client/myclient2.cert.pem"
 
    assert stdout_lines[index_myclient2+2] == "    Key algorithm: 2048-bit RSA"
 
    assert stdout_lines[index_myclient2+3] == "    Private key: .gimmecert/client/myclient2.key.pem"
 
    assert stdout_lines[index_myclient2+4] == "    Certificate: .gimmecert/client/myclient2.cert.pem"
 

	
 
    assert stdout_lines[index_myclient3+1].startswith("    Validity: ")
 
    assert stdout_lines[index_myclient3+2] == "    CSR: .gimmecert/client/myclient3.csr.pem"
 
    assert stdout_lines[index_myclient3+3] == "    Certificate: .gimmecert/client/myclient3.cert.pem"
 
    assert stdout_lines[index_myclient3+2] == "    Key algorithm: 2048-bit RSA"
 
    assert stdout_lines[index_myclient3+3] == "    CSR: .gimmecert/client/myclient3.csr.pem"
 
    assert stdout_lines[index_myclient3+4] == "    Certificate: .gimmecert/client/myclient3.cert.pem"
gimmecert/commands.py
Show inline comments
 
@@ -542,6 +542,11 @@ def status(stdout, stderr, project_directory):
 

	
 
    ca_hierarchy = gimmecert.storage.read_ca_hierarchy(os.path.join(project_directory, '.gimmecert', 'ca'))
 

	
 
    # Derive key specification from the issuing CA certificate.
 
    key_algorithm = gimmecert.crypto.KeyGenerator('rsa', ca_hierarchy[-1][1].public_key().key_size)
 
    print("", file=stdout)  # Separator
 
    print("Default key algorithm: %s" % key_algorithm, file=stdout)
 

	
 
    for i, (_, certificate) in enumerate(ca_hierarchy, 1):
 
        # Separator.
 
        print("", file=stdout)
 
@@ -580,6 +585,7 @@ def status(stdout, stderr, project_directory):
 
            certificate = gimmecert.storage.read_certificate(os.path.join(project_directory, '.gimmecert', 'server', certificate_file))
 
            private_key_path = os.path.join(project_directory, '.gimmecert', 'server', certificate_file.replace('.cert.pem', '.key.pem'))
 
            csr_path = os.path.join(project_directory, '.gimmecert', 'server', certificate_file.replace('.cert.pem', '.csr.pem'))
 
            key_algorithm = str(gimmecert.crypto.KeyGenerator("rsa", certificate.public_key().key_size))
 

	
 
            # Separator.
 
            print("", file=stdout)
 
@@ -597,6 +603,7 @@ def status(stdout, stderr, project_directory):
 
                                          validity_status), file=stdout)
 
            print("    DNS: %s" % ", ".join(gimmecert.utils.get_dns_names(certificate)), file=stdout)
 

	
 
            print("    Key algorithm: %s" % key_algorithm, file=stdout)
 
            if os.path.exists(private_key_path):
 
                print("    Private key: .gimmecert/server/%s" % certificate_file.replace('.cert.pem', '.key.pem'), file=stdout)
 
            elif os.path.exists(csr_path):
 
@@ -620,6 +627,7 @@ def status(stdout, stderr, project_directory):
 
            certificate = gimmecert.storage.read_certificate(os.path.join(project_directory, '.gimmecert', 'client', certificate_file))
 
            private_key_path = os.path.join(project_directory, '.gimmecert', 'client', certificate_file.replace('.cert.pem', '.key.pem'))
 
            csr_path = os.path.join(project_directory, '.gimmecert', 'client', certificate_file.replace('.cert.pem', '.csr.pem'))
 
            key_algorithm = str(gimmecert.crypto.KeyGenerator("rsa", certificate.public_key().key_size))
 

	
 
            # Separator.
 
            print("", file=stdout)
 
@@ -636,6 +644,7 @@ def status(stdout, stderr, project_directory):
 
                                                                            certificate.not_valid_after),
 
                                          validity_status), file=stdout)
 

	
 
            print("    Key algorithm: %s" % key_algorithm, file=stdout)
 
            if os.path.exists(private_key_path):
 
                print("    Private key: .gimmecert/client/%s" % certificate_file.replace('.cert.pem', '.key.pem'), file=stdout)
 
            elif os.path.exists(csr_path):
tests/test_commands.py
Show inline comments
 
@@ -626,12 +626,16 @@ def test_status_reports_uninitialised_directory(tmpdir):
 
    assert "CA hierarchy has not been initialised in current directory." in stdout
 

	
 

	
 
def test_status_reports_ca_hierarchy_information(tmpdir):
 
@pytest.mark.parametrize('ca_key_specification,ca_key_representation', [
 
    (('rsa', 1024), '1024-bit RSA'),
 
    (('rsa', 2048), '2048-bit RSA'),
 
])
 
def test_status_reports_ca_hierarchy_information(tmpdir, ca_key_specification, ca_key_representation):
 
    stdout_stream = io.StringIO()
 
    stderr_stream = io.StringIO()
 

	
 
    with freeze_time('2018-01-01 00:15:00'):
 
        gimmecert.commands.init(io.StringIO(), io.StringIO(), tmpdir.strpath, tmpdir.basename, 3, ("rsa", 2048))
 
        gimmecert.commands.init(io.StringIO(), io.StringIO(), tmpdir.strpath, tmpdir.basename, 3, ca_key_specification)
 

	
 
    with freeze_time('2018-06-01 00:15:00'):
 
        status_code = gimmecert.commands.status(stdout_stream, stderr_stream, tmpdir.strpath)
 
@@ -644,12 +648,13 @@ def test_status_reports_ca_hierarchy_information(tmpdir):
 
    assert stderr == ""
 
    assert "CA hierarchy\n------------\n" in stdout
 

	
 
    index_ca_key_algorithm = stdout_lines.index("Default key algorithm: %s" % ca_key_representation)  # Should not raise
 
    index_ca_1 = stdout_lines.index("CN=%s Level 1 CA" % tmpdir.basename)  # Should not raise
 
    index_ca_2 = stdout_lines.index("CN=%s Level 2 CA" % tmpdir.basename)  # Should not raise
 
    index_ca_3 = stdout_lines.index("CN=%s Level 3 CA [END ENTITY ISSUING CA]" % tmpdir.basename)  # Should not raise
 
    full_chain = stdout_lines.index("Full certificate chain: .gimmecert/ca/chain-full.cert.pem")  # Shold not raise
 

	
 
    assert full_chain > index_ca_3 > index_ca_2 > index_ca_1, "Output ordering for CA section is wrong:\n%s" % stdout
 
    assert full_chain > index_ca_3 > index_ca_2 > index_ca_1 > index_ca_key_algorithm, "Output ordering for CA section is wrong:\n%s" % stdout
 

	
 
    ca_1_validity = stdout_lines[index_ca_1 + 1]
 
    ca_1_certificate_path = stdout_lines[index_ca_1 + 2]
 
@@ -683,7 +688,7 @@ def test_status_reports_server_certificate_information(tmpdir):
 
        gimmecert.commands.init(io.StringIO(), io.StringIO(), tmpdir.strpath, tmpdir.basename, 3, ("rsa", 2048))
 

	
 
    with freeze_time('2018-02-01 00:15:00'):
 
        gimmecert.commands.server(io.StringIO(), io.StringIO(), tmpdir.strpath, 'myserver1', None, None, None)
 
        gimmecert.commands.server(io.StringIO(), io.StringIO(), tmpdir.strpath, 'myserver1', None, None, ("rsa", 1024))
 

	
 
    with freeze_time('2018-03-01 00:15:00'):
 
        gimmecert.commands.server(io.StringIO(), io.StringIO(), tmpdir.strpath, 'myserver2', ['myservice1.example.com', 'myservice2.example.com'], None, None)
 
@@ -709,31 +714,37 @@ def test_status_reports_server_certificate_information(tmpdir):
 

	
 
    myserver1_validity = stdout_lines[index_myserver1 + 1]
 
    myserver1_dns = stdout_lines[index_myserver1 + 2]
 
    myserver1_private_key_path = stdout_lines[index_myserver1 + 3]
 
    myserver1_certificate_path = stdout_lines[index_myserver1 + 4]
 
    myserver1_key_algorithm = stdout_lines[index_myserver1 + 3]
 
    myserver1_private_key_path = stdout_lines[index_myserver1 + 4]
 
    myserver1_certificate_path = stdout_lines[index_myserver1 + 5]
 

	
 
    myserver2_validity = stdout_lines[index_myserver2 + 1]
 
    myserver2_dns = stdout_lines[index_myserver2 + 2]
 
    myserver2_private_key_path = stdout_lines[index_myserver2 + 3]
 
    myserver2_certificate_path = stdout_lines[index_myserver2 + 4]
 
    myserver2_key_algorithm = stdout_lines[index_myserver2 + 3]
 
    myserver2_private_key_path = stdout_lines[index_myserver2 + 4]
 
    myserver2_certificate_path = stdout_lines[index_myserver2 + 5]
 

	
 
    myserver3_validity = stdout_lines[index_myserver3 + 1]
 
    myserver3_dns = stdout_lines[index_myserver3 + 2]
 
    myserver3_csr_path = stdout_lines[index_myserver3 + 3]
 
    myserver3_certificate_path = stdout_lines[index_myserver3 + 4]
 
    myserver3_key_algorithm = stdout_lines[index_myserver3 + 3]
 
    myserver3_csr_path = stdout_lines[index_myserver3 + 4]
 
    myserver3_certificate_path = stdout_lines[index_myserver3 + 5]
 

	
 
    assert myserver1_validity == "    Validity: 2018-02-01 00:00:00 UTC - 2019-01-01 00:15:00 UTC"
 
    assert myserver1_dns == "    DNS: myserver1"
 
    assert myserver1_key_algorithm == "    Key algorithm: 1024-bit RSA"
 
    assert myserver1_private_key_path == "    Private key: .gimmecert/server/myserver1.key.pem"
 
    assert myserver1_certificate_path == "    Certificate: .gimmecert/server/myserver1.cert.pem"
 

	
 
    assert myserver2_validity == "    Validity: 2018-03-01 00:00:00 UTC - 2019-01-01 00:15:00 UTC"
 
    assert myserver2_dns == "    DNS: myserver2, myservice1.example.com, myservice2.example.com"
 
    assert myserver2_key_algorithm == "    Key algorithm: 2048-bit RSA"
 
    assert myserver2_private_key_path == "    Private key: .gimmecert/server/myserver2.key.pem"
 
    assert myserver2_certificate_path == "    Certificate: .gimmecert/server/myserver2.cert.pem"
 

	
 
    assert myserver3_validity == "    Validity: 2018-04-01 00:00:00 UTC - 2019-01-01 00:15:00 UTC"
 
    assert myserver3_dns == "    DNS: myserver3"
 
    assert myserver3_key_algorithm == "    Key algorithm: 2048-bit RSA"
 
    assert myserver3_csr_path == "    CSR: .gimmecert/server/myserver3.csr.pem"
 
    assert myserver3_certificate_path == "    Certificate: .gimmecert/server/myserver3.cert.pem"
 

	
 
@@ -751,7 +762,7 @@ def test_status_reports_client_certificate_information(tmpdir):
 
        gimmecert.commands.init(io.StringIO(), io.StringIO(), tmpdir.strpath, tmpdir.basename, 3, ("rsa", 2048))
 

	
 
    with freeze_time('2018-02-01 00:15:00'):
 
        gimmecert.commands.client(io.StringIO(), io.StringIO(), tmpdir.strpath, 'myclient1', None, None)
 
        gimmecert.commands.client(io.StringIO(), io.StringIO(), tmpdir.strpath, 'myclient1', None, ("rsa", 1024))
 

	
 
    with freeze_time('2018-03-01 00:15:00'):
 
        gimmecert.commands.client(io.StringIO(), io.StringIO(), tmpdir.strpath, 'myclient2', None, None)
 
@@ -776,26 +787,32 @@ def test_status_reports_client_certificate_information(tmpdir):
 
    index_myclient3 = stdout_lines.index("CN=myclient3")  # Should not raise
 

	
 
    myclient1_validity = stdout_lines[index_myclient1 + 1]
 
    myclient1_private_key_path = stdout_lines[index_myclient1 + 2]
 
    myclient1_certificate_path = stdout_lines[index_myclient1 + 3]
 
    myclient1_key_algorithm = stdout_lines[index_myclient1 + 2]
 
    myclient1_private_key_path = stdout_lines[index_myclient1 + 3]
 
    myclient1_certificate_path = stdout_lines[index_myclient1 + 4]
 

	
 
    myclient2_validity = stdout_lines[index_myclient2 + 1]
 
    myclient2_private_key_path = stdout_lines[index_myclient2 + 2]
 
    myclient2_certificate_path = stdout_lines[index_myclient2 + 3]
 
    myclient2_key_algorithm = stdout_lines[index_myclient2 + 2]
 
    myclient2_private_key_path = stdout_lines[index_myclient2 + 3]
 
    myclient2_certificate_path = stdout_lines[index_myclient2 + 4]
 

	
 
    myclient3_validity = stdout_lines[index_myclient3 + 1]
 
    myclient3_csr_path = stdout_lines[index_myclient3 + 2]
 
    myclient3_certificate_path = stdout_lines[index_myclient3 + 3]
 
    myclient3_key_algorithm = stdout_lines[index_myclient3 + 2]
 
    myclient3_csr_path = stdout_lines[index_myclient3 + 3]
 
    myclient3_certificate_path = stdout_lines[index_myclient3 + 4]
 

	
 
    assert myclient1_validity == "    Validity: 2018-02-01 00:00:00 UTC - 2019-01-01 00:15:00 UTC"
 
    assert myclient1_key_algorithm == "    Key algorithm: 1024-bit RSA"
 
    assert myclient1_private_key_path == "    Private key: .gimmecert/client/myclient1.key.pem"
 
    assert myclient1_certificate_path == "    Certificate: .gimmecert/client/myclient1.cert.pem"
 

	
 
    assert myclient2_validity == "    Validity: 2018-03-01 00:00:00 UTC - 2019-01-01 00:15:00 UTC"
 
    assert myclient2_key_algorithm == "    Key algorithm: 2048-bit RSA"
 
    assert myclient2_private_key_path == "    Private key: .gimmecert/client/myclient2.key.pem"
 
    assert myclient2_certificate_path == "    Certificate: .gimmecert/client/myclient2.cert.pem"
 

	
 
    assert myclient3_validity == "    Validity: 2018-04-01 00:00:00 UTC - 2019-01-01 00:15:00 UTC"
 
    assert myclient3_key_algorithm == "    Key algorithm: 2048-bit RSA"
 
    assert myclient3_csr_path == "    CSR: .gimmecert/client/myclient3.csr.pem"
 
    assert myclient3_certificate_path == "    Certificate: .gimmecert/client/myclient3.cert.pem"
 

	
0 comments (0 inline, 0 general)