コード例 #1
0
    def __init__(self, module):
        super(OwnCACertificateBackendCryptography, self).__init__(module, 'cryptography')

        self.create_subject_key_identifier = module.params['ownca_create_subject_key_identifier']
        self.create_authority_key_identifier = module.params['ownca_create_authority_key_identifier']
        self.notBefore = get_relative_time_option(module.params['ownca_not_before'], 'ownca_not_before', backend=self.backend)
        self.notAfter = get_relative_time_option(module.params['ownca_not_after'], 'ownca_not_after', backend=self.backend)
        self.digest = select_message_digest(module.params['ownca_digest'])
        self.version = module.params['ownca_version']
        self.serial_number = x509.random_serial_number()
        self.ca_cert_path = module.params['ownca_path']
        self.ca_cert_content = module.params['ownca_content']
        if self.ca_cert_content is not None:
            self.ca_cert_content = self.ca_cert_content.encode('utf-8')
        self.ca_privatekey_path = module.params['ownca_privatekey_path']
        self.ca_privatekey_content = module.params['ownca_privatekey_content']
        if self.ca_privatekey_content is not None:
            self.ca_privatekey_content = self.ca_privatekey_content.encode('utf-8')
        self.ca_privatekey_passphrase = module.params['ownca_privatekey_passphrase']

        if self.csr_content is None and self.csr_path is None:
            raise CertificateError(
                'csr_path or csr_content is required for ownca provider'
            )
        if self.csr_content is None and not os.path.exists(self.csr_path):
            raise CertificateError(
                'The certificate signing request file {0} does not exist'.format(self.csr_path)
            )
        if self.ca_cert_content is None and not os.path.exists(self.ca_cert_path):
            raise CertificateError(
                'The CA certificate file {0} does not exist'.format(self.ca_cert_path)
            )
        if self.ca_privatekey_content is None and not os.path.exists(self.ca_privatekey_path):
            raise CertificateError(
                'The CA private key file {0} does not exist'.format(self.ca_privatekey_path)
            )

        self._ensure_csr_loaded()
        self.ca_cert = load_certificate(
            path=self.ca_cert_path,
            content=self.ca_cert_content,
            backend=self.backend
        )
        try:
            self.ca_private_key = load_privatekey(
                path=self.ca_privatekey_path,
                content=self.ca_privatekey_content,
                passphrase=self.ca_privatekey_passphrase,
                backend=self.backend
            )
        except OpenSSLBadPassphraseError as exc:
            module.fail_json(msg=str(exc))

        if cryptography_key_needs_digest_for_signing(self.ca_private_key):
            if self.digest is None:
                raise CertificateError(
                    'The digest %s is not supported with the cryptography backend' % module.params['ownca_digest']
                )
        else:
            self.digest = None
コード例 #2
0
    def __init__(self, module):
        super(OwnCACertificateBackendPyOpenSSL, self).__init__(module, 'pyopenssl')

        self.notBefore = get_relative_time_option(self.module.params['ownca_not_before'], 'ownca_not_before', backend=self.backend)
        self.notAfter = get_relative_time_option(self.module.params['ownca_not_after'], 'ownca_not_after', backend=self.backend)
        self.digest = self.module.params['ownca_digest']
        self.version = self.module.params['ownca_version']
        self.serial_number = generate_serial_number()
        if self.module.params['ownca_create_subject_key_identifier'] != 'create_if_not_provided':
            self.module.fail_json(msg='ownca_create_subject_key_identifier cannot be used with the pyOpenSSL backend!')
        if self.module.params['ownca_create_authority_key_identifier']:
            self.module.warn('ownca_create_authority_key_identifier is ignored by the pyOpenSSL backend!')
        self.ca_cert_path = self.module.params['ownca_path']
        self.ca_cert_content = self.module.params['ownca_content']
        if self.ca_cert_content is not None:
            self.ca_cert_content = self.ca_cert_content.encode('utf-8')
        self.ca_privatekey_path = self.module.params['ownca_privatekey_path']
        self.ca_privatekey_content = self.module.params['ownca_privatekey_content']
        if self.ca_privatekey_content is not None:
            self.ca_privatekey_content = self.ca_privatekey_content.encode('utf-8')
        self.ca_privatekey_passphrase = self.module.params['ownca_privatekey_passphrase']

        if self.csr_content is None and not os.path.exists(self.csr_path):
            raise CertificateError(
                'The certificate signing request file {0} does not exist'.format(self.csr_path)
            )
        if self.ca_cert_content is None and not os.path.exists(self.ca_cert_path):
            raise CertificateError(
                'The CA certificate file {0} does not exist'.format(self.ca_cert_path)
            )
        if self.ca_privatekey_content is None and not os.path.exists(self.ca_privatekey_path):
            raise CertificateError(
                'The CA private key file {0} does not exist'.format(self.ca_privatekey_path)
            )

        self._ensure_csr_loaded()
        self.ca_cert = load_certificate(
            path=self.ca_cert_path,
            content=self.ca_cert_content,
        )
        try:
            self.ca_privatekey = load_privatekey(
                path=self.ca_privatekey_path,
                content=self.ca_privatekey_content,
                passphrase=self.ca_privatekey_passphrase
            )
        except OpenSSLBadPassphraseError as exc:
            self.module.fail_json(msg=str(exc))
コード例 #3
0
 def _validate_valid_in(self):
     valid_in_asn1 = get_relative_time_option(self.valid_in,
                                              "valid_in",
                                              backend=self.backend)
     valid_in_date = to_bytes(valid_in_asn1, errors='surrogate_or_strict')
     return self.existing_certificate.get_notBefore(
     ), valid_in_date, self.existing_certificate.get_notAfter()
コード例 #4
0
 def _validate_invalid_at(self):
     rt = get_relative_time_option(self.invalid_at,
                                   "invalid_at",
                                   backend=self.backend)
     rt = to_bytes(rt, errors='surrogate_or_strict')
     return self.existing_certificate.get_notBefore(
     ), rt, self.existing_certificate.get_notAfter()
コード例 #5
0
def main():
    module = AnsibleModule(
        argument_spec=dict(
            path=dict(type='path'),
            content=dict(type='str'),
            valid_at=dict(type='dict'),
            select_crypto_backend=dict(
                type='str',
                default='auto',
                choices=['auto', 'cryptography', 'pyopenssl']),
        ),
        required_one_of=(['path', 'content'], ),
        mutually_exclusive=(['path', 'content'], ),
        supports_check_mode=True,
    )
    if module._name == 'community.crypto.openssl_certificate_info':
        module.deprecate(
            "The 'community.crypto.openssl_certificate_info' module has been renamed to 'community.crypto.x509_certificate_info'",
            version='2.0.0',
            collection_name='community.crypto')

    if module.params['content'] is not None:
        data = module.params['content'].encode('utf-8')
    else:
        try:
            with open(module.params['path'], 'rb') as f:
                data = f.read()
        except (IOError, OSError) as e:
            module.fail_json(
                msg='Error while reading certificate file from disk: {0}'.
                format(e))

    backend, module_backend = select_backend(
        module, module.params['select_crypto_backend'], data)

    valid_at = module.params['valid_at']
    if valid_at:
        for k, v in valid_at.items():
            if not isinstance(v, string_types):
                module.fail_json(
                    msg=
                    'The value for valid_at.{0} must be of type string (got {1})'
                    .format(k, type(v)))
            valid_at[k] = get_relative_time_option(v, 'valid_at.{0}'.format(k))

    try:
        result = module_backend.get_info()

        not_before = module_backend.get_not_before()
        not_after = module_backend.get_not_after()

        result['valid_at'] = dict()
        if valid_at:
            for k, v in valid_at.items():
                result['valid_at'][k] = not_before <= v <= not_after

        module.exit_json(**result)
    except OpenSSLObjectError as exc:
        module.fail_json(msg=to_native(exc))
コード例 #6
0
    def __init__(self, module, backend):
        super(EntrustCertificateBackend, self).__init__(module, backend)
        self.trackingId = None
        self.notAfter = get_relative_time_option(module.params['entrust_not_after'], 'entrust_not_after', backend=self.backend)

        if self.csr_content is None and self.csr_path is None:
            raise CertificateError(
                'csr_path or csr_content is required for entrust provider'
            )
        if self.csr_content is None and not os.path.exists(self.csr_path):
            raise CertificateError(
                'The certificate signing request file {0} does not exist'.format(self.csr_path)
            )

        self._ensure_csr_loaded()

        # ECS API defaults to using the validated organization tied to the account.
        # We want to always force behavior of trying to use the organization provided in the CSR.
        # To that end we need to parse out the organization from the CSR.
        self.csr_org = None
        if self.backend == 'pyopenssl':
            csr_subject = self.csr.get_subject()
            csr_subject_components = csr_subject.get_components()
            for k, v in csr_subject_components:
                if k.upper() == 'O':
                    # Entrust does not support multiple validated organizations in a single certificate
                    if self.csr_org is not None:
                        self.module.fail_json(msg=("Entrust provider does not currently support multiple validated organizations. Multiple organizations "
                                                   "found in Subject DN: '{0}'. ".format(csr_subject)))
                    else:
                        self.csr_org = v
        elif self.backend == 'cryptography':
            csr_subject_orgs = self.csr.subject.get_attributes_for_oid(NameOID.ORGANIZATION_NAME)
            if len(csr_subject_orgs) == 1:
                self.csr_org = csr_subject_orgs[0].value
            elif len(csr_subject_orgs) > 1:
                self.module.fail_json(msg=("Entrust provider does not currently support multiple validated organizations. Multiple organizations found in "
                                           "Subject DN: '{0}'. ".format(self.csr.subject)))
        # If no organization in the CSR, explicitly tell ECS that it should be blank in issued cert, not defaulted to
        # organization tied to the account.
        if self.csr_org is None:
            self.csr_org = ''

        try:
            self.ecs_client = ECSClient(
                entrust_api_user=self.module.params['entrust_api_user'],
                entrust_api_key=self.module.params['entrust_api_key'],
                entrust_api_cert=self.module.params['entrust_api_client_cert_path'],
                entrust_api_cert_key=self.module.params['entrust_api_client_cert_key_path'],
                entrust_api_specification_path=self.module.params['entrust_api_specification_path']
            )
        except SessionConfigurationException as e:
            module.fail_json(msg='Failed to initialize Entrust Provider: {0}'.format(to_native(e.message)))
コード例 #7
0
    def __init__(self, module):
        super(SelfSignedCertificateBackendPyOpenSSL,
              self).__init__(module, 'pyopenssl')

        if module.params[
                'selfsigned_create_subject_key_identifier'] != 'create_if_not_provided':
            module.fail_json(
                msg=
                'selfsigned_create_subject_key_identifier cannot be used with the pyOpenSSL backend!'
            )
        self.notBefore = get_relative_time_option(
            module.params['selfsigned_not_before'],
            'selfsigned_not_before',
            backend=self.backend)
        self.notAfter = get_relative_time_option(
            module.params['selfsigned_not_after'],
            'selfsigned_not_after',
            backend=self.backend)
        self.digest = module.params['selfsigned_digest']
        self.version = module.params['selfsigned_version']
        self.serial_number = generate_serial_number()

        if self.csr_path is not None and not os.path.exists(self.csr_path):
            raise CertificateError(
                'The certificate signing request file {0} does not exist'.
                format(self.csr_path))
        if self.privatekey_content is None and not os.path.exists(
                self.privatekey_path):
            raise CertificateError(
                'The private key file {0} does not exist'.format(
                    self.privatekey_path))

        self._ensure_private_key_loaded()

        self._ensure_csr_loaded()
        if self.csr is None:
            # Create empty CSR on the fly
            self.csr = crypto.X509Req()
            self.csr.set_pubkey(self.privatekey)
            self.csr.sign(self.privatekey, self.digest)
コード例 #8
0
    def __init__(self, module, backend):
        super(CertificateInfo, self).__init__(
            module.params['path'] or '',
            'present',
            False,
            module.check_mode,
        )
        self.backend = backend
        self.module = module
        self.content = module.params['content']
        if self.content is not None:
            self.content = self.content.encode('utf-8')

        self.valid_at = module.params['valid_at']
        if self.valid_at:
            for k, v in self.valid_at.items():
                if not isinstance(v, string_types):
                    self.module.fail_json(
                        msg='The value for valid_at.{0} must be of type string (got {1})'.format(k, type(v))
                    )
                self.valid_at[k] = get_relative_time_option(v, 'valid_at.{0}'.format(k))
コード例 #9
0
    def __init__(self, module):
        super(CRL, self).__init__(
            module.params['path'],
            module.params['state'],
            module.params['force'],
            module.check_mode
        )

        self.format = module.params['format']

        self.update = module.params['mode'] == 'update'
        self.ignore_timestamps = module.params['ignore_timestamps']
        self.return_content = module.params['return_content']
        self.crl_content = None

        self.privatekey_path = module.params['privatekey_path']
        self.privatekey_content = module.params['privatekey_content']
        if self.privatekey_content is not None:
            self.privatekey_content = self.privatekey_content.encode('utf-8')
        self.privatekey_passphrase = module.params['privatekey_passphrase']

        self.issuer = parse_name_field(module.params['issuer'])
        self.issuer = [(entry[0], entry[1]) for entry in self.issuer if entry[1]]

        self.last_update = get_relative_time_option(module.params['last_update'], 'last_update')
        self.next_update = get_relative_time_option(module.params['next_update'], 'next_update')

        self.digest = select_message_digest(module.params['digest'])
        if self.digest is None:
            raise CRLError('The digest "{0}" is not supported'.format(module.params['digest']))

        self.revoked_certificates = []
        for i, rc in enumerate(module.params['revoked_certificates']):
            result = {
                'serial_number': None,
                'revocation_date': None,
                'issuer': None,
                'issuer_critical': False,
                'reason': None,
                'reason_critical': False,
                'invalidity_date': None,
                'invalidity_date_critical': False,
            }
            path_prefix = 'revoked_certificates[{0}].'.format(i)
            if rc['path'] is not None or rc['content'] is not None:
                # Load certificate from file or content
                try:
                    if rc['content'] is not None:
                        rc['content'] = rc['content'].encode('utf-8')
                    cert = load_certificate(rc['path'], content=rc['content'], backend='cryptography')
                    result['serial_number'] = cryptography_serial_number_of_cert(cert)
                except OpenSSLObjectError as e:
                    if rc['content'] is not None:
                        module.fail_json(
                            msg='Cannot parse certificate from {0}content: {1}'.format(path_prefix, to_native(e))
                        )
                    else:
                        module.fail_json(
                            msg='Cannot read certificate "{1}" from {0}path: {2}'.format(path_prefix, rc['path'], to_native(e))
                        )
            else:
                # Specify serial_number (and potentially issuer) directly
                result['serial_number'] = rc['serial_number']
            # All other options
            if rc['issuer']:
                result['issuer'] = [cryptography_get_name(issuer) for issuer in rc['issuer']]
                result['issuer_critical'] = rc['issuer_critical']
            result['revocation_date'] = get_relative_time_option(
                rc['revocation_date'],
                path_prefix + 'revocation_date'
            )
            if rc['reason']:
                result['reason'] = REVOCATION_REASON_MAP[rc['reason']]
                result['reason_critical'] = rc['reason_critical']
            if rc['invalidity_date']:
                result['invalidity_date'] = get_relative_time_option(
                    rc['invalidity_date'],
                    path_prefix + 'invalidity_date'
                )
                result['invalidity_date_critical'] = rc['invalidity_date_critical']
            self.revoked_certificates.append(result)

        self.module = module

        self.backup = module.params['backup']
        self.backup_file = None

        try:
            self.privatekey = load_privatekey(
                path=self.privatekey_path,
                content=self.privatekey_content,
                passphrase=self.privatekey_passphrase,
                backend='cryptography'
            )
        except OpenSSLBadPassphraseError as exc:
            raise CRLError(exc)

        self.crl = None
        try:
            with open(self.path, 'rb') as f:
                data = f.read()
            self.actual_format = 'pem' if identify_pem_format(data) else 'der'
            if self.actual_format == 'pem':
                self.crl = x509.load_pem_x509_crl(data, default_backend())
                if self.return_content:
                    self.crl_content = data
            else:
                self.crl = x509.load_der_x509_crl(data, default_backend())
                if self.return_content:
                    self.crl_content = base64.b64encode(data)
        except Exception as dummy:
            self.crl_content = None
            self.actual_format = self.format
コード例 #10
0
    def __init__(self, module):
        super(SelfSignedCertificateBackendCryptography,
              self).__init__(module, 'cryptography')

        self.create_subject_key_identifier = module.params[
            'selfsigned_create_subject_key_identifier']
        self.notBefore = get_relative_time_option(
            module.params['selfsigned_not_before'],
            'selfsigned_not_before',
            backend=self.backend)
        self.notAfter = get_relative_time_option(
            module.params['selfsigned_not_after'],
            'selfsigned_not_after',
            backend=self.backend)
        self.digest = select_message_digest(module.params['selfsigned_digest'])
        self.version = module.params['selfsigned_version']
        self.serial_number = x509.random_serial_number()

        if self.csr_path is not None and not os.path.exists(self.csr_path):
            raise CertificateError(
                'The certificate signing request file {0} does not exist'.
                format(self.csr_path))
        if self.privatekey_content is None and not os.path.exists(
                self.privatekey_path):
            raise CertificateError(
                'The private key file {0} does not exist'.format(
                    self.privatekey_path))

        self._module = module

        self._ensure_private_key_loaded()

        self._ensure_csr_loaded()
        if self.csr is None:
            # Create empty CSR on the fly
            csr = cryptography.x509.CertificateSigningRequestBuilder()
            csr = csr.subject_name(cryptography.x509.Name([]))
            digest = None
            if cryptography_key_needs_digest_for_signing(self.privatekey):
                digest = self.digest
                if digest is None:
                    self.module.fail_json(
                        msg='Unsupported digest "{0}"'.format(
                            module.params['selfsigned_digest']))
            try:
                self.csr = csr.sign(self.privatekey, digest, default_backend())
            except TypeError as e:
                if str(
                        e
                ) == 'Algorithm must be a registered hash algorithm.' and digest is None:
                    self.module.fail_json(
                        msg=
                        'Signing with Ed25519 and Ed448 keys requires cryptography 2.8 or newer.'
                    )
                raise

        if cryptography_key_needs_digest_for_signing(self.privatekey):
            if self.digest is None:
                raise CertificateError(
                    'The digest %s is not supported with the cryptography backend'
                    % module.params['selfsigned_digest'])
        else:
            self.digest = None
コード例 #11
0
 def _validate_valid_in(self):
     valid_in_date = get_relative_time_option(self.valid_in,
                                              "valid_in",
                                              backend=self.backend)
     return self.existing_certificate.not_valid_before, valid_in_date, self.existing_certificate.not_valid_after
コード例 #12
0
 def _validate_invalid_at(self):
     rt = get_relative_time_option(self.invalid_at,
                                   'invalid_at',
                                   backend=self.backend)
     return self.existing_certificate.not_valid_before, rt, self.existing_certificate.not_valid_after
コード例 #13
0
    def assertonly(self):
        messages = []
        if self.privatekey_path is not None or self.privatekey_content is not None:
            if not self._validate_privatekey():
                messages.append(
                    'Certificate %s and private key %s do not match' %
                    (self.path, self.privatekey_path
                     or '(provided in module options)'))

        if self.csr_path is not None or self.csr_content is not None:
            if not self._validate_csr_signature():
                messages.append(
                    'Certificate %s and CSR %s do not match: private key mismatch'
                    % (self.path, self.csr_path
                       or '(provided in module options)'))
            if not self._validate_csr_subject():
                messages.append(
                    'Certificate %s and CSR %s do not match: subject mismatch'
                    % (self.path, self.csr_path
                       or '(provided in module options)'))
            if not self._validate_csr_extensions():
                messages.append(
                    'Certificate %s and CSR %s do not match: extensions mismatch'
                    % (self.path, self.csr_path
                       or '(provided in module options)'))

        if self.signature_algorithms is not None:
            wrong_alg = self._validate_signature_algorithms()
            if wrong_alg:
                messages.append(
                    'Invalid signature algorithm (got %s, expected one of %s)'
                    % (wrong_alg, self.signature_algorithms))

        if self.subject is not None:
            failure = self._validate_subject()
            if failure:
                dummy, cert_subject = failure
                messages.append(
                    'Invalid subject component (got %s, expected all of %s to be present)'
                    % (cert_subject, self.subject))

        if self.issuer is not None:
            failure = self._validate_issuer()
            if failure:
                dummy, cert_issuer = failure
                messages.append(
                    'Invalid issuer component (got %s, expected all of %s to be present)'
                    % (cert_issuer, self.issuer))

        if self.has_expired is not None:
            cert_expired = self._validate_has_expired()
            if cert_expired != self.has_expired:
                messages.append(
                    'Certificate expiration check failed (certificate expiration is %s, expected %s)'
                    % (cert_expired, self.has_expired))

        if self.version is not None:
            cert_version = self._validate_version()
            if cert_version != self.version:
                messages.append(
                    'Invalid certificate version number (got %s, expected %s)'
                    % (cert_version, self.version))

        if self.key_usage is not None:
            failure = self._validate_key_usage()
            if failure == NO_EXTENSION:
                messages.append('Found no keyUsage extension')
            elif failure:
                dummy, cert_key_usage = failure
                messages.append(
                    'Invalid keyUsage components (got %s, expected all of %s to be present)'
                    % (cert_key_usage, self.key_usage))

        if self.extended_key_usage is not None:
            failure = self._validate_extended_key_usage()
            if failure == NO_EXTENSION:
                messages.append('Found no extendedKeyUsage extension')
            elif failure:
                dummy, ext_cert_key_usage = failure
                messages.append(
                    'Invalid extendedKeyUsage component (got %s, expected all of %s to be present)'
                    % (ext_cert_key_usage, self.extended_key_usage))

        if self.subject_alt_name is not None:
            failure = self._validate_subject_alt_name()
            if failure == NO_EXTENSION:
                messages.append('Found no subjectAltName extension')
            elif failure:
                dummy, cert_san = failure
                messages.append(
                    'Invalid subjectAltName component (got %s, expected all of %s to be present)'
                    % (cert_san, self.subject_alt_name))

        if self.not_before is not None:
            cert_not_valid_before = self._validate_not_before()
            if cert_not_valid_before != get_relative_time_option(
                    self.not_before, 'not_before', backend=self.backend):
                messages.append(
                    'Invalid not_before component (got %s, expected %s to be present)'
                    % (cert_not_valid_before, self.not_before))

        if self.not_after is not None:
            cert_not_valid_after = self._validate_not_after()
            if cert_not_valid_after != get_relative_time_option(
                    self.not_after, 'not_after', backend=self.backend):
                messages.append(
                    'Invalid not_after component (got %s, expected %s to be present)'
                    % (cert_not_valid_after, self.not_after))

        if self.valid_at is not None:
            not_before, valid_at, not_after = self._validate_valid_at()
            if not (not_before <= valid_at <= not_after):
                messages.append(
                    'Certificate is not valid for the specified date (%s) - not_before: %s - not_after: %s'
                    % (self.valid_at, not_before, not_after))

        if self.invalid_at is not None:
            not_before, invalid_at, not_after = self._validate_invalid_at()
            if not_before <= invalid_at <= not_after:
                messages.append(
                    'Certificate is not invalid for the specified date (%s) - not_before: %s - not_after: %s'
                    % (self.invalid_at, not_before, not_after))

        if self.valid_in is not None:
            not_before, valid_in, not_after = self._validate_valid_in()
            if not not_before <= valid_in <= not_after:
                messages.append(
                    'Certificate is not valid in %s from now (that would be %s) - not_before: %s - not_after: %s'
                    % (self.valid_in, valid_in, not_before, not_after))
        return messages