def get_info(self): result = dict() self.csr = crypto_utils.load_certificate_request(self.path, backend=self.backend) result['subject'] = self._get_subject() result['key_usage'], result[ 'key_usage_critical'] = self._get_key_usage() result['extended_key_usage'], result[ 'extended_key_usage_critical'] = self._get_extended_key_usage() result['basic_constraints'], result[ 'basic_constraints_critical'] = self._get_basic_constraints() result['ocsp_must_staple'], result[ 'ocsp_must_staple_critical'] = self._get_ocsp_must_staple() result['subject_alt_name'], result[ 'subject_alt_name_critical'] = self._get_subject_alt_name() result['public_key'] = self._get_public_key(binary=False) pk = self._get_public_key(binary=True) result[ 'public_key_fingerprints'] = crypto_utils.get_fingerprint_of_bytes( pk) if pk is not None else dict() result['extensions_by_oid'] = self._get_all_extensions() result['signature_valid'] = self._is_signature_valid() if not result['signature_valid']: self.module.fail_json(msg='CSR signature is invalid!', **result) return result
def __init__(self, module): super(SelfSignedCertificate, self).__init__(module) self.notBefore = module.params['selfsigned_notBefore'] self.notAfter = module.params['selfsigned_notAfter'] self.digest = module.params['selfsigned_digest'] self.version = module.params['selfsigned_version'] self.csr = crypto_utils.load_certificate_request(self.csr_path) self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase)
def __init__(self, module): super(SelfSignedCertificate, self).__init__(module) self.serial_number = randint(1000, 99999) self.notBefore = module.params['selfsigned_notBefore'] self.notAfter = module.params['selfsigned_notAfter'] self.digest = module.params['selfsigned_digest'] self.csr = crypto_utils.load_certificate_request(self.csr_path) self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase) self.cert = None
def check(self, module): """Ensure the resource is in its desired state.""" def _get_subject(csr): subject = csr.get_subject() components = dict(subject.get_components()) for sub_key, sub_val in components.items(): self.subject[sub_key] = sub_val for val in self.subject.values(): if val == '': self.subjectvalid = False def _get_san(csr): extensions = csr.get_extensions() for ext in extensions: if ext.get_short_name() == b"subjectAltName": for altname in str(ext).split(','): altname_data = altname.strip().split(':') if altname_data[0] not in self.subjectAltName: self.subjectAltName[altname_data[0]] = [] self.subjectAltName[altname_data[0]].append( altname_data[1]) def _get_key(csr): key = csr.get_pubkey() if key.type() == OpenSSL.crypto.TYPE_RSA: key_type = 'RSA' elif key.type() == OpenSSL.crypto.TYPE_DSA: key_type = 'DSA' elif key.type() == 408: key_type = 'EC' else: key_type = 'Unknown' self.key = { 'type': key_type, 'size': key.bits(), } # Minimums are being defined as 4096 for RSA/DSA & 384 for EC if (key_type == 'RSA' or key_type == 'DSA') and key.bits() >= 4096: self.keymin = True elif key_type == 'EC' and key.bits() >= 384: self.keymin = True if module.params['path']: csr = crypto_utils.load_certificate_request(self.path) else: try: csr = load_certificate_request(FILETYPE_PEM, self.csrdata) except (OpenSSL.crypto.Error) as exc: module.fail_json(msg=to_native(exc)) _get_subject(csr) _get_key(csr) _get_san(csr)
def __init__(self, module): super(SelfSignedCertificate, self).__init__(module) self.notBefore = module.params['selfsigned_notBefore'] self.notAfter = module.params['selfsigned_notAfter'] self.digest = module.params['selfsigned_digest'] self.version = module.params['selfsigned_version'] self.serial_number = randint(1000, 99999) self.csr = crypto_utils.load_certificate_request(self.csr_path) self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase )
def check(self, module, perms_required=True): """Ensure the resource is in its desired state.""" state_and_perms = super(Certificate, self).check(module, perms_required) def _validate_privatekey(): if self.privatekey_path: ctx = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_2_METHOD) ctx.use_privatekey(self.privatekey) ctx.use_certificate(self.cert) try: ctx.check_privatekey() return True except OpenSSL.SSL.Error: return False def _validate_csr(): try: self.csr.verify(self.cert.get_pubkey()) except OpenSSL.crypto.Error: return False if self.csr.get_subject() != self.cert.get_subject(): return False csr_extensions = self.csr.get_extensions() cert_extension_count = self.cert.get_extension_count() if len(csr_extensions) != cert_extension_count: return False for extension_number in range(0, cert_extension_count): cert_extension = self.cert.get_extension(extension_number) csr_extension = filter( lambda extension: extension.get_short_name() == cert_extension.get_short_name(), csr_extensions) if cert_extension.get_data() != list( csr_extension)[0].get_data(): return False return True if not state_and_perms: return False self.cert = crypto_utils.load_certificate(self.path) if self.privatekey_path: self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase) return _validate_privatekey() if self.csr_path: self.csr = crypto_utils.load_certificate_request(self.csr_path) if not _validate_csr(): return False return True
def __init__(self, module): super(SelfSignedCertificate, self).__init__(module) self.notBefore = self.get_relative_time_option(module.params['selfsigned_not_before'], 'selfsigned_not_before') self.notAfter = self.get_relative_time_option(module.params['selfsigned_not_after'], 'selfsigned_not_after') self.digest = module.params['selfsigned_digest'] self.version = module.params['selfsigned_version'] self.serial_number = randint(1000, 99999) self.csr = crypto_utils.load_certificate_request(self.csr_path) self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase )
def __init__(self, module): super(SelfSignedCertificate, self).__init__(module) self.notBefore = module.params['selfsigned_notBefore'] self.notAfter = module.params['selfsigned_notAfter'] self.digest = module.params['selfsigned_digest'] self.version = module.params['selfsigned_version'] self.csr = crypto_utils.load_certificate_request(self.csr_path) self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase) if module.params['provider'] == 'localsigned': self.cacert = crypto_utils.load_certificate( module.params['cacert_path']) else: self.cacert = None
def get_info(self): result = dict() self.csr = crypto_utils.load_certificate_request(self.path, content=self.content, backend=self.backend) subject = self._get_subject_ordered() result['subject'] = dict() for k, v in subject: result['subject'][k] = v result['subject_ordered'] = subject result['key_usage'], result[ 'key_usage_critical'] = self._get_key_usage() result['extended_key_usage'], result[ 'extended_key_usage_critical'] = self._get_extended_key_usage() result['basic_constraints'], result[ 'basic_constraints_critical'] = self._get_basic_constraints() result['ocsp_must_staple'], result[ 'ocsp_must_staple_critical'] = self._get_ocsp_must_staple() result['subject_alt_name'], result[ 'subject_alt_name_critical'] = self._get_subject_alt_name() result['public_key'] = self._get_public_key(binary=False) pk = self._get_public_key(binary=True) result[ 'public_key_fingerprints'] = crypto_utils.get_fingerprint_of_bytes( pk) if pk is not None else dict() if self.backend != 'pyopenssl': ski = self._get_subject_key_identifier() if ski is not None: ski = to_native(binascii.hexlify(ski)) ski = ':'.join([ski[i:i + 2] for i in range(0, len(ski), 2)]) result['subject_key_identifier'] = ski aki, aci, acsn = self._get_authority_key_identifier() if aki is not None: aki = to_native(binascii.hexlify(aki)) aki = ':'.join([aki[i:i + 2] for i in range(0, len(aki), 2)]) result['authority_key_identifier'] = aki result['authority_cert_issuer'] = aci result['authority_cert_serial_number'] = acsn result['extensions_by_oid'] = self._get_all_extensions() result['signature_valid'] = self._is_signature_valid() if not result['signature_valid']: self.module.fail_json(msg='CSR signature is invalid!', **result) return result
def __init__(self, module): super(OwnCACertificate, self).__init__(module) self.notBefore = module.params['ownca_not_before'] self.notAfter = module.params['ownca_not_after'] self.digest = module.params['ownca_digest'] self.version = module.params['ownca_version'] self.serial_number = randint(1000, 99999) self.ca_cert_path = module.params['ownca_path'] self.ca_privatekey_path = module.params['ownca_privatekey_path'] self.ca_privatekey_passphrase = module.params['ownca_privatekey_passphrase'] self.csr = crypto_utils.load_certificate_request(self.csr_path) self.ca_cert = crypto_utils.load_certificate(self.ca_cert_path) self.ca_privatekey = crypto_utils.load_privatekey( self.ca_privatekey_path, self.ca_privatekey_passphrase )
def _check_csr(self): def _check_subject(csr): subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in self.subject] current_subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in csr.get_subject().get_components()] if not set(subject) == set(current_subject): return False return True 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(',')] # 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 def _check_keyUsage_(extensions, extName, expected, critical): usages_ext = [ext for ext in extensions if ext.get_short_name() == extName] if (not usages_ext and expected) or (usages_ext and not expected): return False elif not usages_ext and not expected: return True else: current = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage.strip())) for usage in str(usages_ext[0]).split(',')] expected = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage)) for usage in expected] return set(current) == set(expected) and usages_ext[0].get_critical() == critical def _check_keyUsage(extensions): usages_ext = [ext for ext in extensions if ext.get_short_name() == b'keyUsage'] if (not usages_ext and self.keyUsage) or (usages_ext and not self.keyUsage): return False elif not usages_ext and not self.keyUsage: return True else: # OpenSSL._util.lib.OBJ_txt2nid() always returns 0 for all keyUsage values # (since keyUsage has a fixed bitfield for these values and is not extensible). # Therefore, we create an extension for the wanted values, and compare the # data of the extensions (which is the serialized bitfield). expected_ext = crypto.X509Extension(b"keyUsage", False, ', '.join(self.keyUsage).encode('ascii')) return usages_ext[0].get_data() == expected_ext.get_data() and usages_ext[0].get_critical() == self.keyUsage_critical def _check_extenededKeyUsage(extensions): return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical) def _check_basicConstraints(extensions): return _check_keyUsage_(extensions, b'basicConstraints', self.basicConstraints, self.basicConstraints_critical) def _check_ocspMustStaple(extensions): oms_ext = [ext for ext in extensions if to_bytes(ext.get_short_name()) == OPENSSL_MUST_STAPLE_NAME and to_bytes(ext) == OPENSSL_MUST_STAPLE_VALUE] if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000: # Older versions of libssl don't know about OCSP Must Staple oms_ext.extend([ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05']) if self.ocspMustStaple: return len(oms_ext) > 0 and oms_ext[0].get_critical() == self.ocspMustStaple_critical else: return len(oms_ext) == 0 def _check_extensions(csr): extensions = csr.get_extensions() return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and _check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and _check_ocspMustStaple(extensions)) def _check_signature(csr): try: return csr.verify(self.privatekey) except crypto.Error: return False csr = crypto_utils.load_certificate_request(self.path) return _check_subject(csr) and _check_extensions(csr) and _check_signature(csr)
def check(self, module, perms_required=True): """Ensure the resource is in its desired state.""" state_and_perms = super(CertificateSigningRequest, self).check(module, perms_required) self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase) def _check_subject(csr): subject = csr.get_subject() for (key, value) in self.subject.items(): if getattr(subject, key, None) != value: return False return True 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(',') ] # 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 def _check_keyUsage_(extensions, extName, expected, critical): usages_ext = [ ext for ext in extensions if ext.get_short_name() == extName ] if (not usages_ext and expected) or (usages_ext and not expected): return False elif not usages_ext and not expected: return True else: current = [ OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage.strip())) for usage in str(usages_ext[0]).split(',') ] expected = [ OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage)) for usage in expected ] return set(current) == set( expected) and usages_ext[0].get_critical() == critical def _check_keyUsage(extensions): return _check_keyUsage_(extensions, b'keyUsage', self.keyUsage, self.keyUsage_critical) def _check_extenededKeyUsage(extensions): return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical) def _check_extensions(csr): extensions = csr.get_extensions() return _check_subjectAltName(extensions) and _check_keyUsage( extensions) and _check_extenededKeyUsage(extensions) def _check_signature(csr): try: return csr.verify(self.privatekey) except crypto.Error: return False if not state_and_perms: return False csr = crypto_utils.load_certificate_request(self.path) return _check_subject(csr) and _check_extensions( csr) and _check_signature(csr)
def _check_csr(self): def _check_subject(csr): subject = [(crypto_utils.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 _find_extension(extensions, type): return next( (ext for ext in extensions if isinstance(ext.value, type)), None) def _check_subjectAltName(extensions): current_altnames_ext = _find_extension( extensions, cryptography.x509.SubjectAlternativeName) current_altnames = [ str(altname) for altname in current_altnames_ext.value ] if current_altnames_ext else [] altnames = [ str(crypto_utils.cryptography_get_name(altname)) for altname in self.subjectAltName ] if self.subjectAltName else [] if set(altnames) != set(current_altnames): return False if altnames: if current_altnames_ext.critical != self.subjectAltName_critical: return False return True def _check_keyUsage(extensions): current_keyusage_ext = _find_extension(extensions, cryptography.x509.KeyUsage) if not self.keyUsage: return current_keyusage_ext is None elif current_keyusage_ext is None: return False params = crypto_utils.cryptography_parse_key_usage_params( self.keyUsage) for param in params: if getattr(current_keyusage_ext.value, '_' + param) != params[param]: return False if current_keyusage_ext.critical != self.keyUsage_critical: return False return True 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(crypto_utils.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 _check_basicConstraints(extensions): bc_ext = _find_extension(extensions, cryptography.x509.BasicConstraints) current_ca = bc_ext.value.ca if bc_ext else False current_path_length = bc_ext.value.path_length if bc_ext else None ca, path_length = crypto_utils.cryptography_get_basic_constraints( self.basicConstraints) # Check CA flag if ca != current_ca: return False # Check path length if path_length != current_path_length: return False # Check criticality if self.basicConstraints: if bc_ext.critical != self.basicConstraints_critical: return False return True def _check_ocspMustStaple(extensions): try: # This only works with cryptography >= 2.1 tlsfeature_ext = _find_extension(extensions, cryptography.x509.TLSFeature) has_tlsfeature = True except AttributeError as dummy: tlsfeature_ext = next( (ext for ext in extensions if ext.value.oid == CRYPTOGRAPHY_MUST_STAPLE_NAME), None) has_tlsfeature = False if self.ocspMustStaple: if not tlsfeature_ext or tlsfeature_ext.critical != self.ocspMustStaple_critical: return False if has_tlsfeature: return cryptography.x509.TLSFeatureType.status_request in tlsfeature_ext.value else: return tlsfeature_ext.value.value == CRYPTOGRAPHY_MUST_STAPLE_VALUE else: return tlsfeature_ext is None def _check_extensions(csr): extensions = csr.extensions return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and _check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and _check_ocspMustStaple(extensions)) def _check_signature(csr): if not csr.is_signature_valid: return False # To check whether public key of CSR belongs to private key, # encode both public keys and compare PEMs. key_a = csr.public_key().public_bytes( cryptography.hazmat.primitives.serialization.Encoding.PEM, cryptography.hazmat.primitives.serialization.PublicFormat. SubjectPublicKeyInfo) key_b = self.privatekey.public_key().public_bytes( cryptography.hazmat.primitives.serialization.Encoding.PEM, cryptography.hazmat.primitives.serialization.PublicFormat. SubjectPublicKeyInfo) return key_a == key_b try: csr = crypto_utils.load_certificate_request(self.path, backend='cryptography') except Exception as dummy: return False return _check_subject(csr) and _check_extensions( csr) and _check_signature(csr)
def check(self, module, perms_required=True): """Ensure the resource is in its desired state.""" state_and_perms = super(CertificateSigningRequest, self).check(module, perms_required) self.privatekey = crypto_utils.load_privatekey(self.privatekey_path, self.privatekey_passphrase) def _check_subject(csr): subject = csr.get_subject() for (key, value) in self.subject.items(): if getattr(subject, key, None) != value: return False return True 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(',')] # 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 def _check_keyUsage_(extensions, extName, expected, critical): usages_ext = [ext for ext in extensions if ext.get_short_name() == extName] if (not usages_ext and expected) or (usages_ext and not expected): return False elif not usages_ext and not expected: return True else: current = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage.strip())) for usage in str(usages_ext[0]).split(',')] expected = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage)) for usage in expected] return set(current) == set(expected) and usages_ext[0].get_critical() == critical def _check_keyUsage(extensions): return _check_keyUsage_(extensions, b'keyUsage', self.keyUsage, self.keyUsage_critical) def _check_extenededKeyUsage(extensions): return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical) def _check_extensions(csr): extensions = csr.get_extensions() return _check_subjectAltName(extensions) and _check_keyUsage(extensions) and _check_extenededKeyUsage(extensions) def _check_signature(csr): try: return csr.verify(self.privatekey) except crypto.Error: return False if not state_and_perms: return False csr = crypto_utils.load_certificate_request(self.path) return _check_subject(csr) and _check_extensions(csr) and _check_signature(csr)
def check(self, module, perms_required=True): """Ensure the resource is in its desired state.""" state_and_perms = super(CertificateSigningRequest, self).check(module, perms_required) self.privatekey = crypto_utils.load_privatekey(self.privatekey_path, self.privatekey_passphrase) def _check_subject(csr): subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in self.subject] current_subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in csr.get_subject().get_components()] if not set(subject) == set(current_subject): return False return True 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(',')] # 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 def _check_keyUsage_(extensions, extName, expected, critical): usages_ext = [ext for ext in extensions if ext.get_short_name() == extName] if (not usages_ext and expected) or (usages_ext and not expected): return False elif not usages_ext and not expected: return True else: current = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage.strip())) for usage in str(usages_ext[0]).split(',')] expected = [OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage)) for usage in expected] return set(current) == set(expected) and usages_ext[0].get_critical() == critical def _check_keyUsage(extensions): return _check_keyUsage_(extensions, b'keyUsage', self.keyUsage, self.keyUsage_critical) def _check_extenededKeyUsage(extensions): return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical) def _check_basicConstraints(extensions): return _check_keyUsage_(extensions, b'basicConstraints', self.basicConstraints, self.basicConstraints_critical) def _check_ocspMustStaple(extensions): oms_ext = [ext for ext in extensions if ext.get_short_name() == MUST_STAPLE_NAME and str(ext) == MUST_STAPLE_VALUE] if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000: # Older versions of libssl don't know about OCSP Must Staple oms_ext.extend([ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05']) if self.ocspMustStaple: return len(oms_ext) > 0 and oms_ext[0].get_critical() == self.ocspMustStaple_critical else: return len(oms_ext) == 0 def _check_extensions(csr): extensions = csr.get_extensions() return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and _check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and _check_ocspMustStaple(extensions)) def _check_signature(csr): try: return csr.verify(self.privatekey) except crypto.Error: return False if not state_and_perms: return False csr = crypto_utils.load_certificate_request(self.path) return _check_subject(csr) and _check_extensions(csr) and _check_signature(csr)
def check(self, module, perms_required=True): """Ensure the resource is in its desired state.""" state_and_perms = super(CertificateSigningRequest, self).check(module, perms_required) self.privatekey = crypto_utils.load_privatekey( self.privatekey_path, self.privatekey_passphrase) def _check_subject(csr): subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in self.subject] current_subject = [ (OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in csr.get_subject().get_components() ] if not set(subject) == set(current_subject): return False return True 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(',') ] # 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 def _check_keyUsage_(extensions, extName, expected, critical): usages_ext = [ ext for ext in extensions if ext.get_short_name() == extName ] if (not usages_ext and expected) or (usages_ext and not expected): return False elif not usages_ext and not expected: return True else: current = [ OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage.strip())) for usage in str(usages_ext[0]).split(',') ] expected = [ OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage)) for usage in expected ] return set(current) == set( expected) and usages_ext[0].get_critical() == critical def _check_keyUsage(extensions): return _check_keyUsage_(extensions, b'keyUsage', self.keyUsage, self.keyUsage_critical) def _check_extenededKeyUsage(extensions): return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical) def _check_basicConstraints(extensions): return _check_keyUsage_(extensions, b'basicConstraints', self.basicConstraints, self.basicConstraints_critical) def _check_ocspMustStaple(extensions): oms_ext = [ ext for ext in extensions if ext.get_short_name() == MUST_STAPLE_NAME and str(ext) == MUST_STAPLE_VALUE ] if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000: # Older versions of libssl don't know about OCSP Must Staple oms_ext.extend([ ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05' ]) if self.ocspMustStaple: return len(oms_ext) > 0 and oms_ext[0].get_critical( ) == self.ocspMustStaple_critical else: return len(oms_ext) == 0 def _check_extensions(csr): extensions = csr.get_extensions() return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and _check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and _check_ocspMustStaple(extensions)) def _check_signature(csr): try: return csr.verify(self.privatekey) except crypto.Error: return False if not state_and_perms: return False csr = crypto_utils.load_certificate_request(self.path) return _check_subject(csr) and _check_extensions( csr) and _check_signature(csr)
def _check_csr(self): def _check_subject(csr): subject = [(OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in self.subject] current_subject = [ (OpenSSL._util.lib.OBJ_txt2nid(to_bytes(sub[0])), to_bytes(sub[1])) for sub in csr.get_subject().get_components() ] if not set(subject) == set(current_subject): return False return True 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 def _check_keyUsage_(extensions, extName, expected, critical): usages_ext = [ ext for ext in extensions if ext.get_short_name() == extName ] if (not usages_ext and expected) or (usages_ext and not expected): return False elif not usages_ext and not expected: return True else: current = [ OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage.strip())) for usage in str(usages_ext[0]).split(',') ] expected = [ OpenSSL._util.lib.OBJ_txt2nid(to_bytes(usage)) for usage in expected ] return set(current) == set( expected) and usages_ext[0].get_critical() == critical def _check_keyUsage(extensions): usages_ext = [ ext for ext in extensions if ext.get_short_name() == b'keyUsage' ] if (not usages_ext and self.keyUsage) or (usages_ext and not self.keyUsage): return False elif not usages_ext and not self.keyUsage: return True else: # OpenSSL._util.lib.OBJ_txt2nid() always returns 0 for all keyUsage values # (since keyUsage has a fixed bitfield for these values and is not extensible). # Therefore, we create an extension for the wanted values, and compare the # data of the extensions (which is the serialized bitfield). expected_ext = crypto.X509Extension( b"keyUsage", False, ', '.join(self.keyUsage).encode('ascii')) return usages_ext[0].get_data() == expected_ext.get_data( ) and usages_ext[0].get_critical() == self.keyUsage_critical def _check_extenededKeyUsage(extensions): return _check_keyUsage_(extensions, b'extendedKeyUsage', self.extendedKeyUsage, self.extendedKeyUsage_critical) def _check_basicConstraints(extensions): return _check_keyUsage_(extensions, b'basicConstraints', self.basicConstraints, self.basicConstraints_critical) def _check_ocspMustStaple(extensions): oms_ext = [ ext for ext in extensions if to_bytes(ext.get_short_name()) == OPENSSL_MUST_STAPLE_NAME and to_bytes(ext) == OPENSSL_MUST_STAPLE_VALUE ] if OpenSSL.SSL.OPENSSL_VERSION_NUMBER < 0x10100000: # Older versions of libssl don't know about OCSP Must Staple oms_ext.extend([ ext for ext in extensions if ext.get_short_name() == b'UNDEF' and ext.get_data() == b'\x30\x03\x02\x01\x05' ]) if self.ocspMustStaple: return len(oms_ext) > 0 and oms_ext[0].get_critical( ) == self.ocspMustStaple_critical else: return len(oms_ext) == 0 def _check_extensions(csr): extensions = csr.get_extensions() return (_check_subjectAltName(extensions) and _check_keyUsage(extensions) and _check_extenededKeyUsage(extensions) and _check_basicConstraints(extensions) and _check_ocspMustStaple(extensions)) def _check_signature(csr): try: return csr.verify(self.privatekey) except crypto.Error: return False try: csr = crypto_utils.load_certificate_request(self.path, backend='pyopenssl') except Exception as dummy: return False return _check_subject(csr) and _check_extensions( csr) and _check_signature(csr)