|
@ -122,49 +122,67 @@ class Interface(PrintError): |
|
|
return False |
|
|
return False |
|
|
return True |
|
|
return True |
|
|
|
|
|
|
|
|
@aiosafe |
|
|
async def _try_saving_ssl_cert_for_first_time(self, ca_ssl_context): |
|
|
async def run(self): |
|
|
try: |
|
|
if self.protocol != 's': |
|
|
ca_signed = await self.is_server_ca_signed(ca_ssl_context) |
|
|
await self.open_session(None, exit_early=False) |
|
|
except (ConnectionRefusedError, socket.gaierror, aiorpcx.socks.SOCKSFailure) as e: |
|
|
assert False |
|
|
self.print_error('disconnecting due to: {}'.format(e)) |
|
|
|
|
|
self.exception = e |
|
|
|
|
|
return False |
|
|
|
|
|
if ca_signed: |
|
|
|
|
|
with open(self.cert_path, 'w') as f: |
|
|
|
|
|
# empty file means this is CA signed, not self-signed |
|
|
|
|
|
f.write('') |
|
|
|
|
|
else: |
|
|
|
|
|
await self.save_certificate() |
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
ca_sslc = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) |
|
|
def _is_saved_ssl_cert_available(self): |
|
|
exists = os.path.exists(self.cert_path) |
|
|
if not os.path.exists(self.cert_path): |
|
|
if exists: |
|
|
return False |
|
|
with open(self.cert_path, 'r') as f: |
|
|
with open(self.cert_path, 'r') as f: |
|
|
contents = f.read() |
|
|
contents = f.read() |
|
|
if contents != '': # if not CA signed |
|
|
if contents == '': # CA signed |
|
|
|
|
|
return True |
|
|
|
|
|
# pinned self-signed cert |
|
|
try: |
|
|
try: |
|
|
b = pem.dePem(contents, 'CERTIFICATE') |
|
|
b = pem.dePem(contents, 'CERTIFICATE') |
|
|
except SyntaxError: |
|
|
except SyntaxError: |
|
|
exists = False |
|
|
self.print_error("error parsing already saved cert:", e) |
|
|
else: |
|
|
return False |
|
|
|
|
|
try: |
|
|
x = x509.X509(b) |
|
|
x = x509.X509(b) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
self.print_error("error parsing already saved cert:", e) |
|
|
|
|
|
return False |
|
|
try: |
|
|
try: |
|
|
x.check_date() |
|
|
x.check_date() |
|
|
|
|
|
return True |
|
|
except x509.CertificateError as e: |
|
|
except x509.CertificateError as e: |
|
|
self.print_error("certificate problem", e) |
|
|
self.print_error("certificate has expired:", e) |
|
|
os.unlink(self.cert_path) |
|
|
os.unlink(self.cert_path) |
|
|
exists = False |
|
|
return False |
|
|
if not exists: |
|
|
|
|
|
try: |
|
|
@aiosafe |
|
|
ca_signed = await self.is_server_ca_signed(ca_sslc) |
|
|
async def run(self): |
|
|
except (ConnectionRefusedError, socket.gaierror, aiorpcx.socks.SOCKSFailure) as e: |
|
|
if self.protocol != 's': |
|
|
self.print_error('disconnecting due to: {}'.format(e)) |
|
|
await self.open_session(None, exit_early=False) |
|
|
self.exception = e |
|
|
assert False |
|
|
|
|
|
|
|
|
|
|
|
ca_sslc = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) |
|
|
|
|
|
if not self._is_saved_ssl_cert_available(): |
|
|
|
|
|
done_saving_cert = await self._try_saving_ssl_cert_for_first_time(ca_sslc) |
|
|
|
|
|
if not done_saving_cert: |
|
|
return |
|
|
return |
|
|
if ca_signed: |
|
|
|
|
|
with open(self.cert_path, 'w') as f: |
|
|
|
|
|
# empty file means this is CA signed, not self-signed |
|
|
|
|
|
f.write('') |
|
|
|
|
|
else: |
|
|
|
|
|
await self.save_certificate() |
|
|
|
|
|
siz = os.stat(self.cert_path).st_size |
|
|
siz = os.stat(self.cert_path).st_size |
|
|
if siz == 0: # if CA signed |
|
|
if siz == 0: |
|
|
|
|
|
# CA signed cert |
|
|
sslc = ca_sslc |
|
|
sslc = ca_sslc |
|
|
else: |
|
|
else: |
|
|
|
|
|
# pinned self-signed cert |
|
|
sslc = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=self.cert_path) |
|
|
sslc = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=self.cert_path) |
|
|
sslc.check_hostname = 0 |
|
|
sslc.check_hostname = 0 |
|
|
|
|
|
# start main connection |
|
|
try: |
|
|
try: |
|
|
await self.open_session(sslc, exit_early=False) |
|
|
await self.open_session(sslc, exit_early=False) |
|
|
except (asyncio.CancelledError, ConnectionRefusedError, socket.gaierror, |
|
|
except (asyncio.CancelledError, ConnectionRefusedError, socket.gaierror, |
|
|