]>
git.ipfire.org Git - thirdparty/openssl.git/blob - demos/sslecho/main.c
c75eac2bc374c1051f651bd19729d7e43049af8e
2 * Copyright 2022-2024 The OpenSSL Project Authors. All Rights Reserved.
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
13 #include <sys/socket.h>
14 #include <arpa/inet.h>
15 #include <netinet/in.h>
16 #include <openssl/ssl.h>
17 #include <openssl/err.h>
20 static const int server_port
= 4433;
22 typedef unsigned char bool;
27 * This flag won't be useful until both accept/read (TCP & SSL) methods
28 * can be called with a timeout. TBD.
30 static volatile bool server_running
= true;
32 static int create_socket(bool isServer
)
36 struct sockaddr_in addr
;
38 s
= socket(AF_INET
, SOCK_STREAM
, 0);
40 perror("Unable to create socket");
45 addr
.sin_family
= AF_INET
;
46 addr
.sin_port
= htons(server_port
);
47 addr
.sin_addr
.s_addr
= INADDR_ANY
;
49 /* Reuse the address; good for quick restarts */
50 if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &optval
, sizeof(optval
))
52 perror("setsockopt(SO_REUSEADDR) failed");
56 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
57 perror("Unable to bind");
61 if (listen(s
, 1) < 0) {
62 perror("Unable to listen");
70 static SSL_CTX
* create_context(bool isServer
)
72 const SSL_METHOD
*method
;
76 method
= TLS_server_method();
78 method
= TLS_client_method();
80 ctx
= SSL_CTX_new(method
);
82 perror("Unable to create SSL context");
83 ERR_print_errors_fp(stderr
);
90 static void configure_server_context(SSL_CTX
*ctx
)
92 /* Set the key and cert */
93 if (SSL_CTX_use_certificate_chain_file(ctx
, "cert.pem") <= 0) {
94 ERR_print_errors_fp(stderr
);
98 if (SSL_CTX_use_PrivateKey_file(ctx
, "key.pem", SSL_FILETYPE_PEM
) <= 0) {
99 ERR_print_errors_fp(stderr
);
104 static void configure_client_context(SSL_CTX
*ctx
)
107 * Configure the client to abort the handshake if certificate verification
110 SSL_CTX_set_verify(ctx
, SSL_VERIFY_PEER
, NULL
);
112 * In a real application you would probably just use the default system certificate trust store and call:
113 * SSL_CTX_set_default_verify_paths(ctx);
114 * In this demo though we are using a self-signed certificate, so the client must trust it directly.
116 if (!SSL_CTX_load_verify_locations(ctx
, "cert.pem", NULL
)) {
117 ERR_print_errors_fp(stderr
);
122 static void usage(void)
124 printf("Usage: sslecho s\n");
126 printf(" sslecho c ip\n");
127 printf(" c=client, s=server, ip=dotted ip of server\n");
131 int main(int argc
, char **argv
)
136 SSL_CTX
*ssl_ctx
= NULL
;
142 /* used by getline relying on realloc, can't be statically allocated */
148 size_t rxcap
= sizeof(rxbuf
);
151 char *rem_server_ip
= NULL
;
153 struct sockaddr_in addr
;
154 unsigned int addr_len
= sizeof(addr
);
156 /* ignore SIGPIPE so that server can continue running when client pipe closes abruptly */
157 signal(SIGPIPE
, SIG_IGN
);
160 printf("\nsslecho : Simple Echo Client/Server : %s : %s\n\n", __DATE__
,
163 /* Need to know if client or server */
168 isServer
= (argv
[1][0] == 's') ? true : false;
169 /* If client get remote server address (could be 127.0.0.1) */
175 rem_server_ip
= argv
[2];
178 /* Create context used by both client and server */
179 ssl_ctx
= create_context(isServer
);
184 printf("We are the server on port: %d\n\n", server_port
);
186 /* Configure server context with appropriate key files */
187 configure_server_context(ssl_ctx
);
189 /* Create server socket; will bind with server port and listen */
190 server_skt
= create_socket(true);
193 * Loop to accept clients.
194 * Need to implement timeouts on TCP & SSL connect/read functions
195 * before we can catch a CTRL-C and kill the server.
197 while (server_running
) {
198 /* Wait for TCP connection from client */
199 client_skt
= accept(server_skt
, (struct sockaddr
*) &addr
,
201 if (client_skt
< 0) {
202 perror("Unable to accept");
206 printf("Client TCP connection accepted\n");
208 /* Create server SSL structure using newly accepted client socket */
209 ssl
= SSL_new(ssl_ctx
);
210 if (!SSL_set_fd(ssl
, client_skt
)) {
211 ERR_print_errors_fp(stderr
);
215 /* Wait for SSL connection from the client */
216 if (SSL_accept(ssl
) <= 0) {
217 ERR_print_errors_fp(stderr
);
218 server_running
= false;
221 printf("Client SSL connection accepted\n\n");
225 /* Get message from client; will fail if client closes connection */
226 if ((rxlen
= SSL_read(ssl
, rxbuf
, rxcap
)) <= 0) {
228 printf("Client closed connection\n");
230 printf("SSL_read returned %d\n", rxlen
);
232 ERR_print_errors_fp(stderr
);
235 /* Insure null terminated input */
237 /* Look for kill switch */
238 if (strcmp(rxbuf
, "kill\n") == 0) {
239 /* Terminate...with extreme prejudice */
240 printf("Server received 'kill' command\n");
241 server_running
= false;
244 /* Show received message */
245 printf("Received: %s", rxbuf
);
247 if (SSL_write(ssl
, rxbuf
, rxlen
) <= 0) {
248 ERR_print_errors_fp(stderr
);
252 if (server_running
) {
253 /* Cleanup for next client */
259 printf("Server exiting...\n");
264 printf("We are the client\n\n");
266 /* Configure client context so we verify the server correctly */
267 configure_client_context(ssl_ctx
);
269 /* Create "bare" socket */
270 client_skt
= create_socket(false);
271 /* Set up connect address */
272 addr
.sin_family
= AF_INET
;
273 inet_pton(AF_INET
, rem_server_ip
, &addr
.sin_addr
.s_addr
);
274 addr
.sin_port
= htons(server_port
);
275 /* Do TCP connect with server */
276 if (connect(client_skt
, (struct sockaddr
*) &addr
, sizeof(addr
)) != 0) {
277 perror("Unable to TCP connect to server");
280 printf("TCP connection to server successful\n");
283 /* Create client SSL structure using dedicated client socket */
284 ssl
= SSL_new(ssl_ctx
);
285 if (!SSL_set_fd(ssl
, client_skt
)) {
286 ERR_print_errors_fp(stderr
);
289 /* Set hostname for SNI */
290 SSL_set_tlsext_host_name(ssl
, rem_server_ip
);
291 /* Configure server hostname check */
292 if (!SSL_set1_host(ssl
, rem_server_ip
)) {
293 ERR_print_errors_fp(stderr
);
297 /* Now do SSL connect with server */
298 if (SSL_connect(ssl
) == 1) {
300 printf("SSL connection to server successful\n\n");
302 /* Loop to send input from keyboard */
304 /* Get a line of input */
305 txlen
= getline(&txbuf
, &txcap
, stdin
);
306 /* Exit loop on error */
307 if (txlen
< 0 || txbuf
== NULL
) {
310 /* Exit loop if just a carriage return */
311 if (txbuf
[0] == '\n') {
314 /* Send it to the server */
315 if ((result
= SSL_write(ssl
, txbuf
, txlen
)) <= 0) {
316 printf("Server closed connection\n");
317 ERR_print_errors_fp(stderr
);
321 /* Wait for the echo */
322 rxlen
= SSL_read(ssl
, rxbuf
, rxcap
);
324 printf("Server closed connection\n");
325 ERR_print_errors_fp(stderr
);
330 printf("Received: %s", rxbuf
);
333 printf("Client exiting...\n");
336 printf("SSL connection to server failed\n\n");
338 ERR_print_errors_fp(stderr
);
347 SSL_CTX_free(ssl_ctx
);
349 if (client_skt
!= -1)
351 if (server_skt
!= -1)
354 if (txbuf
!= NULL
&& txcap
> 0)
357 printf("sslecho exiting\n");