Tristan Neate
Tristan Neate

Reputation: 123

Python Websockets create pem file

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:

Upvotes: 3

Views: 3836

Answers (1)

Mahsa Hassankashi
Mahsa Hassankashi

Reputation: 2137

PEM file contains somethings about public key or|and private key or certificates, and it has base64-encoded bit of data. PEM means Privacy-Enhanced Mail for mail security standard. It includes header and footer lines of the form

Create PEM

How to create a self-signed PEM file

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem

How to create a PEM file from existing certificate files that form a chain (optional) Remove the password from the Private Key by following the steps listed below:

openssl rsa -in server.key -out nopassword.key

How to create a PEM file with the help of an automated script:

  1. Download NetIQ Cool Tool OpenSSL-Toolkit.

  2. Select Create Certificates | PEM with key and entire trust chain

  3. Provide the full path to the directory containing the certificate files.

  4. Provide the filenames of the following: private key public key (server crt) (conditional) password for private key (conditional) any intermediate certificate chain file(s)

You will have something like this:

-----BEGIN RSA PRIVATE KEY----- 
(Private Key: domain_name.key contents) 
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE----- 
(Primary SSL certificate: domain_name.crt contents) 
-----END CERTIFICATE----- 
-----BEGIN CERTIFICATE----- 
(Intermediate certificate: certChainCA.crt contents) 
-----END CERTIFICATE----

You can decode it:

openssl x509 -in cert.pem -text -noout

You will have something like this:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 0 (0x0)
    Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = BE, O = GnuTLS, OU = GnuTLS certificate authority, ST = Leuven, CN = GnuTLS certificate authority
        Validity
            Not Before: May 23 20:38:21 2011 GMT
            Not After : Dec 22 07:41:51 2012 GMT
        Subject: C = BE, O = GnuTLS, OU = GnuTLS certificate authority, ST = Leuven, CN = GnuTLS certificate authority
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:52:d8:8d:23:8a:e3:67:d7:86:36:b1:20:0b:09:
                    7d:c8:c9:ba:a2:20:95:2f:c5:4a:63:fa:83:5f:ce:
                    78:2f:8f:f3:62:ca:fd:b7:f7:80:56:9d:6e:17:b9:
                    0e:11:4c:48:b2:c0:af:3b:59:17:16:30:68:09:07:
                    99:17:fe:dd:a7
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Subject Key Identifier: 
                F0:B4:81:FE:98:12:BF:B5:28:B9:64:40:03:CB:CC:1F:66:4E:28:03
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:31:ae:c0:3d:4a:3f:21:be:85:17:fc:f0:c7:b2:
         31:07:2a:38:56:43:d1:36:d5:95:e1:7e:52:c0:06:43:87:a7:
         02:21:00:97:8c:0e:b8:3c:0a:41:af:ae:a5:cf:06:7e:d5:c4:
         d8:2f:ff:e2:62:80:34:10:ba:22:dd:35:81:46:93:22:9a

Create PEM File

For client section you wrote:

ssl_context.load_cert_chain(path_cert, keyfile=path_key)

Replace it:

import json
import asyncio
import websockets
import ssl
import certifi


ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())


query =  {
    "jsonrpc": "2.0",
    "method": "queryHeadsets",
    "params": {},
    "id": 1
    }
json = json.dumps(query)

async def query(json):

    async with websockets.connect("wss://yourserver.com:54321", ssl=ssl_context) as ws:
        await ws.send(json)
        response = await ws.recv()
        print(response)

asyncio.get_event_loop().run_until_complete(query(json))

Upvotes: 3

Related Questions