def statistic_error(self, error): """统计错误次数,同种达到一定错误次数就终止服务""" error = str(error) count = self.error_container.get(error, 0) count += 1 if count >= self.error_counts: logger.warn('同种错误发生次数达到最大') os._exit(0) self.error_container[error] = count
def check_for_wildcards(self): #TODO: Das ist in der Prüfung von CA Zertifkaten anders. Die Funktion hier steigt leider aus wenn es die AlternativeNames extension nich gitb und daher kann man sie eigentlich für ein CA-ZErt nicht verwenden. Und es müssen auch noch mehr Felder (subject) geprüft werden. for entry in self.cert.subject._attributes: for attr in entry: if attr.oid._name == "commonName": logger.info( "commonName im subject des Zertifikat hat den Wert: " + attr.value) # test auf stern in cn if re.search(r"\*+", attr.value) != None: logger.error( "Der CN enthält mindestens ein *. Das ist nicht OK" ) try: name_extension = self.cert.extensions.get_extension_for_class( x509.SubjectAlternativeName) logger.info("Das Zertifikat hat eine AlternativeName Extension") # liste der san altname_list = name_extension.value.get_values_for_type( x509.DNSName) # keine san enthalten if len(altname_list) < 1: logger.warn("Die Liste der Alernative Names ist leer.") return # test auf stern in san for altname in altname_list: if re.search(r"\*+", altname) != None: logger.error( "Die AlternativeName-Extension enthält mindestens ein *. Das ist nicht OK" ) return logger.info( "Die AlternativeName-Extension enthält keine Wildcards. Das ist OK" ) except Exception as err: # eine fehlende SAN-Extension an sich sollte kein Fehler sein # bitte prüfen logger.info("Es existiert keine AlternativeName-Extension")
def check_cert_for_crl(self): try: crl_extension = self.cert.extensions.get_extension_for_class( x509.CRLDistributionPoints) logger.info( "Das Zertifikat hat eine CRLDistributionPoint Extension") logger.info( "Der Inhalt der CRLDistributionPoint Extension lautet:") logger.info(str(crl_extension)) #TODO: Die Ausgabe der Extension könnte etwas schöner werden except x509.extensions.ExtensionNotFound as err: logger.warn( "Das Zertifikat besitzt keine CRLDistributionPoint-Extension") except Exception as err: logger.warn( "Unbekannter Fehler beim Lesen der CRLDistributionPoint-Extension" ) print err
def check_cert_for_aia(self): try: aia_extension = self.cert.extensions.get_extension_for_class( x509.AuthorityInformationAccess) logger.info( "Das Zertifikat hat eine AuthorityInformationAccess Extension") logger.info( "Der Inhalt der AuthorityInformationAccess Extension lautet:") logger.info(str(aia_extension)) #TODO: Die Ausgabe der Extension könnte etwas schöner werden except x509.extensions.ExtensionNotFound as err: logger.warn( "Das Zertifikat besitzt keine AuthorityInformationAccess-Extension" ) except Exception as err: logger.warn( "Unbekannter Fehler beim Lesen der AuthorityInformationAccess-Extension" ) print err
def test_key_exchange(self): #Anforderung 2.4.1 # key exchange dh Länge anzeigen openssl_cmd_getcert = "echo | openssl s_client -msg -connect " + self.hostname + ":" + str( self.port ) + self.openssl_client_proxy_part + " | grep 'Server Temp Key:'" proc = subprocess.Popen([openssl_cmd_getcert], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) (out, err) = proc.communicate() out_list = out.splitlines() if len(out_list) < 1: logger.warn("Parameter konnten nicht gelesen werden") logger.warn(out) return if "Server Temp Key: DH," in out_list[0]: bits = int(out_list[0].split()[-2]) if bits < 2048: logger.error( "Verwendete Keylänge ist kleiner als 2048 bit. Das ist nicht OK" ) logger.warn(out) else: logger.info( "Verwendete Keylänge beträgt mind. 2048 bit. Das ist so OK." ) logger.info(out) return elif "Server Temp Key: ECDH" in out_list[0]: # verwendete ecc Kurve anzeigen # http://crypto.stackexchange.com/questions/11310/with-openssl-and-ecdhe-how-to-show-the-actual-curve-being-used # openssl key exchange short description openssl_cmd_getcert = "echo | openssl s_client -msg -connect " + self.hostname + ":" + str( self.port ) + self.openssl_client_proxy_part + " | grep 'ServerKey' -A 5" proc = subprocess.Popen([openssl_cmd_getcert], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) (out, err) = proc.communicate() out_list = out.splitlines() if len(out_list) < 2: logger.warn("Parameter konnten nicht gelesen werden") logger.warn(out) return param_list = out_list[1].strip().split() if param_list[0] != "0c" or param_list[4] != "03": logger.warn("Parameter passen nicht zu ECDH Werten") logger.warn(out) return decimal_curve_id = int(param_list[5] + param_list[6], 16) if decimal_curve_id in self.ec_curve_names: logger.info("Verwendete ECDHE Kurve: " + self.ec_curve_names[decimal_curve_id] + ". Das ist so OK.") else: logger.warn( "Verwendete ECDHE Kurve unbekannt, bitte manuell prüfen") logger.warn(out) else: logger.warn( "Verwendeter Key Exchange unbekannt, bitte manuell überprüfen") logger.warn(out) return
def test_supported_cipher_suites(self): #Anforderung 2.3.2/2.3.3/2.3.4 #TODO: Funktioniert aktuell nur mit RSA crypto_type = "RSA" openssl_cmd_getcert = "openssl ciphers" proc = subprocess.Popen([openssl_cmd_getcert], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) (out, err) = proc.communicate() out = out.replace('\n', '').replace('\r', '') all_ciphers = out.split(":") all_ciphers = filter(None, all_ciphers) all_ciphers = filter(None, all_ciphers) for cipher in all_ciphers: cipher_list = [ x for x in self.cipher_suites if x[1] == cipher and x[2] == crypto_type ] allowed = should = must = optional = False if len(cipher_list) == 0: allowed = False elif cipher_list[0][3] == "MUST": must = True allowed = True elif cipher_list[0][3] == "SHOULD": should = True allowed = True elif cipher_list[0][3] == "OPTIONAL": optional = True allowed = True context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) context.set_ciphers(cipher) if self.insecure: context.verify_mode = ssl.CERT_NONE context.check_hostname = False else: context.verify_mode = ssl.CERT_REQUIRED context.check_hostname = True if self.ca_file: context.load_verify_locations(cafile=self.ca_file) else: context.load_default_certs() if self.clientcert_file: context.load_cert_chain(certfile=self.clientcert_file) try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_sock = context.wrap_socket(s, server_hostname=self.hostname) ssl_sock.connect((self.hostname, self.port)) priority = ssl_sock.cipher()[2] if not allowed: logger.error( "Server unterstützt verbotene cipher-suite: " + cipher + " mit Priorität" + str(priority) + " Das sollte nicht der Fall sein") elif must or should or optional: logger.warning(cipher + " wird unterstützt mit Priorität" + str(priority) + ". Bitte in der Checkliste prüfen.") # Zertifikatfehler except ssl.CertificateError as err: logger.error("Zertifikatfehler bei Überprüfung von %s" % (cipher)) print(err) # ssl Verbindungsabbruch except ssl.SSLError as err: if len(err.args) > 1: if "SSLV3_ALERT_HANDSHAKE_FAILURE" in err.args[ 1] or "NO_CIPHERS_AVAILABLE" in err.args[ 1] or "EOF occurred in violation of protocol" in err.args[ 1]: if must: logger.error( cipher + " wird nicht unterstützt aber von der Checkliste gefordert" ) else: logger.info( cipher + " wird nicht unterstützt. Das scheint OK zu sein." ) # DH Key zu klein elif "dh key too small" in err.args[1]: logger.warn(cipher + " " + err.args[1]) # sonstiger Grund else: logger.warn(cipher + " verursacht einen Verbindungsfehler") print(err.args[1]) if len(err.args) == 1: if must: logger.error( cipher + " wird nicht unterstützt aber von der Checkliste gefordert" ) else: logger.info( cipher + " wird nicht unterstützt. Das scheint OK zu sein.") # socket Fehler except socket.error as err: if must: logger.error( cipher + " wird nicht unterstützt aber von der Checkliste gefordert" ) else: logger.info( cipher + " wird nicht unterstützt. Das scheint OK zu sein.")