Hi I'm using the python library Websockets. In developement everything was working, but on the server it crashes because it needs to use WSS. The link above gives an example how to do this:
#!/usr/bin/env python
# WSS (WS over TLS) server example, with a self-signed certificate
import asyncio
import pathlib
import ssl
import websockets
async def hello(websocket, path):
name = await websocket.recv()
print(f"< {name}")
greeting = f"Hello {name}!"
await websocket.send(greeting)
print(f"> {greeting}")
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
localhost_pem = pathlib.Path(__file__).with_name("localhost.pem")
ssl_context.load_cert_chain(localhost_pem)
start_server = websockets.serve(
hello, "localhost", 8765, ssl=ssl_context
)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
This code is straightforward enough, but I am totally lost on how to generate the file it wants (both for server and client). I've researched "creating a pem file" to no avail and have recieved all sorts of ssl errors. Can someone please explain how to create the pem file for this application? Thanks
EDIT: Per the answer I used
sudo openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
this created two files.
My server now successfully listens by doing:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
path_key = pathlib.Path(__file__).with_name("key.pem")
ssl_context.load_cert_chain(path_cert, keyfile=path_key)
print("Listening for connection...")
start_server = websockets.serve(handler, HOSTNAME, PORT, ssl=ssl_context)
The only part left I'm having issues is getting the client to connect, I try:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
ssl_context.load_cert_chain(path_cert)
async with websockets.connect(uri, ssl=ssl_context) as websocket:
But I get the error: ssl.SSLError: [SSL] PEM lib (_ssl.c:3854)
I also tried:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
path_key = pathlib.Path(__file__).with_name("key.pem")
ssl_context.load_cert_chain(path_cert, keyfile=path_key)
async with websockets.connect(uri, ssl=ssl_context) as websocket:
and get the error ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1076)
EDIT2: Per answer I tried this for the client:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.load_verify_locations()
async with websockets.connect(uri, ssl=ssl_context) as websocket:
This generates a new error: TypeError: cafile, capath and cadata cannot be all omitted
Trying the second suggestion:
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())
async with websockets.connect(uri, ssl=ssl_context) as websocket:
Generates error: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1076)
EDIT3: The final working client:
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
path_cert = pathlib.Path(__file__).with_name("cert.pem")
ssl_context.load_verify_locations(path_cert)
async with websockets.connect(uri, ssl=ssl_context) as websocket: