diff --git a/functional_tests/test_csr.py b/functional_tests/test_csr.py index 61d9f0a2d8ab18f8d96d1814d9b114893f6d2626..36107adda4c6a675c8a49d6657d9ed637b6e8886 100644 --- a/functional_tests/test_csr.py +++ b/functional_tests/test_csr.py @@ -655,3 +655,268 @@ def test_renew_command_accepts_csr_from_stdin(tmpdir): # To his delight, they are identical. assert server_certificate_public_key == server_csr_public_key assert client_certificate_public_key == client_csr_public_key + + +def test_client_certificate_issuance_by_passing_csr_as_file_ecdsa(tmpdir): + # John is working on a project where he has already generated + # client ECDSA private key. + tmpdir.chdir() + run_command("openssl", "ecparam", "-genkey", "-noout", "-out", "myclient1.key.pem", "-name", "secp256r1") + + # However, he still needs to have a CA as a trustpoint, so he goes + # ahead and initialises Gimmecert for this purpose. + run_command("gimmecert", "init") + + # Before issuing the certificate, he goes ahead and generates a + # CSR for the client private key. + run_command("openssl", "req", "-new", "-key", "myclient1.key.pem", "-subj", "/CN=myclient1", "-out", "myclient1.csr.pem") + + # John issues client certificate using CSR. + stdout, stderr, exit_code = run_command("gimmecert", "client", "--csr", "myclient1.csr.pem", "myclient1") + + # The operation is successful, and he is presented with + # information about generated artefacts. + assert exit_code == 0 + assert stderr == "" + assert ".gimmecert/client/myclient1.cert.pem" in stdout + assert ".gimmecert/client/myclient1.csr.pem" in stdout + + # John also notices that there is no mention of a private key. + assert ".gimmecert/client/myclient1.key.pem" not in stdout + + # John notices that the content of stored CSR is identical to the + # one he provided. + original_csr = tmpdir.join("myclient1.csr.pem").read() + stored_csr = tmpdir.join(".gimmecert", "client", "myclient1.csr.pem").read() + assert original_csr == stored_csr + + # John then quickly has a look at the public key associated with + # the private key, and public key stored in certificate. + public_key, _, _ = run_command("openssl", "ec", "-pubout", "-in", "myclient1.key.pem") + certificate_public_key, _, _ = run_command("openssl", "x509", "-pubkey", "-noout", "-in", ".gimmecert/client/myclient1.cert.pem") + + # To his delight, they are identical. + assert certificate_public_key == public_key + + +def test_server_certificate_issuance_by_passing_csr_as_file_ecdsa(tmpdir): + # John is working on a project where he has already generated + # server ECDSA private key. + tmpdir.chdir() + run_command("openssl", "ecparam", "-genkey", "-noout", "-out", "myserver1.key.pem", "-name", "secp256r1") + + # However, he still needs to have a CA as a trustpoint, so he goes + # ahead and initialises Gimmecert for this purpose. + run_command("gimmecert", "init") + + # Before issuing the certificate, he goes ahead and generates a + # CSR for the server private key + run_command("openssl", "req", "-new", "-key", "myserver1.key.pem", "-subj", "/CN=myserver1", "-out", "myserver1.csr.pem") + + # John issues server certificate using CSR. + stdout, stderr, exit_code = run_command("gimmecert", "server", "--csr", "myserver1.csr.pem", "myserver1") + + # The operation is successful, and he is presented with + # information about generated artefacts. + assert exit_code == 0 + assert stderr == "" + assert ".gimmecert/server/myserver1.cert.pem" in stdout + assert ".gimmecert/server/myserver1.csr.pem" in stdout + + # John also notices that there is no mention of a private key. + assert ".gimmecert/server/myserver1.key.pem" not in stdout + + # John notices that the content of stored CSR is identical to the + # one he provided. + original_csr = tmpdir.join("myserver1.csr.pem").read() + stored_csr = tmpdir.join(".gimmecert", "server", "myserver1.csr.pem").read() + assert original_csr == stored_csr + + # John then quickly has a look at the public key associated with + # the private key, and public key stored in certificate. + public_key, _, _ = run_command("openssl", "ec", "-pubout", "-in", "myserver1.key.pem") + certificate_public_key, _, _ = run_command("openssl", "x509", "-pubkey", "-noout", "-in", ".gimmecert/server/myserver1.cert.pem") + + # To his delight, they are identical. + assert certificate_public_key == public_key + + +def test_renew_certificate_originally_issued_with_csr_ecdsa(tmpdir): + # In one of his past projects, John has initialised CA hierarchy + # and issued server and client certificate using CSR. + tmpdir.chdir() + + run_command("openssl", "ecparam", "-genkey", "-noout", "-out", "myserver.key.pem", "-name", "secp256r1") + run_command("openssl", "req", "-new", "-key", "myserver.key.pem", "-subj", "/CN=myserver", "-out", "mycustomserver.csr.pem") + + run_command("openssl", "ecparam", "-genkey", "-noout", "-out", "myclient.key.pem", "-name", "secp256r1") + run_command("openssl", "req", "-new", "-key", "myclient.key.pem", "-subj", "/CN=myserver", "-out", "mycustomclient.csr.pem") + + run_command("gimmecert", "init") + run_command("gimmecert", "server", "--csr", "mycustomserver.csr.pem", "myserver") + run_command("gimmecert", "client", "--csr", "mycustomclient.csr.pem", "myclient") + + # After a while John comes back to the project and has a look at + # generated artefacts. + server_old_stored_csr = tmpdir.join(".gimmecert", "server", "myserver.csr.pem").read() + server_old_certificate = tmpdir.join(".gimmecert", "server", "myserver.cert.pem").read() + + client_old_stored_csr = tmpdir.join(".gimmecert", "client", "myclient.csr.pem").read() + client_old_certificate = tmpdir.join(".gimmecert", "client", "myclient.cert.pem").read() + + # He decides to renew the certificates to update their + # validity. First he runs renewal for the server certificate. + stdout, stderr, exit_code = run_command("gimmecert", "renew", "server", "myserver") + + # No errors are shown, and John is informed about generated + # artefacts. He notices that there is not mention of private key. + assert exit_code == 0 + assert stderr == "" + assert "Renewed certificate for server myserver." in stdout + assert ".gimmecert/server/myserver.csr.pem" in stdout + assert ".gimmecert/server/myserver.cert.pem" in stdout + assert ".gimmecert/server/myserver.key.pem" not in stdout + + # John has a look at generated artefacts. + server_new_stored_csr = tmpdir.join(".gimmecert", "server", "myserver.csr.pem").read() + server_new_certificate = tmpdir.join(".gimmecert", "server", "myserver.cert.pem").read() + server_csr_public_key, _, _ = run_command("openssl", "req", "-noout", "-pubkey", "-in", ".gimmecert/server/myserver.csr.pem") + server_certificate_public_key, _, _ = run_command("openssl", "x509", "-noout", "-pubkey", "-in", ".gimmecert/server/myserver.cert.pem") + + # John notices that the reported CSR has remained unchanged, that + # the certificate seems to have been updated, and that the public + # key is the same in CSR and certificate. + assert server_new_stored_csr == server_old_stored_csr + assert server_new_certificate != server_old_certificate + assert server_csr_public_key == server_certificate_public_key + + # John renews the client certificate. + stdout, stderr, exit_code = run_command("gimmecert", "renew", "client", "myclient") + + # No errors are shown, and John is informed about generated + # artefacts. He notices that there is not mention of private key. + assert exit_code == 0 + assert stderr == "" + assert "Renewed certificate for client myclient." in stdout + assert ".gimmecert/client/myclient.csr.pem" in stdout + assert ".gimmecert/client/myclient.cert.pem" in stdout + assert ".gimmecert/client/myclient.key.pem" not in stdout + + # John has a look at generated artefacts. + client_new_stored_csr = tmpdir.join(".gimmecert", "client", "myclient.csr.pem").read() + client_new_certificate = tmpdir.join(".gimmecert", "client", "myclient.cert.pem").read() + client_csr_public_key, _, _ = run_command("openssl", "req", "-noout", "-pubkey", "-in", ".gimmecert/client/myclient.csr.pem") + client_certificate_public_key, _, _ = run_command("openssl", "x509", "-noout", "-pubkey", "-in", ".gimmecert/client/myclient.cert.pem") + + # John notices that the reported CSR has remained unchanged, that + # the certificate seems to have been updated, and that the public + # key is the same in CSR and certificate. + assert client_new_stored_csr == client_old_stored_csr + assert client_new_certificate != client_old_certificate + assert client_csr_public_key == client_certificate_public_key + + +def test_renew_certificate_originally_issued_with_private_key_using_csr_ecdsa(tmpdir): + # John has an existing project where he has generated a server and + # client private key with corresponding CSR. + tmpdir.chdir() + + run_command("openssl", "ecparam", "-genkey", "-noout", "-out", "myserver.key.pem", "-name", "secp256r1") + run_command("openssl", "req", "-new", "-key", "myserver.key.pem", "-subj", "/CN=myserver", "-out", "mycustomserver.csr.pem") + + run_command("openssl", "ecparam", "-genkey", "-noout", "-out", "myclient.key.pem", "-name", "secp256r1") + run_command("openssl", "req", "-new", "-key", "myclient.key.pem", "-subj", "/CN=myserver", "-out", "mycustomclient.csr.pem") + + # He wants to grab some certificates for those, so he goes ahead + # and initialised the CA hierarchy. + tmpdir.chdir() + run_command("gimmecert", "init") + + # He proceeds to issue a server and client certificate. + run_command("gimmecert", "server", "myserver") + run_command("gimmecert", "client", "myclient") + + # Very quickly John realises that he has mistakenly forgotten to + # pass-in the relevant CSRs, and that Gimmecert has generated + # private keys locally and issued certificates for them. + assert tmpdir.join('.gimmecert', 'server', 'myserver.key.pem').check(file=1) + assert not tmpdir.join('.gimmecert', 'server', 'myserver.csr.pem').check(file=1) + assert tmpdir.join('.gimmecert', 'client', 'myclient.key.pem').check(file=1) + assert not tmpdir.join('.gimmecert', 'client', 'myclient.csr.pem').check(file=1) + + # John has a look at generated artefacts. + server_old_certificate = tmpdir.join(".gimmecert", "server", "myserver.cert.pem").read() + server_old_certificate_public_key, _, _ = run_command("openssl", "x509", "-noout", "-pubkey", "-in", ".gimmecert/server/myserver.cert.pem") + + client_old_certificate = tmpdir.join(".gimmecert", "client", "myclient.cert.pem").read() + client_old_certificate_public_key, _, _ = run_command("openssl", "x509", "-noout", "-pubkey", "-in", ".gimmecert/client/myclient.cert.pem") + + # He also has a look at the CSRs he generated for both server and + # client. + server_csr_public_key, _, _ = run_command("openssl", "req", "-noout", "-pubkey", "-in", "mycustomserver.csr.pem") + server_csr = tmpdir.join("mycustomserver.csr.pem").read() + + client_csr_public_key, _, _ = run_command("openssl", "req", "-noout", "-pubkey", "-in", "mycustomclient.csr.pem") + client_csr = tmpdir.join("mycustomclient.csr.pem").read() + + # He goes ahead and renews the server certificate first, + # passing-in the CSR this time around. + stdout, stderr, exit_code = run_command("gimmecert", "renew", "--csr", "mycustomserver.csr.pem", "server", "myserver") + + # No errors are shown, and John is informed about generated + # artefacts, and that the private key has been removed and + # replaced with the CSR. + assert exit_code == 0 + assert stderr == "" + assert "Renewed certificate for server myserver." in stdout + assert "Private key used for issuance of previous certificate has been removed, and replaced with the passed-in CSR." in stdout + assert ".gimmecert/server/myserver.csr.pem" in stdout + assert ".gimmecert/server/myserver.cert.pem" in stdout + assert ".gimmecert/server/myserver.key.pem" not in stdout + + # John has a look at generated artefacts. + server_stored_csr = tmpdir.join(".gimmecert", "server", "myserver.csr.pem").read() + server_stored_csr_public_key, _, _ = run_command("openssl", "req", "-noout", "-pubkey", "-in", ".gimmecert/server/myserver.csr.pem") + + server_new_certificate = tmpdir.join(".gimmecert", "server", "myserver.cert.pem").read() + server_new_certificate_public_key, _, _ = run_command("openssl", "x509", "-noout", "-pubkey", "-in", ".gimmecert/server/myserver.cert.pem") + + # John notices that, for start, the private key has indeed been + # removed from the filesystem, that the content of the certificate + # has changed, that the passed-in CSR has been stored, and that + # public key from the certificate matches the public key in CSR. + assert not tmpdir.join(".gimmecert", "server", "myserver.key.pem").check() + assert server_new_certificate != server_old_certificate + assert server_stored_csr == server_csr + assert server_new_certificate_public_key == server_csr_public_key + + # John renews the client certificate afterwards, passing-in the + # CSR this time around. + stdout, stderr, exit_code = run_command("gimmecert", "renew", "--csr", "mycustomclient.csr.pem", "client", "myclient") + + # No errors are shown, and John is informed about generated + # artefacts, and that the private key has been removed and + # replaced with the CSR. + assert exit_code == 0 + assert stderr == "" + assert "Renewed certificate for client myclient." in stdout + assert "Private key used for issuance of previous certificate has been removed, and replaced with the passed-in CSR." in stdout + assert ".gimmecert/client/myclient.csr.pem" in stdout + assert ".gimmecert/client/myclient.cert.pem" in stdout + assert ".gimmecert/client/myclient.key.pem" not in stdout + + # John has a look at generated artefacts. + client_stored_csr = tmpdir.join(".gimmecert", "client", "myclient.csr.pem").read() + client_stored_csr_public_key, _, _ = run_command("openssl", "req", "-noout", "-pubkey", "-in", ".gimmecert/client/myclient.csr.pem") + + client_new_certificate = tmpdir.join(".gimmecert", "client", "myclient.cert.pem").read() + client_new_certificate_public_key, _, _ = run_command("openssl", "x509", "-noout", "-pubkey", "-in", ".gimmecert/client/myclient.cert.pem") + + # John notices that, for start, the private key has indeed been + # removed from the filesystem, that the content of the certificate + # has changed, that the passed-in CSR has been stored, and that + # public key from the certificate matches the public key in CSR. + assert not tmpdir.join(".gimmecert", "client", "myclient.key.pem").check() + assert client_new_certificate != client_old_certificate + assert client_stored_csr == client_csr + assert client_new_certificate_public_key == client_csr_public_key