]>
git.ipfire.org Git - thirdparty/openssl.git/blob - demos/sslecho/main.c
2 * Copyright 2022-2023 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 <openssl/ssl.h>
16 #include <openssl/err.h>
19 static const int server_port
= 4433;
21 typedef unsigned char bool;
26 * This flag won't be useful until both accept/read (TCP & SSL) methods
27 * can be called with a timeout. TBD.
29 static volatile bool server_running
= true;
31 int create_socket(bool isServer
)
35 struct sockaddr_in addr
;
37 s
= socket(AF_INET
, SOCK_STREAM
, 0);
39 perror("Unable to create socket");
44 addr
.sin_family
= AF_INET
;
45 addr
.sin_port
= htons(server_port
);
46 addr
.sin_addr
.s_addr
= INADDR_ANY
;
48 /* Reuse the address; good for quick restarts */
49 if (setsockopt(s
, SOL_SOCKET
, SO_REUSEADDR
, &optval
, sizeof(optval
))
51 perror("setsockopt(SO_REUSEADDR) failed");
55 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
56 perror("Unable to bind");
60 if (listen(s
, 1) < 0) {
61 perror("Unable to listen");
69 SSL_CTX
* create_context(bool isServer
)
71 const SSL_METHOD
*method
;
75 method
= TLS_server_method();
77 method
= TLS_client_method();
79 ctx
= SSL_CTX_new(method
);
81 perror("Unable to create SSL context");
82 ERR_print_errors_fp(stderr
);
89 void configure_server_context(SSL_CTX
*ctx
)
91 /* Set the key and cert */
92 if (SSL_CTX_use_certificate_chain_file(ctx
, "cert.pem") <= 0) {
93 ERR_print_errors_fp(stderr
);
97 if (SSL_CTX_use_PrivateKey_file(ctx
, "key.pem", SSL_FILETYPE_PEM
) <= 0) {
98 ERR_print_errors_fp(stderr
);
103 void configure_client_context(SSL_CTX
*ctx
)
106 * Configure the client to abort the handshake if certificate verification
109 SSL_CTX_set_verify(ctx
, SSL_VERIFY_PEER
, NULL
);
111 * In a real application you would probably just use the default system certificate trust store and call:
112 * SSL_CTX_set_default_verify_paths(ctx);
113 * In this demo though we are using a self-signed certificate, so the client must trust it directly.
115 if (!SSL_CTX_load_verify_locations(ctx
, "cert.pem", NULL
)) {
116 ERR_print_errors_fp(stderr
);
123 printf("Usage: sslecho s\n");
125 printf(" sslecho c ip\n");
126 printf(" c=client, s=server, ip=dotted ip of server\n");
130 int main(int argc
, char **argv
)
135 SSL_CTX
*ssl_ctx
= NULL
;
141 /* used by getline relying on realloc, can't be statically allocated */
147 size_t rxcap
= sizeof(rxbuf
);
150 char *rem_server_ip
= NULL
;
152 struct sockaddr_in addr
;
153 unsigned int addr_len
= sizeof(addr
);
155 /* ignore SIGPIPE so that server can continue running when client pipe closes abruptly */
156 signal(SIGPIPE
, SIG_IGN
);
159 printf("\nsslecho : Simple Echo Client/Server (OpenSSL 3.0.1-dev) : %s : %s\n\n", __DATE__
,
162 /* Need to know if client or server */
167 isServer
= (argv
[1][0] == 's') ? true : false;
168 /* If client get remote server address (could be 127.0.0.1) */
174 rem_server_ip
= argv
[2];
177 /* Create context used by both client and server */
178 ssl_ctx
= create_context(isServer
);
183 printf("We are the server on port: %d\n\n", server_port
);
185 /* Configure server context with appropriate key files */
186 configure_server_context(ssl_ctx
);
188 /* Create server socket; will bind with server port and listen */
189 server_skt
= create_socket(true);
192 * Loop to accept clients.
193 * Need to implement timeouts on TCP & SSL connect/read functions
194 * before we can catch a CTRL-C and kill the server.
196 while (server_running
) {
197 /* Wait for TCP connection from client */
198 client_skt
= accept(server_skt
, (struct sockaddr
*) &addr
,
200 if (client_skt
< 0) {
201 perror("Unable to accept");
205 printf("Client TCP connection accepted\n");
207 /* Create server SSL structure using newly accepted client socket */
208 ssl
= SSL_new(ssl_ctx
);
209 SSL_set_fd(ssl
, client_skt
);
211 /* Wait for SSL connection from the client */
212 if (SSL_accept(ssl
) <= 0) {
213 ERR_print_errors_fp(stderr
);
214 server_running
= false;
217 printf("Client SSL connection accepted\n\n");
221 /* Get message from client; will fail if client closes connection */
222 if ((rxlen
= SSL_read(ssl
, rxbuf
, rxcap
)) <= 0) {
224 printf("Client closed connection\n");
226 printf("SSL_read returned %d\n", rxlen
);
228 ERR_print_errors_fp(stderr
);
231 /* Insure null terminated input */
233 /* Look for kill switch */
234 if (strcmp(rxbuf
, "kill\n") == 0) {
235 /* Terminate...with extreme prejudice */
236 printf("Server received 'kill' command\n");
237 server_running
= false;
240 /* Show received message */
241 printf("Received: %s", rxbuf
);
243 if (SSL_write(ssl
, rxbuf
, rxlen
) <= 0) {
244 ERR_print_errors_fp(stderr
);
248 if (server_running
) {
249 /* Cleanup for next client */
255 printf("Server exiting...\n");
260 printf("We are the client\n\n");
262 /* Configure client context so we verify the server correctly */
263 configure_client_context(ssl_ctx
);
265 /* Create "bare" socket */
266 client_skt
= create_socket(false);
267 /* Set up connect address */
268 addr
.sin_family
= AF_INET
;
269 inet_pton(AF_INET
, rem_server_ip
, &addr
.sin_addr
.s_addr
);
270 addr
.sin_port
= htons(server_port
);
271 /* Do TCP connect with server */
272 if (connect(client_skt
, (struct sockaddr
*) &addr
, sizeof(addr
)) != 0) {
273 perror("Unable to TCP connect to server");
276 printf("TCP connection to server successful\n");
279 /* Create client SSL structure using dedicated client socket */
280 ssl
= SSL_new(ssl_ctx
);
281 SSL_set_fd(ssl
, client_skt
);
282 /* Set hostname for SNI */
283 SSL_set_tlsext_host_name(ssl
, rem_server_ip
);
284 /* Configure server hostname check */
285 SSL_set1_host(ssl
, rem_server_ip
);
287 /* Now do SSL connect with server */
288 if (SSL_connect(ssl
) == 1) {
290 printf("SSL connection to server successful\n\n");
292 /* Loop to send input from keyboard */
294 /* Get a line of input */
295 txlen
= getline(&txbuf
, &txcap
, stdin
);
296 /* Exit loop on error */
297 if (txlen
< 0 || txbuf
== NULL
) {
300 /* Exit loop if just a carriage return */
301 if (txbuf
[0] == '\n') {
304 /* Send it to the server */
305 if ((result
= SSL_write(ssl
, txbuf
, txlen
)) <= 0) {
306 printf("Server closed connection\n");
307 ERR_print_errors_fp(stderr
);
311 /* Wait for the echo */
312 rxlen
= SSL_read(ssl
, rxbuf
, rxcap
);
314 printf("Server closed connection\n");
315 ERR_print_errors_fp(stderr
);
320 printf("Received: %s", rxbuf
);
323 printf("Client exiting...\n");
326 printf("SSL connection to server failed\n\n");
328 ERR_print_errors_fp(stderr
);
337 SSL_CTX_free(ssl_ctx
);
339 if (client_skt
!= -1)
341 if (server_skt
!= -1)
344 if (txbuf
!= NULL
&& txcap
> 0)
347 printf("sslecho exiting\n");