1 /*
2  *  SSL client demonstration program
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  */
7 
8 #define MBEDTLS_DECLARE_PRIVATE_IDENTIFIERS
9 
10 #include "mbedtls/build_info.h"
11 
12 #include "mbedtls/platform.h"
13 
14 #if !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) ||      \
15     !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_SSL_CLI_C) ||           \
16     !defined(MBEDTLS_PEM_PARSE_C) || !defined(MBEDTLS_X509_CRT_PARSE_C)
main(void)17 int main(void)
18 {
19     mbedtls_printf("MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or "
20                    "MBEDTLS_NET_C and/or MBEDTLS_SSL_CLI_C and/or "
21                    "MBEDTLS_PEM_PARSE_C and/or MBEDTLS_X509_CRT_PARSE_C "
22                    "not defined.\n");
23     mbedtls_exit(0);
24 }
25 #else
26 
27 #include "mbedtls/net_sockets.h"
28 #include "mbedtls/debug.h"
29 #include "mbedtls/ssl.h"
30 #include "mbedtls/entropy.h"
31 #include "mbedtls/ctr_drbg.h"
32 #include "mbedtls/error.h"
33 #include "test/certs.h"
34 
35 #include <string.h>
36 
37 #define SERVER_PORT "4433"
38 #define SERVER_NAME "localhost"
39 #define GET_REQUEST "GET / HTTP/1.0\r\n\r\n"
40 
41 #define DEBUG_LEVEL 1
42 
43 
my_debug(void * ctx,int level,const char * file,int line,const char * str)44 static void my_debug(void *ctx, int level,
45                      const char *file, int line,
46                      const char *str)
47 {
48     ((void) level);
49 
50     mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str);
51     fflush((FILE *) ctx);
52 }
53 
main(void)54 int main(void)
55 {
56     int ret = 1, len;
57     int exit_code = MBEDTLS_EXIT_FAILURE;
58     mbedtls_net_context server_fd;
59     uint32_t flags;
60     unsigned char buf[1024];
61     const char *pers = "ssl_client1";
62 
63     mbedtls_entropy_context entropy;
64     mbedtls_ctr_drbg_context ctr_drbg;
65     mbedtls_ssl_context ssl;
66     mbedtls_ssl_config conf;
67     mbedtls_x509_crt cacert;
68 
69 #if defined(MBEDTLS_DEBUG_C)
70     mbedtls_debug_set_threshold(DEBUG_LEVEL);
71 #endif
72 
73     /*
74      * 0. Initialize the RNG and the session data
75      */
76     mbedtls_net_init(&server_fd);
77     mbedtls_ssl_init(&ssl);
78     mbedtls_ssl_config_init(&conf);
79     mbedtls_x509_crt_init(&cacert);
80     mbedtls_ctr_drbg_init(&ctr_drbg);
81     mbedtls_entropy_init(&entropy);
82 
83     psa_status_t status = psa_crypto_init();
84     if (status != PSA_SUCCESS) {
85         mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n",
86                         (int) status);
87         goto exit;
88     }
89 
90     mbedtls_printf("\n  . Seeding the random number generator...");
91     fflush(stdout);
92 
93 
94     if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
95                                      (const unsigned char *) pers,
96                                      strlen(pers))) != 0) {
97         mbedtls_printf(" failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret);
98         goto exit;
99     }
100 
101     mbedtls_printf(" ok\n");
102 
103     /*
104      * 0. Initialize certificates
105      */
106     mbedtls_printf("  . Loading the CA root certificate ...");
107     fflush(stdout);
108 
109     ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_cas_pem,
110                                  mbedtls_test_cas_pem_len);
111     if (ret < 0) {
112         mbedtls_printf(" failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n",
113                        (unsigned int) -ret);
114         goto exit;
115     }
116 
117     mbedtls_printf(" ok (%d skipped)\n", ret);
118 
119     /*
120      * 1. Start the connection
121      */
122     mbedtls_printf("  . Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT);
123     fflush(stdout);
124 
125     if ((ret = mbedtls_net_connect(&server_fd, SERVER_NAME,
126                                    SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
127         mbedtls_printf(" failed\n  ! mbedtls_net_connect returned %d\n\n", ret);
128         goto exit;
129     }
130 
131     mbedtls_printf(" ok\n");
132 
133     /*
134      * 2. Setup stuff
135      */
136     mbedtls_printf("  . Setting up the SSL/TLS structure...");
137     fflush(stdout);
138 
139     if ((ret = mbedtls_ssl_config_defaults(&conf,
140                                            MBEDTLS_SSL_IS_CLIENT,
141                                            MBEDTLS_SSL_TRANSPORT_STREAM,
142                                            MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
143         mbedtls_printf(" failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
144         goto exit;
145     }
146 
147     mbedtls_printf(" ok\n");
148 
149     /* OPTIONAL is not optimal for security,
150      * but makes interop easier in this simplified example */
151     mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
152     mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
153     mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
154 
155     if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
156         mbedtls_printf(" failed\n  ! mbedtls_ssl_setup returned %d\n\n", ret);
157         goto exit;
158     }
159 
160     if ((ret = mbedtls_ssl_set_hostname(&ssl, SERVER_NAME)) != 0) {
161         mbedtls_printf(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
162         goto exit;
163     }
164 
165     mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
166 
167     /*
168      * 4. Handshake
169      */
170     mbedtls_printf("  . Performing the SSL/TLS handshake...");
171     fflush(stdout);
172 
173     while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
174         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
175             mbedtls_printf(" failed\n  ! mbedtls_ssl_handshake returned -0x%x\n\n",
176                            (unsigned int) -ret);
177             goto exit;
178         }
179     }
180 
181     mbedtls_printf(" ok\n");
182 
183     /*
184      * 5. Verify the server certificate
185      */
186     mbedtls_printf("  . Verifying peer X.509 certificate...");
187 
188     /* In real life, we probably want to bail out when ret != 0 */
189     if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
190 #if !defined(MBEDTLS_X509_REMOVE_INFO)
191         char vrfy_buf[512];
192 #endif
193 
194         mbedtls_printf(" failed\n");
195 
196 #if !defined(MBEDTLS_X509_REMOVE_INFO)
197         mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "  ! ", flags);
198 
199         mbedtls_printf("%s\n", vrfy_buf);
200 #endif
201     } else {
202         mbedtls_printf(" ok\n");
203     }
204 
205     /*
206      * 3. Write the GET request
207      */
208     mbedtls_printf("  > Write to server:");
209     fflush(stdout);
210 
211     len = sprintf((char *) buf, GET_REQUEST);
212 
213     while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) {
214         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
215             mbedtls_printf(" failed\n  ! mbedtls_ssl_write returned %d\n\n", ret);
216             goto exit;
217         }
218     }
219 
220     len = ret;
221     mbedtls_printf(" %d bytes written\n\n%s", len, (char *) buf);
222 
223     /*
224      * 7. Read the HTTP response
225      */
226     mbedtls_printf("  < Read from server:");
227     fflush(stdout);
228 
229     do {
230         len = sizeof(buf) - 1;
231         memset(buf, 0, sizeof(buf));
232         ret = mbedtls_ssl_read(&ssl, buf, len);
233 
234         if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
235             continue;
236         }
237 
238         if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
239             mbedtls_printf("The return value %d from mbedtls_ssl_read() means that the server\n"
240                            "closed the connection first. We're ok with that.\n",
241                            MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY);
242             break;
243         }
244 
245         if (ret < 0) {
246             mbedtls_printf("failed\n  ! mbedtls_ssl_read returned %d\n\n", ret);
247             break;
248         }
249 
250         if (ret == 0) {
251             mbedtls_printf("\n\nEOF\n\n");
252             break;
253         }
254 
255         len = ret;
256         mbedtls_printf(" %d bytes read\n\n%s", len, (char *) buf);
257     } while (1);
258 
259     mbedtls_ssl_close_notify(&ssl);
260 
261     if (ret == 0 || ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
262         exit_code = MBEDTLS_EXIT_SUCCESS;
263     }
264 
265 exit:
266 
267 #ifdef MBEDTLS_ERROR_C
268     if (exit_code != MBEDTLS_EXIT_SUCCESS) {
269         char error_buf[100];
270         mbedtls_strerror(ret, error_buf, 100);
271         mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf);
272     }
273 #endif
274 
275     mbedtls_net_free(&server_fd);
276     mbedtls_x509_crt_free(&cacert);
277     mbedtls_ssl_free(&ssl);
278     mbedtls_ssl_config_free(&conf);
279     mbedtls_ctr_drbg_free(&ctr_drbg);
280     mbedtls_entropy_free(&entropy);
281     mbedtls_psa_crypto_free();
282 
283     mbedtls_exit(exit_code);
284 }
285 
286 #endif /* configuration allows running this program */
287