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
def generate_csr(self): """(Re-)Generate CSR.""" self._ensure_private_key_loaded() csr = cryptography.x509.CertificateSigningRequestBuilder() try: csr = csr.subject_name( cryptography.x509.Name([ cryptography.x509.NameAttribute( cryptography_name_to_oid(entry[0]), to_text(entry[1])) for entry in self.subject ])) except ValueError as e: raise CertificateSigningRequestError(e) if self.subjectAltName: csr = csr.add_extension(cryptography.x509.SubjectAlternativeName( [cryptography_get_name(name) for name in self.subjectAltName]), critical=self.subjectAltName_critical) if self.keyUsage: params = cryptography_parse_key_usage_params(self.keyUsage) csr = csr.add_extension(cryptography.x509.KeyUsage(**params), critical=self.keyUsage_critical) if self.extendedKeyUsage: usages = [ cryptography_name_to_oid(usage) for usage in self.extendedKeyUsage ] csr = csr.add_extension(cryptography.x509.ExtendedKeyUsage(usages), critical=self.extendedKeyUsage_critical) if self.basicConstraints: params = {} ca, path_length = cryptography_get_basic_constraints( self.basicConstraints) csr = csr.add_extension(cryptography.x509.BasicConstraints( ca, path_length), critical=self.basicConstraints_critical) if self.ocspMustStaple: try: # This only works with cryptography >= 2.1 csr = csr.add_extension(cryptography.x509.TLSFeature( [cryptography.x509.TLSFeatureType.status_request]), critical=self.ocspMustStaple_critical) except AttributeError as dummy: csr = csr.add_extension( cryptography.x509.UnrecognizedExtension( CRYPTOGRAPHY_MUST_STAPLE_NAME, CRYPTOGRAPHY_MUST_STAPLE_VALUE), critical=self.ocspMustStaple_critical) if self.name_constraints_permitted or self.name_constraints_excluded: try: csr = csr.add_extension( cryptography.x509.NameConstraints( [ cryptography_get_name( name, 'name constraints permitted') for name in self.name_constraints_permitted ], [ cryptography_get_name(name, 'name constraints excluded') for name in self.name_constraints_excluded ], ), critical=self.name_constraints_critical) except TypeError as e: raise OpenSSLObjectError( 'Error while parsing name constraint: {0}'.format(e)) if self.create_subject_key_identifier: csr = csr.add_extension( cryptography.x509.SubjectKeyIdentifier.from_public_key( self.privatekey.public_key()), critical=False) elif self.subject_key_identifier is not None: csr = csr.add_extension(cryptography.x509.SubjectKeyIdentifier( self.subject_key_identifier), critical=False) if self.authority_key_identifier is not None or self.authority_cert_issuer is not None or self.authority_cert_serial_number is not None: issuers = None if self.authority_cert_issuer is not None: issuers = [ cryptography_get_name(n, 'authority cert issuer') for n in self.authority_cert_issuer ] csr = csr.add_extension(cryptography.x509.AuthorityKeyIdentifier( self.authority_key_identifier, issuers, self.authority_cert_serial_number), critical=False) if self.crl_distribution_points: csr = csr.add_extension(cryptography.x509.CRLDistributionPoints( self.crl_distribution_points), critical=False) digest = None if cryptography_key_needs_digest_for_signing(self.privatekey): digest = select_message_digest(self.digest) if digest is None: raise CertificateSigningRequestError( 'Unsupported digest "{0}"'.format(self.digest)) try: self.csr = csr.sign(self.privatekey, digest, self.cryptography_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 except UnicodeError as e: # This catches IDNAErrors, which happens when a bad name is passed as a SAN # (https://github.com/ansible-collections/community.crypto/issues/105). # For older cryptography versions, this is handled by idna, which raises # an idna.core.IDNAError. Later versions of cryptography deprecated and stopped # requiring idna, whence we cannot easily handle this error. Fortunately, in # most versions of idna, IDNAError extends UnicodeError. There is only version # 2.3 where it extends Exception instead (see # https://github.com/kjd/idna/commit/ebefacd3134d0f5da4745878620a6a1cba86d130 # and then # https://github.com/kjd/idna/commit/ea03c7b5db7d2a99af082e0239da2b68aeea702a). msg = 'Error while creating CSR: {0}\n'.format(e) if self.using_common_name_for_san: self.module.fail_json( msg=msg + 'This is probably caused because the Common Name is used as a SAN.' ' Specifying use_common_name_for_san=false might fix this.' ) self.module.fail_json( msg=msg + 'This is probably caused by an invalid Subject Alternative DNS Name.' )
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