Skip to content

Commit 3ef1d37

Browse files
committed
SocketWrapper: implement SSLClient
connect() temporarily accepts a third parameter with a PEM encoded certificate Cleanest way to add it is via raw strings const char * certificate = R"(-----BEGIN CERTIFICATE----- .... -----END CERTIFICATE-----)";
1 parent 83cc65e commit 3ef1d37

File tree

3 files changed

+124
-2
lines changed

3 files changed

+124
-2
lines changed

Diff for: libraries/SocketWrapper/SocketWrapper.h

+94-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
#pragma once
22

3+
#include "zephyr/sys/printk.h"
4+
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
5+
#include <zephyr/net/tls_credentials.h>
6+
#define CA_CERTIFICATE_TAG 1
7+
#endif
8+
39
#include <zephyr/net/socket.h>
410

511
class ZephyrSocketWrapper {
612
protected:
713
int sock_fd;
14+
bool is_ssl = false;
15+
int ssl_sock_temp_char = -1;
816

917
public:
1018
ZephyrSocketWrapper() : sock_fd(-1) {}
@@ -33,6 +41,8 @@ class ZephyrSocketWrapper {
3341

3442
if (ret == 0) {
3543
break;
44+
} else {
45+
k_sleep(K_MSEC(1));
3646
}
3747
}
3848

@@ -77,11 +87,86 @@ class ZephyrSocketWrapper {
7787
return true;
7888
}
7989

90+
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
91+
bool connectSSL(const char* host, uint16_t port, char* ca_certificate_pem = nullptr) {
92+
93+
// Resolve address
94+
struct addrinfo hints;
95+
struct addrinfo *res;
96+
97+
hints.ai_family = AF_INET;
98+
hints.ai_socktype = SOCK_STREAM;
99+
100+
int resolve_attempts = 100;
101+
int ret;
102+
103+
while (resolve_attempts--) {
104+
ret = getaddrinfo(host, String(port).c_str(), &hints, &res);
105+
106+
if (ret == 0) {
107+
break;
108+
} else {
109+
k_sleep(K_MSEC(1));
110+
}
111+
}
112+
113+
if (ret != 0) {
114+
return false;
115+
}
116+
117+
if (ca_certificate_pem != nullptr) {
118+
ret = tls_credential_add(CA_CERTIFICATE_TAG, TLS_CREDENTIAL_CA_CERTIFICATE,
119+
ca_certificate_pem, strlen(ca_certificate_pem) + 1);
120+
Serial.println(ret);
121+
}
122+
123+
sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TLS_1_2);
124+
if (sock_fd < 0) {
125+
return false;
126+
}
127+
128+
sec_tag_t sec_tag_opt[] = {
129+
CA_CERTIFICATE_TAG,
130+
};
131+
setsockopt(sock_fd, SOL_TLS, TLS_SEC_TAG_LIST,
132+
sec_tag_opt, sizeof(sec_tag_opt));
133+
134+
setsockopt(sock_fd, SOL_TLS, TLS_HOSTNAME, host, strlen(host));
135+
136+
uint32_t timeo_optval = 100;
137+
setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeo_optval, sizeof(timeo_optval));
138+
139+
if (::connect(sock_fd, res->ai_addr, res->ai_addrlen) < 0) {
140+
::close(sock_fd);
141+
sock_fd = -1;
142+
return false;
143+
}
144+
is_ssl = true;
145+
146+
return true;
147+
}
148+
#endif
149+
80150
int available() {
81151
int count = 0;
82-
zsock_ioctl(sock_fd, ZFD_IOCTL_FIONREAD, &count);
83-
if (count == 0) {
152+
if (is_ssl) {
153+
/*
154+
TODO: HACK:
155+
The correct colution would be to call
156+
::recv(sock_fd, &ssl_sock_temp_char, 1, MSG_PEEK | MSG_DONTWAIT);
157+
but it doesn't seem to work. Instead, save a temporary variable
158+
and use it in read()
159+
*/
160+
if (ssl_sock_temp_char != -1) {
161+
return 1;
162+
}
163+
count = ::recv(sock_fd, &ssl_sock_temp_char, 1, MSG_DONTWAIT);
164+
} else {
165+
zsock_ioctl(sock_fd, ZFD_IOCTL_FIONREAD, &count);
166+
}
167+
if (count <= 0) {
84168
delay(1);
169+
count = 0;
85170
}
86171
return count;
87172
}
@@ -90,6 +175,13 @@ class ZephyrSocketWrapper {
90175
if (sock_fd == -1) {
91176
return -1;
92177
}
178+
// TODO: see available()
179+
if (ssl_sock_temp_char != -1) {
180+
int ret = ::recv(sock_fd, &buffer[1], size - 1, flags);
181+
buffer[0] = ssl_sock_temp_char;
182+
ssl_sock_temp_char = -1;
183+
return ret + 1;
184+
}
93185
return ::recv(sock_fd, buffer, size, flags);
94186
}
95187

Diff for: libraries/SocketWrapper/ZephyrClient.h

+12
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ class ZephyrClient : public arduino::Client, ZephyrSocketWrapper {
2828
}
2929
return ret;
3030
}
31+
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
32+
int connectSSL(const char* host, uint16_t port, const char* cert) {
33+
return this->connectSSL(host, port, (char*)cert);
34+
}
35+
int connectSSL(const char* host, uint16_t port, char* cert) {
36+
auto ret = ZephyrSocketWrapper::connectSSL((char*)host, port, cert);
37+
if (ret) {
38+
_connected = true;
39+
}
40+
return ret;
41+
}
42+
#endif
3143
uint8_t connected() override {
3244
return _connected;
3345
}

Diff for: libraries/SocketWrapper/ZephyrSSLClient.h

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include "SocketWrapper.h"
2+
#include "api/Client.h"
3+
#include "unistd.h"
4+
#include "zephyr/sys/printk.h"
5+
#include "ZephyrClient.h"
6+
7+
#if defined(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
8+
class ZephyrSSLClient : public ZephyrClient {
9+
10+
public:
11+
int connect(const char* host, uint16_t port, const char* cert) {
12+
return connectSSL(host, port, (char*)cert);
13+
}
14+
int connect(const char* host, uint16_t port, char* cert) {
15+
return connectSSL(host, port, cert);
16+
}
17+
};
18+
#endif

0 commit comments

Comments
 (0)