Skip to content

Commit af7e489

Browse files
tveme-no-dev
authored andcommitted
WiFiClientSecure: add support for PSK (pre-shared key) ciphers (#2133)
* WiFiClientSecure: add support for PSK (pre-shared key) ciphers * add example for WiFiClientSecure PSK * WiFiClientSecure: added README
1 parent 5cfff19 commit af7e489

File tree

6 files changed

+220
-3
lines changed

6 files changed

+220
-3
lines changed

Diff for: libraries/WiFiClientSecure/README.md

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
WiFiClientSecure
2+
================
3+
4+
The WiFiClientSecure class implements support for secure connections using TLS (SSL).
5+
It inherits from WiFiClient and thus implements a superset of that class' interface.
6+
There are three ways to establish a secure connection using the WiFiClientSecure class:
7+
using a root certificate authority (CA) cert, using a root CA cert plus a client cert and key,
8+
and using a pre-shared key (PSK).
9+
10+
Using a root certificate authority cert
11+
---------------------------------------
12+
This method authenticates the server and negotiates an encrypted connection.
13+
It is the same functionality as implemented in your web browser when you connect to HTTPS sites.
14+
15+
If you are accessing your own server:
16+
- Generate a root certificate for your own certificate authority
17+
- Generate a cert & private key using your root certificate ("self-signed cert") for your server
18+
If you are accessing a public server:
19+
- Obtain the cert of the public CA that signed that server's cert
20+
Then:
21+
- In WiFiClientSecure use setCACert (or the appropriate connect method) to set the root cert of your
22+
CA or of the public CA
23+
- When WiFiClientSecure connects to the target server it uses the CA cert to verify the certificate
24+
presented by the server, and then negotiates encryption for the connection
25+
26+
Please see the WiFiClientSecure example.
27+
28+
Using a root CA cert and client cert/keys
29+
-----------------------------------------
30+
This method authenticates the server and additionally also authenticates
31+
the client to the server, then negotiates an encrypted connection.
32+
33+
- Follow steps above
34+
- Using your root CA generate cert/key for your client
35+
- Register the keys with the server you will be accessing so the server can authenticate your client
36+
- In WiFiClientSecure use setCACert (or the appropriate connect method) to set the root cert of your
37+
CA or of the public CA, this is used to authenticate the server
38+
- In WiFiClientSecure use setCertificate, and setPrivateKey (or the appropriate connect method) to
39+
set your client's cert & key, this will be used to authenticate your client to the server
40+
- When WiFiClientSecure connects to the target server it uses the CA cert to verify the certificate
41+
presented by the server, it will use the cert/key to authenticate your client to the server, and
42+
it will then negotiate encryption for the connection
43+
44+
Using Pre-Shared Keys (PSK)
45+
---------------------------
46+
47+
TLS supports authentication and encryption using a pre-shared key (i.e. a key that both client and
48+
server know) as an alternative to the public key cryptography commonly used on the web for HTTPS.
49+
PSK is starting to be used for MQTT, e.g. in mosquitto, to simplify the set-up and avoid having to
50+
go through the whole CA, cert, and private key process.
51+
52+
A pre-shared key is a binary string of up to 32 bytes and is commonly represented in hex form. In
53+
addition to the key, clients can also present an id and typically the server allows a different key
54+
to be associated with each client id. In effect this is very similar to username and password pairs,
55+
except that unlike a password the key is not directly transmitted to the server, thus a connection to a
56+
malicious server does not divulge the password. Plus the server is also authenticated to the client.
57+
58+
To use PSK:
59+
- Generate a random hex string (generating an MD5 or SHA for some file is one way to do this)
60+
- Come up with a string id for your client and configure your server to accept the id/key pair
61+
- In WiFiClientSecure use setPreSharedKey (or the appropriate connect method) to
62+
set the id/key combo
63+
- When WiFiClientSecure connects to the target server it uses the id/key combo to authenticate the
64+
server (it must prove that it has the key too), authenticate the client and then negotiate
65+
encryption for the connection
66+
67+
Please see the WiFiClientPSK example.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
Wifi secure connection example for ESP32 using a pre-shared key (PSK)
3+
This is useful with MQTT servers instead of using a self-signed cert, tested with mosquitto.
4+
Running on TLS 1.2 using mbedTLS
5+
6+
To test run a test server using: openssl s_server -accept 8443 -psk 1a2b3c4d -nocert
7+
It will show the http request made, but there's no easy way to send a reply back...
8+
9+
2017 - Evandro Copercini - Apache 2.0 License.
10+
2018 - Adapted for PSK by Thorsten von Eicken
11+
*/
12+
13+
#include <WiFiClientSecure.h>
14+
15+
#if 0
16+
const char* ssid = "your-ssid"; // your network SSID (name of wifi network)
17+
const char* password = "your-password"; // your network password
18+
#else
19+
const char* ssid = "test"; // your network SSID (name of wifi network)
20+
const char* password = "securetest"; // your network password
21+
#endif
22+
23+
//const char* server = "server.local"; // Server hostname
24+
const IPAddress server = IPAddress(192, 168, 0, 14); // Server IP address
25+
const int port = 8443; // server's port (8883 for MQTT)
26+
27+
const char* pskIdent = "Client_identity"; // PSK identity (sometimes called key hint)
28+
const char* psKey = "1a2b3c4d"; // PSK Key (must be hex string without 0x)
29+
30+
WiFiClientSecure client;
31+
32+
void setup() {
33+
//Initialize serial and wait for port to open:
34+
Serial.begin(115200);
35+
delay(100);
36+
37+
Serial.print("Attempting to connect to SSID: ");
38+
Serial.println(ssid);
39+
WiFi.begin(ssid, password);
40+
41+
// attempt to connect to Wifi network:
42+
while (WiFi.status() != WL_CONNECTED) {
43+
Serial.print(".");
44+
// wait 1 second for re-trying
45+
delay(1000);
46+
}
47+
48+
Serial.print("Connected to ");
49+
Serial.println(ssid);
50+
51+
client.setPreSharedKey(pskIdent, psKey);
52+
53+
Serial.println("\nStarting connection to server...");
54+
if (!client.connect(server, port))
55+
Serial.println("Connection failed!");
56+
else {
57+
Serial.println("Connected to server!");
58+
// Make a HTTP request:
59+
client.println("GET /a/check HTTP/1.0");
60+
client.print("Host: ");
61+
client.println(server);
62+
client.println("Connection: close");
63+
client.println();
64+
65+
while (client.connected()) {
66+
String line = client.readStringUntil('\n');
67+
if (line == "\r") {
68+
Serial.println("headers received");
69+
break;
70+
}
71+
}
72+
// if there are incoming bytes available
73+
// from the server, read them and print them:
74+
while (client.available()) {
75+
char c = client.read();
76+
Serial.write(c);
77+
}
78+
79+
client.stop();
80+
}
81+
}
82+
83+
void loop() {
84+
// do nothing
85+
}

Diff for: libraries/WiFiClientSecure/src/WiFiClientSecure.cpp

+31-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ WiFiClientSecure::WiFiClientSecure()
3939
_CA_cert = NULL;
4040
_cert = NULL;
4141
_private_key = NULL;
42+
_pskIdent = NULL;
43+
_psKey = NULL;
4244
next = NULL;
4345
}
4446

@@ -59,6 +61,8 @@ WiFiClientSecure::WiFiClientSecure(int sock)
5961
_CA_cert = NULL;
6062
_cert = NULL;
6163
_private_key = NULL;
64+
_pskIdent = NULL;
65+
_psKey = NULL;
6266
next = NULL;
6367
}
6468

@@ -89,11 +93,15 @@ void WiFiClientSecure::stop()
8993

9094
int WiFiClientSecure::connect(IPAddress ip, uint16_t port)
9195
{
96+
if (_pskIdent && _psKey)
97+
return connect(ip, port, _pskIdent, _psKey);
9298
return connect(ip, port, _CA_cert, _cert, _private_key);
9399
}
94100

95101
int WiFiClientSecure::connect(const char *host, uint16_t port)
96102
{
103+
if (_pskIdent && _psKey)
104+
return connect(host, port, _pskIdent, _psKey);
97105
return connect(host, port, _CA_cert, _cert, _private_key);
98106
}
99107

@@ -104,7 +112,24 @@ int WiFiClientSecure::connect(IPAddress ip, uint16_t port, const char *_CA_cert,
104112

105113
int WiFiClientSecure::connect(const char *host, uint16_t port, const char *_CA_cert, const char *_cert, const char *_private_key)
106114
{
107-
int ret = start_ssl_client(sslclient, host, port, _CA_cert, _cert, _private_key);
115+
int ret = start_ssl_client(sslclient, host, port, _CA_cert, _cert, _private_key, NULL, NULL);
116+
_lastError = ret;
117+
if (ret < 0) {
118+
log_e("start_ssl_client: %d", ret);
119+
stop();
120+
return 0;
121+
}
122+
_connected = true;
123+
return 1;
124+
}
125+
126+
int WiFiClientSecure::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) {
127+
return connect(ip.toString().c_str(), port,_pskIdent, _psKey);
128+
}
129+
130+
int WiFiClientSecure::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) {
131+
log_v("start_ssl_client with PSK");
132+
int ret = start_ssl_client(sslclient, host, port, NULL, NULL, NULL, _pskIdent, _psKey);
108133
_lastError = ret;
109134
if (ret < 0) {
110135
log_e("start_ssl_client: %d", ret);
@@ -223,6 +248,11 @@ void WiFiClientSecure::setPrivateKey (const char *private_key)
223248
_private_key = private_key;
224249
}
225250

251+
void WiFiClientSecure::setPreSharedKey(const char *pskIdent, const char *psKey) {
252+
_pskIdent = pskIdent;
253+
_psKey = psKey;
254+
}
255+
226256
bool WiFiClientSecure::verify(const char* fp, const char* domain_name)
227257
{
228258
if (!sslclient)

Diff for: libraries/WiFiClientSecure/src/WiFiClientSecure.h

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class WiFiClientSecure : public WiFiClient
3535
const char *_CA_cert;
3636
const char *_cert;
3737
const char *_private_key;
38+
const char *_pskIdent; // identity for PSK cipher suites
39+
const char *_psKey; // key in hex for PSK cipher suites
3840

3941
public:
4042
WiFiClientSecure *next;
@@ -45,6 +47,8 @@ class WiFiClientSecure : public WiFiClient
4547
int connect(const char *host, uint16_t port);
4648
int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
4749
int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
50+
int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey);
51+
int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey);
4852
int peek();
4953
size_t write(uint8_t data);
5054
size_t write(const uint8_t *buf, size_t size);
@@ -55,6 +59,7 @@ class WiFiClientSecure : public WiFiClient
5559
void stop();
5660
uint8_t connected();
5761
int lastError(char *buf, const size_t size);
62+
void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex
5863
void setCACert(const char *rootCA);
5964
void setCertificate(const char *client_ca);
6065
void setPrivateKey (const char *private_key);

Diff for: libraries/WiFiClientSecure/src/ssl_client.cpp

+31-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ void ssl_init(sslclient_context *ssl_client)
4545
}
4646

4747

48-
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key)
48+
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey)
4949
{
5050
char buf[512];
5151
int ret, flags, timeout;
@@ -116,6 +116,36 @@ int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t p
116116
if (ret < 0) {
117117
return handle_error(ret);
118118
}
119+
} else if (pskIdent != NULL && psKey != NULL) {
120+
log_v("Setting up PSK");
121+
// convert PSK from hex to binary
122+
if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2*MBEDTLS_PSK_MAX_LEN) {
123+
log_e("pre-shared key not valid hex or too long");
124+
return -1;
125+
}
126+
unsigned char psk[MBEDTLS_PSK_MAX_LEN];
127+
size_t psk_len = strlen(psKey)/2;
128+
for (int j=0; j<strlen(psKey); j+= 2) {
129+
char c = psKey[j];
130+
if (c >= '0' && c <= '9') c -= '0';
131+
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
132+
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
133+
else return -1;
134+
psk[j/2] = c<<4;
135+
c = psKey[j+1];
136+
if (c >= '0' && c <= '9') c -= '0';
137+
else if (c >= 'A' && c <= 'F') c -= 'A' - 10;
138+
else if (c >= 'a' && c <= 'f') c -= 'a' - 10;
139+
else return -1;
140+
psk[j/2] |= c;
141+
}
142+
// set mbedtls config
143+
ret = mbedtls_ssl_conf_psk(&ssl_client->ssl_conf, psk, psk_len,
144+
(const unsigned char *)pskIdent, strlen(pskIdent));
145+
if (ret != 0) {
146+
log_e("mbedtls_ssl_conf_psk returned %d", ret);
147+
return handle_error(ret);
148+
}
119149
} else {
120150
mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE);
121151
log_i("WARNING: Use certificates for a more secure communication!");

Diff for: libraries/WiFiClientSecure/src/ssl_client.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ typedef struct sslclient_context {
2929

3030

3131
void ssl_init(sslclient_context *ssl_client);
32-
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key);
32+
int start_ssl_client(sslclient_context *ssl_client, const char *host, uint32_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey);
3333
void stop_ssl_socket(sslclient_context *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key);
3434
int data_to_read(sslclient_context *ssl_client);
3535
int send_ssl_data(sslclient_context *ssl_client, const uint8_t *data, uint16_t len);

0 commit comments

Comments
 (0)