def verify_callback( conn: SSL.Connection, x509: SSL.X509, errno: int, depth: int, is_cert_verified: bool ) -> bool: if is_cert_verified and depth == 0 and not sni: conn.cert_error = exceptions.InvalidCertificateException( f"Certificate verification error for {address}: Cannot validate hostname, SNI missing." ) is_cert_verified = False elif is_cert_verified: pass else: conn.cert_error = exceptions.InvalidCertificateException( "Certificate verification error for {}: {} (errno: {}, depth: {})".format( sni, SSL._ffi.string(SSL._lib.X509_verify_cert_error_string(errno)).decode(), errno, depth ) ) # SSL_VERIFY_NONE: The handshake will be continued regardless of the verification result. return is_cert_verified
def verify_callback( conn: SSL.Connection, x509: SSL.X509, errno: int, depth: int, is_cert_verified: bool ) -> bool: if is_cert_verified and depth == 0: # Verify hostname of leaf certificate. cert = certs.Cert(x509) try: crt: typing.Dict[str, typing.Any] = dict( subjectAltName=[("DNS", x.decode("ascii", "strict")) for x in cert.altnames] ) if cert.cn: crt["subject"] = [[["commonName", cert.cn.decode("ascii", "strict")]]] if sni: # SNI hostnames allow support of IDN by using ASCII-Compatible Encoding # Conversion algorithm is in RFC 3490 which is implemented by idna codec # https://docs.python.org/3/library/codecs.html#text-encodings # https://tools.ietf.org/html/rfc6066#section-3 # https://tools.ietf.org/html/rfc4985#section-3 hostname = sni.encode("idna").decode("ascii") else: hostname = "no-hostname" match_hostname(crt, hostname) except (ValueError, CertificateError) as e: conn.cert_error = exceptions.InvalidCertificateException( "Certificate verification error for {}: {}".format( sni or repr(address), str(e) ) ) is_cert_verified = False elif is_cert_verified: pass else: conn.cert_error = exceptions.InvalidCertificateException( "Certificate verification error for {}: {} (errno: {}, depth: {})".format( sni, SSL._ffi.string(SSL._lib.X509_verify_cert_error_string(errno)).decode(), errno, depth ) ) # SSL_VERIFY_NONE: The handshake will be continued regardless of the verification result. return is_cert_verified
def verify_cert(conn, x509, errno, err_depth, is_cert_verified): if not is_cert_verified: self.ssl_verification_error = exceptions.InvalidCertificateException( "Certificate Verification Error for {}: {} (errno: {}, depth: {})" .format( sni, strutils.always_str( SSL._ffi.string( SSL._lib.X509_verify_cert_error_string( errno)), "utf8"), errno, err_depth)) return is_cert_verified
def convert_to_ssl(self, sni=None, alpn_protos=None, **sslctx_kwargs): """ cert: Path to a file containing both client cert and private key. options: A bit field consisting of OpenSSL.SSL.OP_* values verify_options: A bit field consisting of OpenSSL.SSL.VERIFY_* values ca_path: Path to a directory of trusted CA certificates prepared using the c_rehash tool ca_pemfile: Path to a PEM formatted trusted CA certificate """ verification_mode = sslctx_kwargs.get('verify_options', None) if verification_mode == SSL.VERIFY_PEER and not sni: raise exceptions.TlsException( "Cannot validate certificate hostname without SNI") context = self.create_ssl_context(alpn_protos=alpn_protos, sni=sni, **sslctx_kwargs) self.connection = SSL.Connection(context, self.connection) if sni: self.sni = sni self.connection.set_tlsext_host_name(sni.encode("idna")) self.connection.set_connect_state() try: self.connection.do_handshake() except SSL.Error as v: if self.ssl_verification_error: raise self.ssl_verification_error else: raise exceptions.TlsException("SSL handshake error: %s" % repr(v)) self.cert = certs.SSLCert(self.connection.get_peer_certificate()) # Keep all server certificates in a list for i in self.connection.get_peer_cert_chain(): self.server_certs.append(certs.SSLCert(i)) # Validate TLS Hostname try: crt = dict(subjectAltName=[("DNS", x.decode("ascii", "strict")) for x in self.cert.altnames]) if self.cert.cn: crt["subject"] = [[[ "commonName", self.cert.cn.decode("ascii", "strict") ]]] if sni: # SNI hostnames allow support of IDN by using ASCII-Compatible Encoding # Conversion algorithm is in RFC 3490 which is implemented by idna codec # https://docs.python.org/3/library/codecs.html#text-encodings # https://tools.ietf.org/html/rfc6066#section-3 # https://tools.ietf.org/html/rfc4985#section-3 hostname = sni.encode("idna").decode("ascii") else: hostname = "no-hostname" match_hostname(crt, hostname) except (ValueError, CertificateError) as e: self.ssl_verification_error = exceptions.InvalidCertificateException( "Certificate Verification Error for {}: {}".format( sni or repr(self.address), str(e))) if verification_mode == SSL.VERIFY_PEER: raise self.ssl_verification_error self.ssl_established = True self.rfile.set_descriptor(self.connection) self.wfile.set_descriptor(self.connection)
def convert_to_ssl(self, sni=None, alpn_protos=None, **sslctx_kwargs): """ cert: Path to a file containing both client cert and private key. options: A bit field consisting of OpenSSL.SSL.OP_* values verify_options: A bit field consisting of OpenSSL.SSL.VERIFY_* values ca_path: Path to a directory of trusted CA certificates prepared using the c_rehash tool ca_pemfile: Path to a PEM formatted trusted CA certificate """ verification_mode = sslctx_kwargs.get('verify_options', None) if verification_mode == SSL.VERIFY_PEER and not sni: raise exceptions.TlsException( "Cannot validate certificate hostname without SNI") context = self.create_ssl_context(alpn_protos=alpn_protos, sni=sni, **sslctx_kwargs) self.connection = SSL.Connection(context, self.connection) if sni: self.sni = sni self.connection.set_tlsext_host_name(sni.encode("idna")) self.connection.set_connect_state() try: self.connection.do_handshake() except SSL.Error as v: if self.ssl_verification_error: raise self.ssl_verification_error else: raise exceptions.TlsException("SSL handshake error: %s" % repr(v)) else: # Fix for pre v1.0 OpenSSL, which doesn't throw an exception on # certificate validation failure if verification_mode == SSL.VERIFY_PEER and self.ssl_verification_error: raise self.ssl_verification_error self.cert = certs.SSLCert(self.connection.get_peer_certificate()) # Keep all server certificates in a list for i in self.connection.get_peer_cert_chain(): self.server_certs.append(certs.SSLCert(i)) # Validate TLS Hostname try: crt = dict(subjectAltName=[("DNS", x.decode("ascii", "strict")) for x in self.cert.altnames]) if self.cert.cn: crt["subject"] = [[[ "commonName", self.cert.cn.decode("ascii", "strict") ]]] if sni: hostname = sni else: hostname = "no-hostname" match_hostname(crt, hostname) except (ValueError, CertificateError) as e: self.ssl_verification_error = exceptions.InvalidCertificateException( "Certificate Verification Error for {}: {}".format( sni or repr(self.address), str(e))) if verification_mode == SSL.VERIFY_PEER: raise self.ssl_verification_error self.ssl_established = True self.rfile.set_descriptor(self.connection) self.wfile.set_descriptor(self.connection)