diff --git a/.github/workflows/qe-tests.yml b/.github/workflows/qe-tests.yml index 58cfda11768..1806530c0f3 100644 --- a/.github/workflows/qe-tests.yml +++ b/.github/workflows/qe-tests.yml @@ -106,6 +106,15 @@ jobs: - name: Set up PKI deployment by running playbook on "controller" run: vagrant provision controller + - name: Run CA related tests + run: | + vagrant ssh controller -c \ + 'pytest --ansible-host-pattern master \ + --ansible-inventory /vagrant/inventory \ + --ansible-module-path /vagrant/tests/dogtag/pytest-ansible/common-modules/ \ + /vagrant/tests/dogtag/pytest-ansible/pytest/sanity/test_role_users.py \ + --junit-xml pki_cert_junit.xml -qsvvv' + - name: Setup tmate session if: failure() uses: mxschmitt/action-tmate@v2 diff --git a/tests/dogtag/pytest-ansible/.gitlab-ci.yml b/tests/dogtag/pytest-ansible/.gitlab-ci.yml index 386f4175441..63ade94ea0b 100644 --- a/tests/dogtag/pytest-ansible/.gitlab-ci.yml +++ b/tests/dogtag/pytest-ansible/.gitlab-ci.yml @@ -227,6 +227,13 @@ ca-topo-00-bugzilla-cp: - ansible-playbook -u fedora --become -i $HOSTFILE $PYTEST_DIR/installation/main.yml --extra-vars "topology=topology-00" -vv | sed 's/\\n/\n/g' - py.test --html=$CI_PROJECT_DIR/${CI_JOB_NAME}_html_report.html --self-contained-html --ansible-user=fedora --ansible-become --ansible-inventory $HOSTFILE --ansible-host-pattern master $PYTEST_DIR/pytest/ca/bugzilla/test_bug_1656772_man_pkispawn_having_reference_to_setup-ds.py -q -s --junitxml ${CI_JOB_NAME}_junit.xml | sed 's/\\n/\n/g' +topo-02-ca-bugzillas-gs: + <<: *job_definition + stage: tier2-discrete + script: + - ansible-playbook -u fedora --become -i $HOSTFILE $PYTEST_DIR/installation/main.yml --extra-vars "topology=topology-02 tls_ldap=true" -vv | sed 's/\\n/\n/g' + - py.test --html=$CI_PROJECT_DIR/${CI_JOB_NAME}_html_report.html --self-contained-html --ansible-user=fedora --ansible-become --ansible-inventory $HOSTFILE --ansible-host-pattern master $PYTEST_DIR/pytest/sanity/test_role_users.py -q -s --junitxml $CI_PROJECT_DIR/role_user_creation_junit.xml -qsvv + - py.test --html=$CI_PROJECT_DIR/${CI_JOB_NAME}_html_report.html --self-contained-html --ansible-user=fedora --ansible-become --ansible-inventory $HOSTFILE --ansible-host-pattern master $PYTEST_DIR/pytest/ca/bugzilla/test_bug_1787115_Copy_SKI_from_CSR_to_Certificate_Signed.py -q -s --junitxml $CI_PROJECT_DIR/bz_1787115.xml -qsvv diff --git a/tests/dogtag/pytest-ansible/pki/testlib/common/profile.py b/tests/dogtag/pytest-ansible/pki/testlib/common/profile.py index 653bc778958..2344a4e6df3 100644 --- a/tests/dogtag/pytest-ansible/pki/testlib/common/profile.py +++ b/tests/dogtag/pytest-ansible/pki/testlib/common/profile.py @@ -78,7 +78,7 @@ def get_element_policy_value(cls, policy_set_element, javaclass): classId = key[0].get('classId') mydict[classId] = PolicyValues - if mydict.has_key(javaclass): + if javaclass in mydict: value_Id = mydict[javaclass] Policy_Value = policy_set_element.find( './value[@id=' + "\"" + str(value_Id) + "\"" + "]") @@ -1546,7 +1546,7 @@ def add_policies(self, root_element, policy_set_element, profile_input): profile_input['Subject_Pattern'], profile_input['subjectNameDefault']) - if not (profile_input.has_key('PathLength') and profile_input.has_key('isCA')): + if not (('PathLength' in profile_input) and ('isCA' in profile_input)): Policy.no_default(root_element, policy_set_element, profile_input['NotBefore'], @@ -1558,7 +1558,7 @@ def add_policies(self, root_element, policy_set_element, profile_input): Policy.extended_key_usage_extension_default( root_element, policy_set_element) - if profile_input.has_key('ExtOID'): + if 'ExtOID' in profile_input: if profile_input['ExtOID'] in '2.5.29.17': Policy.user_supplied_extension_default(root_element, policy_set_element, profile_input['ExtOID'], profile_input['Subject_Pattern']) @@ -1575,15 +1575,15 @@ def add_policies(self, root_element, policy_set_element, profile_input): Policy.key_usage_default( root_element, policy_set_element, profile_input['Key_List']) Policy.signing_alg(root_element, policy_set_element) - if profile_input.has_key('Generic_extensions'): + if 'Generic_extensions' in profile_input: Policy.generic_extension(root_element, policy_set_element) - if profile_input.has_key('NetscapeExtensions'): + if 'NetscapeExtensions' in profile_input: Policy.netscape_certificate_type_extension_default(root_element, policy_set_element, profile_input['NetscapeExtensions']) - if profile_input.has_key('crlurl'): + if 'crlurl' in profile_input: Policy.crl_distribution_points_ext_default(root_element, policy_set_element, profile_input['crlurl']) - if profile_input.has_key('PathLength') and profile_input.has_key('isCA'): + if 'PathLength' in profile_input and 'isCA' in profile_input: Policy.basic_constraints_extension_default(root_element, policy_set_element, profile_input['PathLength'], profile_input['isCA']) Policy.ca_certificate_validity_default( @@ -1613,7 +1613,7 @@ def create_profile(self, user_params=None): profile_input['Key_Generate_InputId']) # Add subject name input and submitter information - if profile_input.has_key('subject_Name_Input_Id'): + if 'subject_Name_Input_Id' in profile_input: self.add_subject_name_input(root_element, profile_input[ 'subject_Name_Input_Id']) self.add_submitter_info(root_element, profile_input[ diff --git a/tests/dogtag/pytest-ansible/pki/testlib/common/utils.py b/tests/dogtag/pytest-ansible/pki/testlib/common/utils.py index 30ae5f1f883..797531c2a00 100644 --- a/tests/dogtag/pytest-ansible/pki/testlib/common/utils.py +++ b/tests/dogtag/pytest-ansible/pki/testlib/common/utils.py @@ -50,7 +50,7 @@ import constants log = logging.getLogger() -logging.basicConfig(stream=sys.stdout) +logging.basicConfig(stream=sys.stdout,level=logging.INFO) basic_pki_cmd = 'pki -d {} -c {} -p {} -P https -n "{}" '.format(constants.NSSDB, constants.CLIENT_DIR_PASSWORD, diff --git a/tests/dogtag/pytest-ansible/pytest/ca/bugzilla/test_bug_1787115_Copy_SKI_from_CSR_to_Certificate_Signed.py b/tests/dogtag/pytest-ansible/pytest/ca/bugzilla/test_bug_1787115_Copy_SKI_from_CSR_to_Certificate_Signed.py new file mode 100644 index 00000000000..70882499f07 --- /dev/null +++ b/tests/dogtag/pytest-ansible/pytest/ca/bugzilla/test_bug_1787115_Copy_SKI_from_CSR_to_Certificate_Signed.py @@ -0,0 +1,258 @@ +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +""" +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Description: Bug - 1787115 Copy SKI from CSR to Certificate Signed. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Author: Gaurav Swami +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2020 Red Hat, Inc. All rights reserved. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program 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 this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +""" + +import os +import sys +import pytest + +import re +import tempfile + +from pki.testlib.common.utils import ProfileOperations, log + +try: + from pki.testlib.common import constants +except Exception as e: + if os.path.isfile('/tmp/test_dir/constants.py'): + sys.path.append('/tmp/test_dir/') + import constants + +profile = 'caCACert' +profop = ProfileOperations(nssdb=constants.NSSDB) + + +def test_profile_update_SKI_parameters(ansible_module): + """ + :id: 8f761dd1-219e-404a-a1ea-333cf2a606b9 + :Title: Bug 1787115 - Update caCACert Profile with SKI parameter. + :Description: Bug 1787115 - Update caCACert Profile to include SKI parameter 'policyset.caCertSet.8.default.params.useSKIFromCertRequest'. + :Requirement: + :CaseComponent: \- + :Setup: + 1. Use the subsystems setup in ansible to run subsystem commands + + :Steps: + 1. Disable profile caCACert. + 2. Edit caCACert profile to add parameter 'policyset.caCertSet.8.default.params.useSKIFromCertRequest=true' + 3. Enable profile. + + :ExpectedResults: + 1. profile should be disabled. + 2. caCACert profile must include parameter 'policyset.caCertSet.8.default.params.useSKIFromCertRequest=true' + 3. profile should be enabled. + + """ + tmp_file = tempfile.mktemp(suffix='tmp_', prefix='_profile') + add_param = {'policyset.caCertSet.8.default.params.useSKIFromCertRequest': 'true'} + profile_show = ansible_module.pki(cli='ca-profile-show', + nssdb=constants.NSSDB, + port=constants.CA_HTTP_PORT, + dbpassword=constants.CLIENT_DATABASE_PASSWORD, + certnick='"{}"'.format(constants.CA_ADMIN_NICK), + extra_args='{} --raw'.format(profile)) + + for _, result in profile_show.items(): + if result['rc'] == 0: + newProfile = result['stdout'] + if newProfile: + with open(tmp_file, "a+") as f: + f.write(newProfile + '\n') + for key, value in add_param.items(): + f.write(str(key) + '=' + str(value) + '\n') + f.close + else: + log.error("Failed to get caServerCert Profile") + log.error("Failed to run: {}".format(result['cmd'])) + log.error(result['stdout']) + log.error(result['stderr']) + pytest.fail() + + profop.disable_profile(ansible_module, profile) + + ansible_module.copy(src=tmp_file, dest='/tmp/caCACert.tmp') + + update_prof = ansible_module.pki(cli='ca-profile-mod', + nssdb=constants.NSSDB, + port=constants.CA_HTTP_PORT, + dbpassword=constants.CLIENT_DATABASE_PASSWORD, + certnick='"{}"'.format(constants.CA_ADMIN_NICK), + extra_args='/tmp/caCACert.tmp --raw') + for result in update_prof.values(): + if result['rc'] == 0: + log.info('Profile Changed Successfully.') + else: + log.error("Failed to Update Profile.") + pytest.fail("Failed to Update Profile.") + + enabled = profop.enable_profile(ansible_module, profile_name=profile) + assert enabled + + ca_server_cert = ansible_module.pki(cli='ca-profile-show', + nssdb=constants.NSSDB, + port=constants.CA_HTTP_PORT, + dbpassword=constants.CLIENT_DATABASE_PASSWORD, + certnick='"{}"'.format(constants.CA_ADMIN_NICK), + extra_args='{} --raw'.format(profile)) + + for res in ca_server_cert.values(): + if res['rc'] == 0: + assert "policyset.caCertSet.8.default.params.useSKIFromCertRequest=true" in res['stdout'] + else: + pytest.fail("Failed to modify caCACert profile.") + + +def test_SKI_Validation_CSR_Signed_Certificate(ansible_module): + """ + :id: c57e8960-9545-4b1c-9728-be570766037c + :Title: Bug 1787115 - Generate Certificate from CSR with external SKID. + :Description: Sign Certificate from CSR with external SKID extension. + :Requirement: + :CaseComponent: \- + :Setup: + 1. Use the subsystems setup in ansible to run subsystem commands. + + :Steps: + 1. Genrate CSR with external SKID extension + 2. Submit the certificate request with CSR file. + 3. Approve the certificate request + 4. Export signed certificate. + 5. Check the certificate Subject Key Identifier matches with Subject Key Identifier from CSR. + + :ExpectedResults: + 1. CSR should be generate with SKI extension. + 2. CSR should be submitted succeesfully. + 3. Request should be approved succeesfully. + 4. Signed Certificate should be exported succeesfully. + 5. CSR and Signed Certificate SKI extension should identical. + """ + request_id = None + submitted_req = False + SKI_CSR = '/opt/pki/certdb/SKI.csr' + SKI_CRT = '/opt/pki/certdb/SKI.crt' + CA_SKID = '0xcba7aa1e3d2784153d47' # random hexadecimal number starts with 0x + + command = ['echo {} > /opt/pki/certdb/passwd.txt'.format(constants.CLIENT_DATABASE_PASSWORD), + 'openssl rand -out {}/noise.bin 2048'.format(constants.NSSDB)] + for x in command: + output = ansible_module.shell(x) + print("Create noise file: %s", x) + + certutil_args = {'-d ': '{}'.format(constants.NSSDB), '-f': '{}/passwd.txt'.format(constants.NSSDB), + '-z': '{}/noise.bin'.format(constants.NSSDB), '-k': 'rsa', '-g': '2048', '-Z': 'SHA256', + '-s': 'CN=pki1.example.com,O=EXAMPLE', + '--keyUsage': 'critical,dataEncipherment,keyEncipherment,digitalSignature', + '--extKeyUsage': 'serverAuth', '-o': '{}.der'.format(SKI_CSR), '--extSKID': ''} + + log.info("Generating certificate request using certutil tool") + data = [] + for key, value in certutil_args.items(): + data.append(key) + data.append(value) + command = 'certutil' + ' ' + '-R' + " " + " ".join(data) + + log.info("Running Certutil command : %s", command) + csr_output = ansible_module.expect(command=command, responses={ + "Enter value for the key identifier fields,enter to omit:": "{}".format(CA_SKID), + "Is this a critical extension [y/N]?": "y"}) + for result in csr_output.values(): + if result['rc'] == 0: + assert 'Generating key. This may take a few moments...' in result['stdout'] + else: + pytest.fail("Failed to Run Command {}".format(command)) + + ansible_module.shell('openssl req -inform der -in {}.der -out {}'.format(SKI_CSR, SKI_CSR)) + + sub_req = ansible_module.pki(cli='ca-cert-request-submit', + nssdb=constants.NSSDB, + port=constants.CA_HTTP_PORT, + dbpassword=constants.CLIENT_DATABASE_PASSWORD, + certnick='"{}"'.format(constants.CA_ADMIN_NICK), + extra_args='--profile {} --csr-file {}'.format(profile, SKI_CSR)) + for result in sub_req.values(): + log.info("Running {}".format(result['cmd'])) + if result['rc'] == 0: + assert "Submitted certificate request" in result['stdout'] + assert "Request ID" in result['stdout'] + assert "Request Status: pending" in result['stdout'] + try: + request_id = re.search('Request ID: [\w]*', + result['stdout']).group().encode('utf-8') + request_id = request_id.decode().split(":")[1].strip() + except Exception as e: + print(e) + sys.exit(1) + else: + log.error("Failed to Submit Certificate Request.") + log.error("Failed to run: {}".format(result['cmd'])) + pytest.fail() + + submitted_req = True + + if submitted_req: + approve_new_req = ansible_module.pki(cli='ca-cert-request-review', + nssdb=constants.NSSDB, + port=constants.CA_HTTP_PORT, + dbpassword=constants.CLIENT_DATABASE_PASSWORD, + certnick='"{}"'.format(constants.CA_ADMIN_NICK), + extra_args='{} --action approve'.format(request_id)) + for result in approve_new_req.values(): + log.info("Running : {}".format(result['cmd'])) + if result['rc'] == 0: + cert_id = re.findall('Certificate ID:.*', result['stdout']) + cert_request_id = int(cert_id[0].split(":")[1].strip(), 16) + assert 'Approved certificate request {}'.format(request_id) in result['stdout'] + assert 'Type: enrollment' in result['stdout'] + assert 'Operation Result: success' in result['stdout'] + log.info("Successfully approved certificate request.") + else: + log.error("Failed to display certificate request.") + pytest.fail("Failed to run pki ca-cert-request-review {} --action approve".format(request_id)) + + cert_show = ansible_module.pki(cli='ca-cert-export', + nssdb=constants.NSSDB, + port=constants.CA_HTTP_PORT, + dbpassword=constants.CLIENT_DATABASE_PASSWORD, + extra_args='{} --output {}'.format(cert_request_id, SKI_CRT)) + + ansible_module.package(name='dumpasn1', state='latest') + ansible_module.shell('AtoB {} {}'.format(SKI_CRT, SKI_CRT)) + dumpasn1 = ansible_module.command('dumpasn1 -a -d -v -l {}'.format(SKI_CRT)) + for res in dumpasn1.values(): + log.info("Running : {}".format(res['cmd'])) + if res['rc'] == 0: + assert "OCTET STRING CB A7 AA 1E 3D 27 84 15 3D 47" in res['stdout'] + log.info("SKI extension is Identical in CSR and Signed Certificate.") + else: + log.error("Failed verify the SKI match between CSR and Signed Certificate.") + + ansible_module.command('rm -rf {} {}'.format(SKI_CRT, SKI_CSR)) + \ No newline at end of file diff --git a/tests/dogtag/pytest-ansible/requirements.txt b/tests/dogtag/pytest-ansible/requirements.txt index d4740317aec..ce47b78be47 100644 --- a/tests/dogtag/pytest-ansible/requirements.txt +++ b/tests/dogtag/pytest-ansible/requirements.txt @@ -1,5 +1,5 @@ ansible==2.9.13 -pytest-ansible==2.2.2 +pytest-ansible==2.2.3 pytest-ansible-playbook pytest-logger pytest-autochecklog==0.2.0 @@ -7,4 +7,4 @@ configparser==4.0.2 pytest-html==1.22.1 pytest_marker_bugzilla==0.9.4 python-bugzilla==2.5.0 -pyOpenSSL +pyOpenSSL \ No newline at end of file