Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/demos/sslecho/main.c
34889 views
1
/*
2
* Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
3
*
4
* Licensed under the Apache License 2.0 (the "License"). You may not use
5
* this file except in compliance with the License. You can obtain a copy
6
* in the file LICENSE in the source distribution or at
7
* https://www.openssl.org/source/license.html
8
*/
9
10
#include <stdio.h>
11
#include <string.h>
12
#include <signal.h>
13
#include <openssl/ssl.h>
14
#include <openssl/err.h>
15
#if !defined(OPENSSL_SYS_WINDOWS)
16
#include <unistd.h>
17
#include <sys/socket.h>
18
#include <arpa/inet.h>
19
#include <netinet/in.h>
20
#else
21
#include <winsock.h>
22
#endif
23
24
static const int server_port = 4433;
25
26
typedef unsigned char flag;
27
#define true 1
28
#define false 0
29
30
/*
31
* This flag won't be useful until both accept/read (TCP & SSL) methods
32
* can be called with a timeout. TBD.
33
*/
34
static volatile flag server_running = true;
35
36
static int create_socket(flag isServer)
37
{
38
int s;
39
int optval = 1;
40
struct sockaddr_in addr;
41
42
s = socket(AF_INET, SOCK_STREAM, 0);
43
if (s < 0) {
44
perror("Unable to create socket");
45
exit(EXIT_FAILURE);
46
}
47
48
if (isServer) {
49
addr.sin_family = AF_INET;
50
addr.sin_port = htons(server_port);
51
addr.sin_addr.s_addr = INADDR_ANY;
52
53
/* Reuse the address; good for quick restarts */
54
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))
55
< 0) {
56
perror("setsockopt(SO_REUSEADDR) failed");
57
exit(EXIT_FAILURE);
58
}
59
60
if (bind(s, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
61
perror("Unable to bind");
62
exit(EXIT_FAILURE);
63
}
64
65
if (listen(s, 1) < 0) {
66
perror("Unable to listen");
67
exit(EXIT_FAILURE);
68
}
69
}
70
71
return s;
72
}
73
74
static SSL_CTX *create_context(flag isServer)
75
{
76
const SSL_METHOD *method;
77
SSL_CTX *ctx;
78
79
if (isServer)
80
method = TLS_server_method();
81
else
82
method = TLS_client_method();
83
84
ctx = SSL_CTX_new(method);
85
if (ctx == NULL) {
86
perror("Unable to create SSL context");
87
ERR_print_errors_fp(stderr);
88
exit(EXIT_FAILURE);
89
}
90
91
return ctx;
92
}
93
94
static void configure_server_context(SSL_CTX *ctx)
95
{
96
/* Set the key and cert */
97
if (SSL_CTX_use_certificate_chain_file(ctx, "cert.pem") <= 0) {
98
ERR_print_errors_fp(stderr);
99
exit(EXIT_FAILURE);
100
}
101
102
if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
103
ERR_print_errors_fp(stderr);
104
exit(EXIT_FAILURE);
105
}
106
}
107
108
static void configure_client_context(SSL_CTX *ctx)
109
{
110
/*
111
* Configure the client to abort the handshake if certificate verification
112
* fails
113
*/
114
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
115
/*
116
* In a real application you would probably just use the default system certificate trust store and call:
117
* SSL_CTX_set_default_verify_paths(ctx);
118
* In this demo though we are using a self-signed certificate, so the client must trust it directly.
119
*/
120
if (!SSL_CTX_load_verify_locations(ctx, "cert.pem", NULL)) {
121
ERR_print_errors_fp(stderr);
122
exit(EXIT_FAILURE);
123
}
124
}
125
126
static void usage(void)
127
{
128
printf("Usage: sslecho s\n");
129
printf(" --or--\n");
130
printf(" sslecho c ip\n");
131
printf(" c=client, s=server, ip=dotted ip of server\n");
132
exit(EXIT_FAILURE);
133
}
134
135
#define BUFFERSIZE 1024
136
int main(int argc, char **argv)
137
{
138
flag isServer;
139
int result;
140
141
SSL_CTX *ssl_ctx = NULL;
142
SSL *ssl = NULL;
143
144
int server_skt = -1;
145
int client_skt = -1;
146
147
/* used by fgets */
148
char buffer[BUFFERSIZE];
149
char *txbuf;
150
151
char rxbuf[128];
152
size_t rxcap = sizeof(rxbuf);
153
int rxlen;
154
155
char *rem_server_ip = NULL;
156
157
struct sockaddr_in addr;
158
#if defined(OPENSSL_SYS_CYGWIN) || defined(OPENSSL_SYS_WINDOWS)
159
int addr_len = sizeof(addr);
160
#else
161
unsigned int addr_len = sizeof(addr);
162
#endif
163
164
#if !defined (OPENSSL_SYS_WINDOWS)
165
/* ignore SIGPIPE so that server can continue running when client pipe closes abruptly */
166
signal(SIGPIPE, SIG_IGN);
167
#endif
168
169
/* Splash */
170
printf("\nsslecho : Simple Echo Client/Server : %s : %s\n\n", __DATE__,
171
__TIME__);
172
173
/* Need to know if client or server */
174
if (argc < 2) {
175
usage();
176
/* NOTREACHED */
177
}
178
isServer = (argv[1][0] == 's') ? true : false;
179
/* If client get remote server address (could be 127.0.0.1) */
180
if (!isServer) {
181
if (argc != 3) {
182
usage();
183
/* NOTREACHED */
184
}
185
rem_server_ip = argv[2];
186
}
187
188
/* Create context used by both client and server */
189
ssl_ctx = create_context(isServer);
190
191
/* If server */
192
if (isServer) {
193
194
printf("We are the server on port: %d\n\n", server_port);
195
196
/* Configure server context with appropriate key files */
197
configure_server_context(ssl_ctx);
198
199
/* Create server socket; will bind with server port and listen */
200
server_skt = create_socket(true);
201
202
/*
203
* Loop to accept clients.
204
* Need to implement timeouts on TCP & SSL connect/read functions
205
* before we can catch a CTRL-C and kill the server.
206
*/
207
while (server_running) {
208
/* Wait for TCP connection from client */
209
client_skt = accept(server_skt, (struct sockaddr*) &addr,
210
&addr_len);
211
if (client_skt < 0) {
212
perror("Unable to accept");
213
exit(EXIT_FAILURE);
214
}
215
216
printf("Client TCP connection accepted\n");
217
218
/* Create server SSL structure using newly accepted client socket */
219
ssl = SSL_new(ssl_ctx);
220
if (!SSL_set_fd(ssl, client_skt)) {
221
ERR_print_errors_fp(stderr);
222
exit(EXIT_FAILURE);
223
}
224
225
/* Wait for SSL connection from the client */
226
if (SSL_accept(ssl) <= 0) {
227
ERR_print_errors_fp(stderr);
228
server_running = false;
229
} else {
230
231
printf("Client SSL connection accepted\n\n");
232
233
/* Echo loop */
234
while (true) {
235
/* Get message from client; will fail if client closes connection */
236
if ((rxlen = SSL_read(ssl, rxbuf, rxcap)) <= 0) {
237
if (rxlen == 0) {
238
printf("Client closed connection\n");
239
} else {
240
printf("SSL_read returned %d\n", rxlen);
241
}
242
ERR_print_errors_fp(stderr);
243
break;
244
}
245
/* Insure null terminated input */
246
rxbuf[rxlen] = 0;
247
/* Look for kill switch */
248
if (strcmp(rxbuf, "kill\n") == 0) {
249
/* Terminate...with extreme prejudice */
250
printf("Server received 'kill' command\n");
251
server_running = false;
252
break;
253
}
254
/* Show received message */
255
printf("Received: %s", rxbuf);
256
/* Echo it back */
257
if (SSL_write(ssl, rxbuf, rxlen) <= 0) {
258
ERR_print_errors_fp(stderr);
259
}
260
}
261
}
262
if (server_running) {
263
/* Cleanup for next client */
264
SSL_shutdown(ssl);
265
SSL_free(ssl);
266
close(client_skt);
267
/*
268
* Set client_skt to -1 to avoid double close when
269
* server_running become false before next accept
270
*/
271
client_skt = -1;
272
}
273
}
274
printf("Server exiting...\n");
275
}
276
/* Else client */
277
else {
278
279
printf("We are the client\n\n");
280
281
/* Configure client context so we verify the server correctly */
282
configure_client_context(ssl_ctx);
283
284
/* Create "bare" socket */
285
client_skt = create_socket(false);
286
/* Set up connect address */
287
addr.sin_family = AF_INET;
288
inet_pton(AF_INET, rem_server_ip, &addr.sin_addr.s_addr);
289
addr.sin_port = htons(server_port);
290
/* Do TCP connect with server */
291
if (connect(client_skt, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
292
perror("Unable to TCP connect to server");
293
goto exit;
294
} else {
295
printf("TCP connection to server successful\n");
296
}
297
298
/* Create client SSL structure using dedicated client socket */
299
ssl = SSL_new(ssl_ctx);
300
if (!SSL_set_fd(ssl, client_skt)) {
301
ERR_print_errors_fp(stderr);
302
goto exit;
303
}
304
/* Set hostname for SNI */
305
SSL_set_tlsext_host_name(ssl, rem_server_ip);
306
/* Configure server hostname check */
307
if (!SSL_set1_host(ssl, rem_server_ip)) {
308
ERR_print_errors_fp(stderr);
309
goto exit;
310
}
311
312
/* Now do SSL connect with server */
313
if (SSL_connect(ssl) == 1) {
314
315
printf("SSL connection to server successful\n\n");
316
317
/* Loop to send input from keyboard */
318
while (true) {
319
/* Get a line of input */
320
memset(buffer, 0, BUFFERSIZE);
321
txbuf = fgets(buffer, BUFFERSIZE, stdin);
322
323
/* Exit loop on error */
324
if (txbuf == NULL) {
325
break;
326
}
327
/* Exit loop if just a carriage return */
328
if (txbuf[0] == '\n') {
329
break;
330
}
331
/* Send it to the server */
332
if ((result = SSL_write(ssl, txbuf, strlen(txbuf))) <= 0) {
333
printf("Server closed connection\n");
334
ERR_print_errors_fp(stderr);
335
break;
336
}
337
338
/* Wait for the echo */
339
rxlen = SSL_read(ssl, rxbuf, rxcap);
340
if (rxlen <= 0) {
341
printf("Server closed connection\n");
342
ERR_print_errors_fp(stderr);
343
break;
344
} else {
345
/* Show it */
346
rxbuf[rxlen] = 0;
347
printf("Received: %s", rxbuf);
348
}
349
}
350
printf("Client exiting...\n");
351
} else {
352
353
printf("SSL connection to server failed\n\n");
354
355
ERR_print_errors_fp(stderr);
356
}
357
}
358
exit:
359
/* Close up */
360
if (ssl != NULL) {
361
SSL_shutdown(ssl);
362
SSL_free(ssl);
363
}
364
SSL_CTX_free(ssl_ctx);
365
366
if (client_skt != -1)
367
close(client_skt);
368
if (server_skt != -1)
369
close(server_skt);
370
371
printf("sslecho exiting\n");
372
373
return EXIT_SUCCESS;
374
}
375
376