def _validate_issuer(self): expected_issuer = Name([ NameAttribute(oid=cryptography_name_to_oid(iss[0]), value=to_text(iss[1])) for iss in self.issuer ]) cert_issuer = self.existing_certificate.issuer if not compare_sets(expected_issuer, cert_issuer, self.issuer_strict): return self.issuer, cert_issuer
def __init__(self, criterium, module): self.criterium = criterium self.test_certificates = criterium.test_certificates self.subject = [] self.issuer = [] if criterium.subject: self.subject = [(cryptography_name_to_oid(k), to_native(v)) for k, v in parse_name_field(criterium.subject)] if criterium.issuer: self.issuer = [(cryptography_name_to_oid(k), to_native(v)) for k, v in parse_name_field(criterium.issuer)] self.subject_key_identifier = CryptographyChainMatcher._parse_key_identifier( criterium.subject_key_identifier, 'subject_key_identifier', criterium.index, module) self.authority_key_identifier = CryptographyChainMatcher._parse_key_identifier( criterium.authority_key_identifier, 'authority_key_identifier', criterium.index, module)
def _validate_subject(self): expected_subject = Name([ NameAttribute(oid=cryptography_name_to_oid(sub[0]), value=to_text(sub[1])) for sub in self.subject ]) cert_subject = self.existing_certificate.subject if not compare_sets(expected_subject, cert_subject, self.subject_strict): return expected_subject, cert_subject
def _check_extenededKeyUsage(extensions): current_usages_ext = _find_extension(extensions, cryptography.x509.ExtendedKeyUsage) current_usages = [str(usage) for usage in current_usages_ext.value] if current_usages_ext else [] usages = [str(cryptography_name_to_oid(usage)) for usage in self.extendedKeyUsage] if self.extendedKeyUsage else [] if set(current_usages) != set(usages): return False if usages: if current_usages_ext.critical != self.extendedKeyUsage_critical: return False return True
def _generate_crl(self): backend = default_backend() crl = CertificateRevocationListBuilder() try: crl = crl.issuer_name( Name([ NameAttribute(cryptography_name_to_oid(entry[0]), to_text(entry[1])) for entry in self.issuer ])) except ValueError as e: raise CRLError(e) crl = crl.last_update(self.last_update) crl = crl.next_update(self.next_update) if self.update and self.crl: new_entries = set([ self._compress_entry(entry) for entry in self.revoked_certificates ]) for entry in self.crl: decoded_entry = self._compress_entry( cryptography_decode_revoked_certificate(entry)) if decoded_entry not in new_entries: crl = crl.add_revoked_certificate(entry) for entry in self.revoked_certificates: revoked_cert = RevokedCertificateBuilder() revoked_cert = revoked_cert.serial_number(entry['serial_number']) revoked_cert = revoked_cert.revocation_date( entry['revocation_date']) if entry['issuer'] is not None: revoked_cert = revoked_cert.add_extension( x509.CertificateIssuer([ cryptography_get_name(name, 'issuer') for name in entry['issuer'] ]), entry['issuer_critical']) if entry['reason'] is not None: revoked_cert = revoked_cert.add_extension( x509.CRLReason(entry['reason']), entry['reason_critical']) if entry['invalidity_date'] is not None: revoked_cert = revoked_cert.add_extension( x509.InvalidityDate(entry['invalidity_date']), entry['invalidity_date_critical']) crl = crl.add_revoked_certificate(revoked_cert.build(backend)) self.crl = crl.sign(self.privatekey, self.digest, backend=backend) if self.format == 'pem': return self.crl.public_bytes(Encoding.PEM) else: return self.crl.public_bytes(Encoding.DER)
def check(self, perms_required=True, ignore_conversion=True): """Ensure the resource is in its desired state.""" state_and_perms = super(CRL, self).check(self.module, perms_required) if not state_and_perms: return False if self.crl is None: return False if self.last_update != self.crl.last_update and not self.ignore_timestamps: return False if self.next_update != self.crl.next_update and not self.ignore_timestamps: return False if self.digest.name != self.crl.signature_hash_algorithm.name: return False want_issuer = [(cryptography_name_to_oid(entry[0]), entry[1]) for entry in self.issuer] if want_issuer != [(sub.oid, sub.value) for sub in self.crl.issuer]: return False old_entries = [ self._compress_entry(cryptography_decode_revoked_certificate(cert)) for cert in self.crl ] new_entries = [ self._compress_entry(cert) for cert in self.revoked_certificates ] if self.update: # We don't simply use a set so that duplicate entries are treated correctly for entry in new_entries: try: old_entries.remove(entry) except ValueError: return False else: if old_entries != new_entries: return False if self.format != self.actual_format and not ignore_conversion: return False return True
def _validate_extended_key_usage(self): try: current_ext_keyusage = self.existing_certificate.extensions.get_extension_for_class( x509.ExtendedKeyUsage).value usages = [ cryptography_name_to_oid(usage) for usage in self.extended_key_usage ] expected_ext_keyusage = x509.ExtendedKeyUsage(usages) if not compare_sets(expected_ext_keyusage, current_ext_keyusage, self.extended_key_usage_strict): return [eku.value for eku in expected_ext_keyusage ], [eku.value for eku in current_ext_keyusage] except cryptography.x509.ExtensionNotFound: # This is only bad if the user specified a non-empty list if self.extended_key_usage: return NO_EXTENSION
def _check_subject(csr): subject = [(cryptography_name_to_oid(entry[0]), entry[1]) for entry in self.subject] current_subject = [(sub.oid, sub.value) for sub in csr.subject] return set(subject) == set(current_subject)
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.' )