Skip to content

Commit 478701b

Browse files
Emma Stenslandpadelsbach
authored andcommitted
F-5613: keep peer verification enabled after loading CA cert in Mynewt client
1 parent 3e274a1 commit 478701b

8 files changed

Lines changed: 388 additions & 64 deletions

mynewt/README.md

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,35 @@ including the `wolfssl` command with represents the client TLS application.
113113

114114
## Usage
115115

116+
### Run a local TLS server to connect to
117+
118+
This example uses the repo's test CA (`certs/ca-cert.pem`, embedded as `local_ca.h`).
119+
To avoid dependencies on live internet hosts, point the client at the local
120+
`tls/server-tls` example.
121+
122+
In a separate terminal, from the `wolfssl-examples` directory:
123+
124+
```
125+
$ cd tls
126+
$ make
127+
$ ./server-tls
128+
```
129+
130+
Leave this running. It handles one connection at a time.
131+
132+
### Connecting to a different target instead
133+
134+
To connect to a real host, build with `WOLFSSL_MN_USE_CUSTOM_CA`:
135+
136+
```
137+
$ newt target set wolfsslclienttlsmn_sim syscfg=WOLFSSL_MN_USE_CUSTOM_CA=1
138+
```
139+
140+
Fill in `mynewt/custom_ca.h` with your target's root CA. Set `DEFAULT_IPADDR`
141+
and `DEFAULT_PORT` in `client-tls-mn.c`, then rebuild.
142+
143+
Note: This demo pins the CA and IP address at build time. Update them manually if the target changes.
144+
116145
### Command list
117146

118147
The client TLS application `wolfssl` has the following commands:
@@ -123,28 +152,29 @@ The client TLS application `wolfssl` has the following commands:
123152
| time | "unix timestamp" | To set the time | "time 1532616682" |
124153
| net | udp | create udp socket | "net udp" |
125154
| net | tcp | create tcp socket | "net tcp" |
126-
| net | connect "ipaddress" port | connect "ipaddress" | "net connect 93.184.216.34 443" |
155+
| net | connect "ipaddress" port | connect "ipaddress" | "net connect 127.0.0.1 11111" |
127156
| net | close | close socket | "net close" |
128-
| net | send "string" "ipaddress" "port" | send string | "net send "GET \r\n" 93.184.216.34 80 |
129-
| net | recv "ipaddress" | recv from ipaddress | "net recv 93.184.216.34 80 |
157+
| net | send "string" "ipaddress" "port" | send string | "net send "hello" 127.0.0.1 11111" |
158+
| net | recv "ipaddress" | recv from ipaddress | "net recv 127.0.0.1 11111" |
130159
| wolfssl | init | initialize wolfssl library | "wolfssl init" |
131160
| wolfssl | connect | connect via ssl | "wolfssl connect" |
132-
| wolfssl | write "string" | send string via ssl | "wolfssl write "GET /"" |
161+
| wolfssl | write "string" | send string via ssl | "wolfssl write "hello wolfssl!"" |
133162
| wolfssl | read | recv via ssl | "wolfssl recv" |
134163
| wolfssl | clear | finish wolfssl library | "wolfssl clear" |
135164

136165
### Command examples
137-
Get `index.html` from `www.example.com:443` (i.e. `93.184.216.34:443`) using
138-
Mynewt TCP networking and the wolfSSL TLS and crypto.
166+
Connect to the locally-run `tls/server-tls` example (`127.0.0.1:11111`)
167+
using Mynewt TCP networking and the wolfSSL TLS and crypto. Make sure
168+
`./server-tls` (see above) is running first.
139169

140170
At the Mynewt `compat>` shell prompt:
141171

142172
```
143173
net tcp
144-
net connect 93.184.216.34 443
174+
net connect 127.0.0.1 11111
145175
wolfssl init
146176
wolfssl connect
147-
wolfssl write "GET /"
177+
wolfssl write "hello wolfssl!"
148178
wolfssl read
149179
wolfssl clear
150180
net close
@@ -155,33 +185,21 @@ The resulting application output should be similar to the following:
155185
```
156186
compat> net tcp
157187
001143 mn_socket(TCP) = 0 566b7800
158-
compat> net connect 93.184.216.34 443
159-
005078 93.184.216.34/443
188+
compat> net connect 127.0.0.1 11111
189+
005078 127.0.0.1/11111
160190
005078 mn_connect() = 0
161191
compat> net_test_writable 0 - 0
162192
wolfssl init
163193
005853 wolfssl contexts are initialized
164194
005854 wolfSSL ctx initialize
165195
compat> wolfssl connect
166196
006517 wolfSSL_connect() = 1
167-
compat> wolfssl write "GET /"
168-
009182 wolfSSL_write() = 4L
197+
compat> wolfssl write "hello wolfssl!"
198+
009182 wolfSSL_write() = 14L
169199
compat> wolfssl read
170-
010564 HTTP/1.0 501 Not Implemented
171-
Content-Type: text/html
172-
Content-Length: 357
173-
Connection: close
174-
Date: Wed, 12 Apr 2023 14:49:27 <?xml version="1.0" encoding="iso-8859-1"?>
175-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
176-
"http://wwwitle>501 - Not Implemented</title>
177-
</head>
178-
<body>
179-
<h1>501 - Not Implemented</h1>
180-
</body>
181-
</html>
200+
010564 I hear ya fa shizzle!
182201
183202
010578
184-
010578 ERROR: wolfSSL_read rc:-1 err:6
185203
compat> wolfssl clear
186204
012551 clear wolfssl contexts
187205
012553 wolfSSL ctx clear
@@ -190,8 +208,7 @@ compat> net close
190208
compat>
191209
```
192210

193-
NOTE: The server-side connection close after reception of data results in the
194-
read error.
211+
`server-tls` handles one request per connection and loops. It can be reused for repeated `wolfssl connect` runs.
195212

196213
## Notes
197214

@@ -211,6 +228,10 @@ Install:
211228
- expect
212229
- bash
213230
- screen
231+
- openssl
232+
- xxd
233+
- python3
234+
- fuser
214235
- [newt](https://mynewt.apache.org/latest/get_started/native_install/index.html)(v1.4.1 over)
215236

216237
## Usage

mynewt/apps.wolfsslclienttlsmn.pkg.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,6 @@ pkg.deps:
3636
- "@apache-mynewt-core/sys/log/full"
3737
- "@apache-mynewt-core/sys/stats/full"
3838

39-
pkg.cflags: -DWOLFSSL_APACHE_MYNEWT -Wno-error -DNO_FILESYSTEM -DWOLFSSL_IGNORE_FILE_WARN
39+
# WC_NO_HARDEN is required for native sim targets.
40+
# WOLFSSL_CUSTOM_CONFIG applies Mynewt-specific settings.
41+
pkg.cflags: -DWOLFSSL_APACHE_MYNEWT -DWOLFSSL_CUSTOM_CONFIG -DWC_NO_HARDEN -Wno-error -DNO_FILESYSTEM -DWOLFSSL_IGNORE_FILE_WARN

mynewt/apps.wolfsslclienttlsmn.syscfg.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
# Settings this app defines.
2121
syscfg.defs:
22+
WOLFSSL_MN_USE_CUSTOM_CA:
23+
description: >
24+
Use custom CA (custom_ca.h) and IP/port (client-tls-mn.c)
25+
instead of local server-tls demo.
26+
value: 0
2227

2328
# Settings this app overrides.
2429
syscfg.vals:

mynewt/client-tls-mn.c

Lines changed: 74 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,26 @@ extern time_t time(time_t*);
5353

5454
/* wolfSSL */
5555
#include <wolfssl/ssl.h>
56-
#define USE_CERT_BUFFERS_2048
57-
#include <wolfssl/certs_test.h>
5856

59-
#define DEFAULT_IPADDR "93.184.216.34" /* www.example.com */
57+
#if MYNEWT_VAL(WOLFSSL_MN_USE_CUSTOM_CA)
58+
#include "custom_ca.h"
59+
60+
/* TODO: set to your real target's current IP/port/hostname; see custom_ca.h */
61+
#define DEFAULT_IPADDR_PLACEHOLDER
62+
#ifdef DEFAULT_IPADDR_PLACEHOLDER
63+
#error "mynewt/client-tls-mn.c: set DEFAULT_IPADDR/DEFAULT_PORT/DEFAULT_HOSTNAME (in the " \
64+
"WOLFSSL_MN_USE_CUSTOM_CA branch above) to your real target's " \
65+
"current IP/port/hostname and remove this #error before building."
66+
#endif
67+
#define DEFAULT_IPADDR "0.0.0.0"
6068
#define DEFAULT_PORT 443
69+
#define DEFAULT_HOSTNAME "example.com"
70+
#else
71+
/* Generated by setup.sh from certs/ca-cert.pem. */
72+
#include "local_ca.h"
73+
#define DEFAULT_IPADDR "127.0.0.1" /* local tls/server-tls example */
74+
#define DEFAULT_PORT 11111
75+
#endif
6176

6277
struct os_sem test_sem;
6378

@@ -120,12 +135,12 @@ static const oc_handler_t omgr_oc_handler = {
120135

121136
static void net_test_readable(void *arg, int err)
122137
{
123-
console_printf("net_test_readable %x - %d\n", (int)arg, err);
138+
console_printf("net_test_readable %lx - %d\n", (unsigned long)(uintptr_t)arg, err);
124139
}
125140

126141
static void net_test_writable(void *arg, int err)
127142
{
128-
console_printf("net_test_writable %x - %d\n", (int)arg, err);
143+
console_printf("net_test_writable %lx - %d\n", (unsigned long)(uintptr_t)arg, err);
129144
}
130145

131146
static const union mn_socket_cb net_test_cbs = {
@@ -135,7 +150,7 @@ static const union mn_socket_cb net_test_cbs = {
135150

136151
static int net_test_newconn(void *arg, struct mn_socket *new)
137152
{
138-
console_printf("net_test_newconn %x - %x\n", (int)arg, (int)new);
153+
console_printf("net_test_newconn %lx - %lx\n", (unsigned long)(uintptr_t)arg, (unsigned long)(uintptr_t)new);
139154
mn_socket_set_cbs(new, NULL, &net_test_cbs);
140155
net_test_socket2 = new;
141156
return 0;
@@ -161,12 +176,12 @@ net_cli(int argc, char **argv)
161176
}
162177
if (!strcmp(argv[1], "udp")) {
163178
rc = mn_socket(&net_test_socket, MN_PF_INET, MN_SOCK_DGRAM, 0);
164-
console_printf("mn_socket(UDP) = %d %x\n", rc,
165-
(int)net_test_socket);
179+
console_printf("mn_socket(UDP) = %d %lx\n", rc,
180+
(unsigned long)(uintptr_t)net_test_socket);
166181
} else if (!strcmp(argv[1], "tcp")) {
167182
rc = mn_socket(&net_test_socket, MN_PF_INET, MN_SOCK_STREAM, 0);
168-
console_printf("mn_socket(TCP) = %d %x\n", rc,
169-
(int)net_test_socket);
183+
console_printf("mn_socket(TCP) = %d %lx\n", rc,
184+
(unsigned long)(uintptr_t)net_test_socket);
170185
} else if (!strcmp(argv[1], "connect") || !strcmp(argv[1], "bind")) {
171186
char *addrStr = DEFAULT_IPADDR;
172187
int port = DEFAULT_PORT;
@@ -389,16 +404,38 @@ static int wolfssl_ctx_init() {
389404
return -1;
390405
}
391406

392-
int ret = wolfSSL_CTX_load_verify_buffer(wolfsslCtx, ca_cert_der_2048, sizeof_ca_cert_der_2048, SSL_FILETYPE_ASN1);
407+
#if MYNEWT_VAL(WOLFSSL_MN_USE_CUSTOM_CA)
408+
int ret = wolfSSL_CTX_load_verify_buffer(wolfsslCtx, custom_ca_der, sizeof_custom_ca_der, SSL_FILETYPE_ASN1);
409+
#else
410+
int ret = wolfSSL_CTX_load_verify_buffer(wolfsslCtx, local_ca_der, sizeof_local_ca_der, SSL_FILETYPE_ASN1);
411+
#endif
393412
if(ret != SSL_SUCCESS) {
394413
console_printf("Error %d loading CA cert\n", ret);
395-
return ret;
414+
wolfSSL_CTX_free(wolfsslCtx);
415+
wolfsslCtx = NULL;
416+
return -1;
396417
}
397418

398-
wolfSSL_CTX_set_verify(wolfsslCtx, SSL_VERIFY_NONE, 0);
419+
/* Depends on bundled test CA certs not expiring. */
420+
wolfSSL_CTX_set_verify(wolfsslCtx, SSL_VERIFY_PEER, NULL);
399421
/* Create a WOLFSSL object */
400422
if ((ssl = wolfSSL_new(wolfsslCtx)) == NULL) {
401423
console_printf("ERROR: failed to create WOLFSSL object\n");
424+
wolfSSL_CTX_free(wolfsslCtx);
425+
wolfsslCtx = NULL;
426+
return -1;
427+
}
428+
429+
#if MYNEWT_VAL(WOLFSSL_MN_USE_CUSTOM_CA)
430+
if (wolfSSL_check_domain_name(ssl, DEFAULT_HOSTNAME) != SSL_SUCCESS) {
431+
#else
432+
if (wolfSSL_check_domain_name(ssl, DEFAULT_IPADDR) != SSL_SUCCESS) {
433+
#endif
434+
console_printf("ERROR: failed to set expected hostname\n");
435+
wolfSSL_free(ssl);
436+
ssl = NULL;
437+
wolfSSL_CTX_free(wolfsslCtx);
438+
wolfsslCtx = NULL;
402439
return -1;
403440
}
404441

@@ -428,13 +465,19 @@ wolfssl_cli(int argc, char **argv)
428465
const char *subCommand = argv[1];
429466

430467
if(!strcmp(subCommand, "init")) {
431-
wolfssl_ctx_init();
468+
if (wolfssl_ctx_init() != 0) {
469+
return -1;
470+
}
432471
wolfSSL_SetIO_Mynewt(ssl, net_test_socket, &net_test_sin);
433472
console_printf("wolfSSL ctx initialize\n");
434473
} else if(!strcmp(subCommand, "clear")) {
435474
wolfssl_ctx_clear();
436475
console_printf("wolfSSL ctx clear\n");
437476
} else if(!strcmp(subCommand, "connect")) {
477+
if (ssl == NULL) {
478+
console_printf("ERROR: run \"wolfssl init\" first\n");
479+
return -1;
480+
}
438481
rc = wolfSSL_connect(ssl);
439482
if(rc != SSL_SUCCESS) {
440483
err = wolfSSL_get_error(ssl, 0);
@@ -445,7 +488,11 @@ wolfssl_cli(int argc, char **argv)
445488
} else if(!strcmp(subCommand, "write")) {
446489
char *str = "GET /index.html HTTP/1.0\r\n\r\n";
447490
int len;
448-
if(argc > 3) {
491+
if (ssl == NULL) {
492+
console_printf("ERROR: run \"wolfssl init\" first\n");
493+
return -1;
494+
}
495+
if(argc > 2) {
449496
str = argv[2];
450497
}
451498
len = strlen(str);
@@ -459,14 +506,20 @@ wolfssl_cli(int argc, char **argv)
459506
console_printf("wolfSSL_write() = %dL\n", rc);
460507
} else if(!strcmp(subCommand, "read")) {
461508
char buff[256];
462-
rc = 0;
463-
while(rc >= 0) {
509+
if (ssl == NULL) {
510+
console_printf("ERROR: run \"wolfssl init\" first\n");
511+
return -1;
512+
}
513+
rc = 1;
514+
while(rc > 0) {
464515
memset(buff, 0, sizeof(buff));
465516
rc = wolfSSL_read(ssl, buff, sizeof(buff)-1);
466517
if(rc < 0) {
467518
err = wolfSSL_get_error(ssl, 0);
468519
console_printf("ERROR: wolfSSL_read rc:%d err:%d\n", rc, err);
469520
return 0;
521+
} else if (rc == 0) {
522+
break;
470523
}
471524
console_printf("%.*s\n", rc, buff);
472525
}
@@ -558,16 +611,18 @@ omgr_app_init(void)
558611
#endif
559612

560613
/**
561-
* main
614+
* mynewt_main
562615
*
563616
* The main task for the project. This function initializes the packages, calls
564617
* init_tasks to initialize additional tasks (and possibly other objects),
565618
* then starts serving events from default event queue.
566619
*
620+
* Named mynewt_main because the BSP provides main().
621+
*
567622
* @return int NOTE: this function should never return!
568623
*/
569624
int
570-
main(int argc, char **argv)
625+
mynewt_main(int argc, char **argv)
571626
{
572627
#ifdef ARCH_sim
573628
mcu_sim_parse_args(argc, argv);

mynewt/custom_ca.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/* custom_ca.h
2+
*
3+
* Copyright (C) 2006-2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL. (formerly known as CyaSSL)
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20+
*/
21+
22+
#ifndef CUSTOM_CA_H
23+
#define CUSTOM_CA_H
24+
25+
/* Trust anchor for WOLFSSL_MN_USE_CUSTOM_CA=1.
26+
*
27+
* CA is pinned at compile time and must be manually updated if the target's chain changes.
28+
* Hostname verification is enforced using DEFAULT_HOSTNAME in client-tls-mn.c.
29+
*
30+
* To configure:
31+
* 1. Get root CA: openssl s_client -connect <host>:443 -servername <host> -showcerts </dev/null
32+
* 2. Convert to DER: openssl x509 -in root.pem -outform der | xxd -i
33+
* 3. Paste bytes below and update DEFAULT_IPADDR/DEFAULT_PORT/DEFAULT_HOSTNAME in client-tls-mn.c.
34+
*/
35+
36+
#define CUSTOM_CA_PLACEHOLDER
37+
38+
#ifdef CUSTOM_CA_PLACEHOLDER
39+
#error "mynewt/custom_ca.h: paste your target's root CA DER bytes into " \
40+
"custom_ca_der[] and remove this #error before building with " \
41+
"WOLFSSL_MN_USE_CUSTOM_CA=1 (see the instructions above)."
42+
#endif
43+
44+
static const unsigned char custom_ca_der[] =
45+
{
46+
/* TODO: paste your target's root CA DER bytes here */
47+
0
48+
};
49+
50+
static const int sizeof_custom_ca_der = sizeof(custom_ca_der);
51+
52+
#endif /* CUSTOM_CA_H */

0 commit comments

Comments
 (0)