I have set up an http server on my local host. I can connect to it securely using the Python requests library but when I try to do so using TLSSocket, the connection is not completed. I cannot tell why but I suspect it’s my certificate
Note that the code is correct for connecting to a remote server (I’ve been using it that way for a while but now I need to replace the remote with a local server for testing) so I think the code is correct but my certificate is wrong.
Here’s how I set it up:
certauth myrootca.pem --hostname "localhost" -d ./certs_dir
This created two files:
myrootca.pem
./certs_dir/localhost.pem
effectively creating my own CA as well as a server private key/public certificate pair.
Each of these files contain two sets of data. One set is surrounded by
-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----
and the other is surrounded by
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
I can just run with these files but I chose to separate them into two files: a .key file (for PRIVATE KEY) and a .crt file (for CERTIFICATE) to create
myrootca.key
myrootca.crt
./certs_dir/localhost.key
./certs_dir/localhost.crt
From what I’ve understood from what I’ve read…
The server
- Sends the public certificate to the client when trying to create a connection
- The certificate contains its public key
- The certificate also contains a signature that was created using the CA private key
The client:
- uses the CA public certificate to verify the signature in the server certificate
- the CA cert can be used to do this since it contains the public key corresponding to the CA private key used to create the signature
- can use the server public key (once verified) to encrypt the handshake used to establish a secure connection
Then I started an http server using uwsgi:
uwsgi --master --https-socket localhost:5683,./certs_dir/localhost.crt,./certs_dir/localhost.key --mount /=server:app
which relies on server.py:
from flask import Flask, send_from_directory
app = Flask(__name__)
@app.route("/<path:path>")
def get_root(path):
return send_from_directory('.', path)
In a different terminal, I then ran:
python3 client.py myrootca.crt testfile
and here are the contents of client.py
# client.py
import requests
import sys
def get_file(fname):
url = "https://localhost:5683/{}".format(fname)
response = requests.get(url,
verify=sys.argv[1])
print(f"{response.text}")
if __name__ == "__main__":
get_file(sys.argv[2])
And then the contents of testfile are dumped to the terminal.
I also ran
openssl verify -CAfile ../myrootca.pem localhost.pem
which returns
localhost.pem: OK
to verify that my certificate was correct. Everything seems to be going well.
Then I plugged in the contents of myrootca.crt into my code. I believe the salient calls are as follows:
TLSSocket socket
nsapi_error_t network_error;
network_error = socket->open(WiFiInterface::get_default_instance());
if (network_error != NSAPI_ERROR_OK){
INET_OTA_LOG("failed to open socket\n");
return inet_ota_client_error_network;
}
ParsedUrl parsed_url = ParsedUrl(server_url);
char *expected_schema = "https";
if (strcmp(parsed_url.schema(), expected_schema) != 0){
INET_OTA_LOG("expected https based ota url\n");
return inet_ota_client_error_unknown;
}
if (parsed_url.host() == NULL || parsed_url.host()[0] == '\0'){
INET_OTA_LOG("failed to parse host\n");
return inet_ota_client_error_unknown;
}
This is where my CA certificate comes in (myrootca.crt). I’ve also tried using localhost.crt. I’ve tried with and without newlines but it doesn’t seem to work since the subsequent connect calls fails.
network_error = socket->set_root_ca_cert(server_cert);
if (network_error != NSAPI_ERROR_OK){
INET_OTA_LOG("bad server cert\n");
return inet_ota_client_error_unknown;
}
size_t desired_tls_mfl = 4096;
unsigned char desired_tls_mfl_mbed_code = MBEDTLS_SSL_MAX_FRAG_LEN_4096;
mbedtls_ssl_config* ssl_config = socket->get_ssl_config();
int mfl_res = mbedtls_ssl_conf_max_frag_len(ssl_config, desired_tls_mfl_mbed_code);
if (mfl_res != 0){
INET_OTA_LOG("failed to set tls mfl\n");
return inet_ota_client_error_unknown;
}
INET_OTA_LOG("connecting to host: %s port:%u\n", parsed_url.host(), parsed_url.port());
socket->set_timeout(20000); // 20s
This is where the code gets stuck and the error is reported
network_error = socket->connect(parsed_url.host(), parsed_url.port());
if (network_error != NSAPI_ERROR_OK) {
INET_OTA_LOG("socket connect error %d\n", network_error);
return inet_ota_client_error_network;
}
return inet_ota_client_error_none;
Did I use the correct certificates/keys? What else am I doing wrong?