Added Simple SSL Echo Client/Server to demos.

Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/17260)
This commit is contained in:
bobwirka 2021-12-12 14:53:13 -05:00 committed by Matt Caswell
parent cb629550cd
commit 801c638c50
7 changed files with 485 additions and 0 deletions

View File

@ -50,3 +50,6 @@ signature:
EVP_Signature_demo.c Compute and verify a signature from multiple buffers
rsa_pss_direct.c Compute and verify an RSA-PSS signature from a hash
rsa_pss_hash.c Compute and verify an RSA-PSS signature over a buffer
sslecho:
main.c Simple SSL echo client/server.

View File

@ -0,0 +1,20 @@
Useful Links:
OpenSSL API Documentation: https://www.openssl.org/docs
Github: https://github.com/openssl/openssl
OpenSSL Wiki: https://wiki.openssl.org/index.php/Main_Page
Original Simple Server: https://wiki.openssl.org/index.php/Simple_TLS_Server
---------------------------------------------------------------
Generate self signed cert and key 'pem' files (good for 10 years):
openssl req -newkey rsa:4096 -x509 -sha256 -days 3650 -nodes -out cert.pem -keyout key.pem
You can just hit carriage returns to accept the default values, except for "Common Name"; you
should enter 'localhost', or an actual hostname.
The same keys can be used for both communicating instances; same or different machines.

26
demos/sslecho/README.md Normal file
View File

@ -0,0 +1,26 @@
OpenSSL Simple Echo Client/Server
=================================
This project implements a simple echo client/server.
It is a console application, with command line parameters determining the mode
of operation (client or server). Start it with no parameters to see usage.
The server code was adapted from the Simple TLS Server on the OpenSSL Wiki.
The server code was modified to perform the echo function, and client code
was added to open a connection with the server and to send keyboard input
to the server.
The new client code illustrates that:
- Connection to the SSL server starts as a standard TCP 'connect'.
- Once connected with TCP, the client 'upgrades' to SSL using
SSL_connect().
- When the SSL connection completes, data is sent and received using
SSL_write() and SSL_read().
- Pretty simple.
The cert.pem and key.pem files included are self signed certificates with the
"Common Name" of 'localhost'.
Best to create the 'pem' files using an actual hostname.

32
demos/sslecho/cert.pem Normal file
View File

@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFkzCCA3ugAwIBAgIUQJ8FQFwuVg1UlnIBam0+liL0RSQwDQYJKoZIhvcNAQEL
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MB4X
DTIyMDIwMjE0MzgzNloXDTMyMDEzMTE0MzgzNlowWTELMAkGA1UEBhMCQVUxEzAR
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEAyPZfTbR9lVvpHxIGRzpYb1gYFjPZ7yTXYZVKEqQLVxw/O2L32ufa
lODiYJr/pKu9++9T+JrmRnonYlyl0uFta3w4rMY9PzHsT7jIZJByoFdraNz1SnxF
1UaHjzF9fjIA0/n/ZGVJDZCCYulpcVkpW14oNG4tTW5IefYUH3GxmPZ5godhWEla
6OXl3+9xkGd5yXq1O4VZbsekcVcZlznuq7blmvs3UrjrEZ5xgmCd8kNzy/E9APKY
SSGx87/U9yyiz5GAphgSNTqAfEWqpzouMv+hUm/J5NuZCXbOPYbE7zfDDauspYiY
/wdGty9ZvDy5g+fFz8sZig1OWuHqvU8QGoIfVRCxjhX3+p0/KshGDBWjLHek+8Wh
IZHmuf1LgT+gOzN3dxxVEcphSiJX0eZ/OhBelowrdabEycm2WAk3qs/tUDMbWh6V
VSH22ODLX/cBrSAY2sk2EU8Mz5Mbm6gFTcJhqOBgVn5g8/3QCAhFG3xq/2LKZ+za
itAKbaeQqyAw5G/+oc7mKCjUqSKE92n6FKZRsJrB+vfy3AQYyqJevHcIf2nbBimX
vb4/rDed/gvSOVGIXIUiUlFHgg8DoVZqMrfJ+y/xwr+Ya+AX8n6J8EB2It3W4EEf
nmosupBcZPb6U2VrtpEe/199nPj2ZXQHGLLQfw8lYjvZDghCFiP0o8cCAwEAAaNT
MFEwHQYDVR0OBBYEFDClIPCiAkevl1qh188Ycjz5IZ/DMB8GA1UdIwQYMBaAFDCl
IPCiAkevl1qh188Ycjz5IZ/DMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
BQADggIBAGQm27D74xUm1X99GbDQpgJenUIu+Bszk8qXCsPfyyQZy4H6+70uXlkC
ASf/keQjrPzrco3rBelbtlCGqqWhsCznVplrjNIntBAkLD0fU3z92SjsMvHEcBDa
Nu6aXExN9gv85EBJHNnj16hqjo8Mk+ydNQ8BtcnZa4zi7GdVh29KbPuEzeoyRnXP
xh5yHUj5Bs6hEUbirhm1WLEK8bvfWykfEJiGOQO8MHAeYK1uPFXDmswgTwJFzZyA
6LSXYbmGOnCM8yAmVXHMnXXCKd+DQFyQ0KrXDiixyTinYFtrONBkNNt/7SnCjJt5
H3LRTNuoZvvGmaS7GxbIMemBjLdrigKicVZunEPGFRTEL7K+spmSMnpAiITStxjR
70wHEe3M9IUbJximKaxvMhXhP0VSPJGOzgG304A2MqMS7UPBDzD/pz5c7gn7ILfM
LcxzStnQcbTqqmdpNVlMv31YpOk5nel5RY3UmwKbQkix6UAo/CJmC1Q3yLU8uG5O
6j7vS8t0wOYcVTAA845JU8C7V5yy6UeCB9F2oGDgVwCe6U8bzTIoCDnkzIKO7LlS
734KP+fNK9LatNzpPQWW+1SK4XEZBNLOMePwu560GLVzPgr9ji0z83E+0yAcWrAO
4gKT+/h3Ep1Ut73daskFAvNJFFt/5Rm+xZECHrxRkXqW1AN/2eXX
-----END CERTIFICATE-----

52
demos/sslecho/key.pem Normal file
View File

@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQDI9l9NtH2VW+kf
EgZHOlhvWBgWM9nvJNdhlUoSpAtXHD87Yvfa59qU4OJgmv+kq73771P4muZGeidi
XKXS4W1rfDisxj0/MexPuMhkkHKgV2to3PVKfEXVRoePMX1+MgDT+f9kZUkNkIJi
6WlxWSlbXig0bi1Nbkh59hQfcbGY9nmCh2FYSVro5eXf73GQZ3nJerU7hVlux6Rx
VxmXOe6rtuWa+zdSuOsRnnGCYJ3yQ3PL8T0A8phJIbHzv9T3LKLPkYCmGBI1OoB8
RaqnOi4y/6FSb8nk25kJds49hsTvN8MNq6yliJj/B0a3L1m8PLmD58XPyxmKDU5a
4eq9TxAagh9VELGOFff6nT8qyEYMFaMsd6T7xaEhkea5/UuBP6A7M3d3HFURymFK
IlfR5n86EF6WjCt1psTJybZYCTeqz+1QMxtaHpVVIfbY4Mtf9wGtIBjayTYRTwzP
kxubqAVNwmGo4GBWfmDz/dAICEUbfGr/Yspn7NqK0Aptp5CrIDDkb/6hzuYoKNSp
IoT3afoUplGwmsH69/LcBBjKol68dwh/adsGKZe9vj+sN53+C9I5UYhchSJSUUeC
DwOhVmoyt8n7L/HCv5hr4BfyfonwQHYi3dbgQR+eaiy6kFxk9vpTZWu2kR7/X32c
+PZldAcYstB/DyViO9kOCEIWI/SjxwIDAQABAoICAH51SpODOGN8ar36gajgtjWa
oc2W41TxQfdOEkaYo+o1BDVCmeVOcOWufcV8w9HDoNGgUJ7oGm/O/mmPE2oYINq6
WI+gT3os2B9yj+d4Xik32YcrQ8+TU/5ZW4RoCCgZHxxE/MkYU1gNz36ekpOZH8U3
AuW7Txaih0j36MHAsZknwF67Ai6kOmjEAltgOX49Hw4CAXlq+FQVnQ0VWi0nb2Du
vp0/6BhN9N4pbhQ06C9C8uMq8tBd2CZs5aYU2NaRaAJl9SaPjyWfoqqQzEpe+iNt
aP6PCeTRqwOhlzZwUAyYck1v8jxYMK6KzZ0IVtd0/uhaOMgBbhjJNr1J3IUz81Ud
gwmU7UrifjtcGiMHNmHnIAJNcbm9sY27EvsyEHz3zf90VQL8wLpYflX9kX5v8soi
WPv6On+u7ARKofHfQKmP1BfJoGY651uyI1vqdpwUds9iQk3dZWUuBf1WRzywH4t/
Vwz/h9cEW1Pd42cjukRCoPE1kLc9vHBUEADaaQG7Y5avuLIfDFzXEmwf9YokGRcy
ULUikhhFgiL4bOiQ4cj0/c3CLFAM98iq+z1pTlGFy5msjgUTg3ouUUbbPTaxaMS5
yVeXelleQADdpj25MTGatBkGW4WC3DYopvvSy+DZ6XarJ6gYm+/cV+eoXddQYLUd
RAQqnQFqVPUIy2rlVuQBAoIBAQDlKILSqQNPZqou6lFgo4tbFLpzUFVAnmrEUhuJ
3v9ppseKncolZ3pcr10VwIzuQZliLLvUiZ8aB+TzMeuIRBm1PkXMpSRhPsVb2bGb
QrTzzPafB8uwVwvr3YzYeRXbpdabU9UpuQMk+lD+GEx5DfowdYJMtdIBOeQdjROi
7JZnHPfNwNheEakJpCgPbulQRfrXx4Fd+npWQprcvCYhg8vnqCHrGazy5g/2dnYF
NW7L2CNHdM74SJKl8gY/YcfEQSFcir6SFWUGPOiHsVdpKX9K0his6DoiV8QPH/S0
RIKZuNIuOmiO8ATblYksrh8UuOQWi2kywE3bF3neMmNgwoRBAoIBAQDggGL0C9Ij
n+DHlkHujbziEwe1pLVSb4x2q5KmZwA4VWDGLARbK2ypx6/LJDsUCwK6ZFHh89DU
eW9Ze6fXMi8Fiv1N1DfawIu9+bU3BG5boiQMdAgYzSCUhwojo3KiIpvbzXCmSQd9
1lJkbwxQFo2GuYZIX+QLyONhGBA1JdF0kBzIrrQWmza+wNj1emftFptZlwAW1+wm
KvZyzAZl3/5fj5/9oAMxlH489edbgRMF/cOmzpB4fIAkbzmvU97xXOzKWX+nPA6D
BTVkkruqESpq2pf06gGnlbCC5Tcf1QS+On+/LGr1frr/aeouRy8xHv5xgVCRcyh+
nLwOP6W/KYYHAoIBAQCXgjtMkJYxrw0hy6ZWIIsIgyHrD9fty0+H0UmH1DpGXhBb
44s9Q7cxBHik4xPKivCgajcdhIf+q+2BpSW2iF/+5tc7QIxXBytxWPMGVgpRjtgX
uQ3A3yxwm6B9l0EOYg0L0VeEKGCd2CoodWRKPSWHWIn3sdbRHLdnmli7RXUDY7Gr
Ba+IMmDykOgzm/8CJeJ9O9iai/rKgWrmOjdzvTHZTd5vFCC2z8kKCLRrKTLB73sT
yXT1zvW2Zdgfm8R6Sx2Fk+3/o8mRYD/VRzklvFv+2f2ahEe7YQ+teFFPxmQawomk
KtXqe2Ka07lIIy9FgiC7jxzUgzR2gIUAlYwC81iBAoIBAC30Oc0oykf+hv1z1WUm
YD6KlK5q267XJJJ6BlfHh7UATQHjqrSay/Bo7qQPc4RjyJgsxtIQnXOQs+lGNZII
NLXWwIj44sIFXdVyUtTDNG/PXb+q1Kl2+69LgRjQcTudB/hTMjbnhgANKepjDMss
AqZMPZ98+WosIdcTHOY0Ko7InQu7LyPde7RKN17wQmu2j/Ajx6HlavJZIv9Wogyi
cChRdvdslJrGgZyq3UPOxP0Z972iVNJE8doDZnRsH5uaYOH+tfGein3pSAehPYbP
YrZirm40pEgQjQQONV1vtjvWL6YLSo2b9l0n6ga1DYTpij3jsYFEaEqafKgSATSD
JGsCggEAVnGMMovIgEADUAiwQzlYb5/gUjRJOetFpPW8R/3CZqFt3FTprNH0Q7Jb
be3PJCLONqYE8K84n66Ro5I/58oVcJ5QwCwZCmZ+Kk4u7j0RYR9kkpR6gWShSpfw
CkrSVNz0zn3l8GxIs11YO+ztBQG82StU+7PTZH9KGEQhytO3km+txC3EXih7Fn7R
Vb2rJ+2v6aSGjH+1n/GFP8YxKAxYk7jPwI5s4YMrn6TQPt4tgr4I0f7DDjjlVLEg
LMixBvYHG/8fXWtldf6Wwhl6UJ5G0LA4KxXRAJ68RX8cQNLG7mv66xogbLEMnrJr
DDFU5HazFnn1G0/rg2SnKHTRLV2E9g==
-----END PRIVATE KEY-----

340
demos/sslecho/main.c Normal file
View File

@ -0,0 +1,340 @@
/*
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
static const int server_port = 4433;
typedef unsigned char bool;
#define true 1
#define false 0
/*
* This flag won't be useful until both accept/read (TCP & SSL) methods
* can be called with a timeout. TBD.
*/
static volatile bool server_running = true;
int create_socket(bool isServer)
{
int s;
int optval = 1;
struct sockaddr_in addr;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
if (isServer) {
addr.sin_family = AF_INET;
addr.sin_port = htons(server_port);
addr.sin_addr.s_addr = INADDR_ANY;
/* Reuse the address; good for quick restarts */
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))
< 0) {
perror("setsockopt(SO_REUSEADDR) failed");
exit(EXIT_FAILURE);
}
if (bind(s, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
perror("Unable to bind");
exit(EXIT_FAILURE);
}
if (listen(s, 1) < 0) {
perror("Unable to listen");
exit(EXIT_FAILURE);
}
}
return s;
}
SSL_CTX* create_context(bool isServer)
{
const SSL_METHOD *method;
SSL_CTX *ctx;
if (isServer)
method = TLS_server_method();
else
method = TLS_client_method();
ctx = SSL_CTX_new(method);
if (ctx == NULL) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
return ctx;
}
void configure_server_context(SSL_CTX *ctx)
{
/* Set the key and cert */
if (SSL_CTX_use_certificate_chain_file(ctx, "cert.pem") <= 0) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
}
void configure_client_context(SSL_CTX *ctx)
{
/*
* Configure the client to abort the handshake if certificate verification
* fails
*/
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
/*
* In a real application you would probably just use the default system certificate trust store and call:
* SSL_CTX_set_default_verify_paths(ctx);
* In this demo though we are using a self-signed certificate, so the client must trust it directly.
*/
if (!SSL_CTX_load_verify_locations(ctx, "cert.pem", NULL)) {
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
}
void usage()
{
printf("Usage: sslecho s\n");
printf(" --or--\n");
printf(" sslecho c ip\n");
printf(" c=client, s=server, ip=dotted ip of server\n");
exit(1);
}
int main(int argc, char **argv)
{
bool isServer;
int result;
SSL_CTX *ssl_ctx = NULL;
SSL *ssl = NULL;
int server_skt = -1;
int client_skt = -1;
char txbuf[128];
size_t txcap = sizeof(txbuf);
int txlen;
char rxbuf[128];
size_t rxcap = sizeof(rxbuf);
int rxlen;
char *rem_server_ip = NULL;
struct sockaddr_in addr;
unsigned int addr_len = sizeof(addr);
/* Splash */
printf("\nsslecho : Simple Echo Client/Server (OpenSSL 3.0.1-dev) : %s : %s\n\n", __DATE__,
__TIME__);
/* Need to know if client or server */
if (argc < 2) {
usage();
/* NOTREACHED */
}
isServer = (argv[1][0] == 's') ? true : false;
/* If client get remote server address (could be 127.0.0.1) */
if (!isServer) {
if (argc != 3) {
usage();
/* NOTREACHED */
}
rem_server_ip = argv[2];
}
/* Create context used by both client and server */
ssl_ctx = create_context(isServer);
/* If server */
if (isServer) {
printf("We are the server on port: %d\n\n", server_port);
/* Configure server context with appropriate key files */
configure_server_context(ssl_ctx);
/* Create server socket; will bind with server port and listen */
server_skt = create_socket(true);
/*
* Loop to accept clients.
* Need to implement timeouts on TCP & SSL connect/read functions
* before we can catch a CTRL-C and kill the server.
*/
while (server_running) {
/* Wait for TCP connection from client */
client_skt = accept(server_skt, (struct sockaddr*) &addr,
&addr_len);
if (client_skt < 0) {
perror("Unable to accept");
exit(EXIT_FAILURE);
}
printf("Client TCP connection accepted\n");
/* Create server SSL structure using newly accepted client socket */
ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, client_skt);
/* Wait for SSL connection from the client */
if (SSL_accept(ssl) <= 0) {
ERR_print_errors_fp(stderr);
server_running = false;
} else {
printf("Client SSL connection accepted\n\n");
/* Echo loop */
while (true) {
/* Get message from client; will fail if client closes connection */
if ((rxlen = SSL_read(ssl, rxbuf, rxcap)) <= 0) {
if (rxlen == 0) {
printf("Client closed connection\n");
}
ERR_print_errors_fp(stderr);
break;
}
/* Insure null terminated input */
rxbuf[rxlen] = 0;
/* Look for kill switch */
if (strcmp(rxbuf, "kill\n") == 0) {
/* Terminate...with extreme prejudice */
printf("Server received 'kill' command\n");
server_running = false;
break;
}
/* Show received message */
printf("Received: %s", rxbuf);
/* Echo it back */
if (SSL_write(ssl, rxbuf, rxlen) <= 0) {
ERR_print_errors_fp(stderr);
}
}
}
if (server_running) {
/* Cleanup for next client */
SSL_shutdown(ssl);
SSL_free(ssl);
close(client_skt);
}
}
printf("Server exiting...\n");
}
/* Else client */
else {
printf("We are the client\n\n");
/* Configure client context so we verify the server correctly */
configure_client_context(ssl_ctx);
/* Create "bare" socket */
client_skt = create_socket(false);
/* Set up connect address */
addr.sin_family = AF_INET;
inet_pton(AF_INET, rem_server_ip, &addr.sin_addr.s_addr);
addr.sin_port = htons(server_port);
/* Do TCP connect with server */
if (connect(client_skt, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
perror("Unable to TCP connect to server");
goto exit;
} else {
printf("TCP connection to server successful\n");
}
/* Create client SSL structure using dedicated client socket */
ssl = SSL_new(ssl_ctx);
SSL_set_fd(ssl, client_skt);
/* Set host name for SNI */
SSL_set_tlsext_host_name(ssl, rem_server_ip);
/* Configure server hostname check */
SSL_set1_host(ssl, rem_server_ip);
/* Now do SSL connect with server */
if (SSL_connect(ssl) == 1) {
printf("SSL connection to server successful\n\n");
/* Loop to send input from keyboard */
while (true) {
/* Get a line of input */
txlen = getline(&txbuf, &txcap, stdin);
/* Exit loop if just a carriage return */
if (txbuf[0] == '\n') {
break;
}
/* Send it to the server */
if ((result = SSL_write(ssl, txbuf, txlen)) <= 0) {
printf("Server closed connection\n");
ERR_print_errors_fp(stderr);
break;
}
/* Wait for the echo */
rxlen = SSL_read(ssl, rxbuf, rxcap);
if (rxlen <= 0) {
printf("Server closed connection\n");
ERR_print_errors_fp(stderr);
break;
} else {
/* Show it */
rxbuf[rxlen] = 0;
printf("Received: %s", rxbuf);
}
}
printf("Client exiting...\n");
} else {
printf("SSL connection to server failed\n\n");
ERR_print_errors_fp(stderr);
}
}
exit:
/* Close up */
if (ssl != NULL) {
SSL_shutdown(ssl);
SSL_free(ssl);
}
SSL_CTX_free(ssl_ctx);
if (client_skt != -1)
close(client_skt);
if (server_skt != -1)
close(server_skt);
OPENSSL_free(txbuf);
OPENSSL_free(rxbuf);
printf("sslecho exiting\n");
return 0;
}

12
demos/sslecho/makefile Normal file
View File

@ -0,0 +1,12 @@
PROG ?= sslecho
all: $(PROG)
# Debug version.
#
$(PROG): main.c
$(CC) -O0 -g3 -W -Wall -I../../include -L../../ -o $(PROG) main.c -lssl -lcrypto
clean:
rm -rf $(PROG) *.o *.obj