# Buggy code
def _check_subjectAltName(extensions):
    altnames_ext = next(
        (ext for ext in extensions if ext.get_short_name() == b"subjectAltName"), ""
    )
    altnames = [
        altname.strip() for altname in str(altnames_ext).split(",") if altname.strip()
    ]
    # apperently openssl returns 'IP address' not 'IP' as specifier when converting the subjectAltName to string
    # although it won't accept this specifier when generating the CSR. (https://github.com/openssl/openssl/issues/4004)
    altnames = [
        name if not name.startswith("IP Address:") else "IP:" + name.split(":", 1)[1]
        for name in altnames
    ]
    if self.subjectAltName:
        if (
            set(altnames) != set(self.subjectAltName)
            or altnames_ext.get_critical() != self.subjectAltName_critical
        ):
            return False
    else:
        if altnames:
            return False

    return True


# Traceback (nAttributeError)
root@test:/ansible/playbooks# ansible-playbook reproduce.yml

PLAY [localhost] *************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************
ok: [localhost]

TASK [Generate root CA private key] ******************************************************************************************************************************
ok: [localhost]

TASK [openssl_csr] ***********************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "module_stderr": "/root/.ansible/tmp/ansible-tmp-1554976577.3779902-7265526702622/AnsiballZ_openssl_csr.py:18: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses\n  import imp\nTraceback (most recent call last):\n  File \"/root/.ansible/tmp/ansible-tmp-1554976577.3779902-7265526702622/AnsiballZ_openssl_csr.py\", line 114, in <module>\n    _ansiballz_main()\n  File \"/root/.ansible/tmp/ansible-tmp-1554976577.3779902-7265526702622/AnsiballZ_openssl_csr.py\", line 106, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/root/.ansible/tmp/ansible-tmp-1554976577.3779902-7265526702622/AnsiballZ_openssl_csr.py\", line 49, in invoke_module\n    imp.load_module('__main__', mod, module, MOD_DESC)\n  File \"/usr/local/lib/python3.7/imp.py\", line 234, in load_module\n    return load_source(name, filename, file)\n  File \"/usr/local/lib/python3.7/imp.py\", line 169, in load_source\n    module = _exec(spec, sys.modules[name])\n  File \"<frozen importlib._bootstrap>\", line 630, in _exec\n  File \"<frozen importlib._bootstrap_external>\", line 728, in exec_module\n  File \"<frozen importlib._bootstrap>\", line 219, in _call_with_frames_removed\n  File \"/tmp/ansible_openssl_csr_payload_agiegmf7/__main__.py\", line 924, in <module>\n  File \"/tmp/ansible_openssl_csr_payload_agiegmf7/__main__.py\", line 907, in main\n  File \"/tmp/ansible_openssl_csr_payload_agiegmf7/__main__.py\", line 441, in generate\n  File \"/tmp/ansible_openssl_csr_payload_agiegmf7/__main__.py\", line 469, in check\n  File \"/tmp/ansible_openssl_csr_payload_agiegmf7/__main__.py\", line 826, in _check_csr\n  File \"/tmp/ansible_openssl_csr_payload_agiegmf7/__main__.py\", line 803, in _check_extensions\n  File \"/tmp/ansible_openssl_csr_payload_agiegmf7/__main__.py\", line 764, in _check_basicConstraints\nAttributeError: 'Extension' object has no attribute 'ca'\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

PLAY RECAP *******************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0

# Fixed code
def _check_subjectAltName(extensions):
    altnames_ext = next(
        (ext for ext in extensions if ext.get_short_name() == b"subjectAltName"), ""
    )
    altnames = [
        self._normalize_san(altname.strip())
        for altname in to_text(altnames_ext, errors="surrogate_or_strict").split(",")
        if altname.strip()
    ]
    if self.subjectAltName:
        if (
            set(altnames)
            != set([self._normalize_san(to_text(name)) for name in self.subjectAltName])
            or altnames_ext.get_critical() != self.subjectAltName_critical
        ):
            return False
    else:
        if altnames:
            return False

    return True