def _verify_cert(self, sock: ssl.SSLSocket): '''Check if certificate matches hostname.''' # Based on tornado.iostream.SSLIOStream # Needed for older OpenSSL (<0.9.8f) versions verify_mode = self._ssl_context.verify_mode assert verify_mode in (ssl.CERT_NONE, ssl.CERT_REQUIRED, ssl.CERT_OPTIONAL), \ 'Unknown verify mode {}'.format(verify_mode) if verify_mode == ssl.CERT_NONE: return cert = sock.getpeercert() if not cert and verify_mode == ssl.CERT_OPTIONAL: return if not cert: raise SSLVerificationError('No SSL certificate given') try: ssl.match_hostname(cert, self._hostname) except ssl.CertificateError as error: raise SSLVerificationError('Invalid SSL certificate') from error
def get_certificate(ssl_socket: ssl.SSLSocket): """ Gather a certificate in a der binary format. :param ssl_socket: secured socket :return: gathered certificate """ certificate_pem = bytes(ssl_socket.getpeercert(binary_form=True)) return x509.load_der_x509_certificate(certificate_pem, default_backend())
def connect(self): msg = 'getaddrinfo returns an empty list' for af, socktype, proto, canonname, addr in getaddrinfo(self.host, self.port, 0, SOCK_STREAM): try: _log.debug('ValidatingHTTPSConnection to %r', addr) ssl = SSLSocket(socket(af, socktype, proto), keyfile=self.key_file, certfile=self.cert_file, cert_reqs=self.cert_reqs, ca_certs=self.ca_certs, ssl_version=self.ssl_version) ssl.connect(addr) except SocketError as e: _log.info('ValidatingHTTPSConnection to %r: %s', addr, e) msg = e self.sock = None continue server_attrs = ssl.getpeercert() # getpeercert() returns {} if the certificate was not verified, in # which case it doesn't matter what the name in the certificate is. if self.check_hostname and server_attrs: self.hostname_matches_cert = False names = [] for gntype, gn in server_attrs.get('subjectAltName', ()): if gntype == 'DNS': self._compare_hostname(gn) names.append(gn) else: _log.warn('ValidatingHTTPSConnection unhandled subjectAltName type: %s=%r', gntype, gn) # Only look at attributes in the first rdn. for attr,val in server_attrs['subject'][0]: if attr == 'commonName': self._cmp_hostname(val) names.append(val) if not self.hostname_matches_cert: raise CertNameMismatchError(self.host, names) # Newer ssl object implements makefile, fileno, etc. No need to # use FakeSocket wrapper self.sock = ssl break if not self.sock: raise SocketError(msg)
def _update_results(self, context: ssl.SSLContext, ssock: ssl.SSLSocket, success: bool): self.results['ssl.success'] = success cert = ssock.getpeercert() if success else None self.results['ssl.con.cert'] = cert self.results['ssl.con.cipher'], self.results[ 'ssl.con.protocol'], self.results[ 'ssl.con.secret_bits'] = ssock.cipher() or (None, None, None) self.results['ssl.con.compression'] = ssock.compression() or None self.results['ssl.con.alpn_protocol'] = ssock.selected_alpn_protocol( ) or None self.results['ssl.con.npn_protocol'] = ssock.selected_npn_protocol( ) or None self.results['ssl.con.ssl_version'] = ssock.version() or None self.results['ssl.con.server_hostname'] = ssock.server_hostname or None self.results[ 'ssl.con.cert.matches_hostname'] = True if cert is not None and ssl.match_hostname( cert, self.host) else False