1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/*
* Licensed under GPLv2, see file LICENSE in this source tree.
*/
//config:config SSL_SERVER
//config: bool "ssl_server (test TLS server)"
//config: default y
//config: select TLS
//config: help
//config: inetd-style TLS server. Stdin/stdout are already connected
//config: to an accepted TCP socket.
//applet:IF_SSL_SERVER(APPLET(ssl_server, BB_DIR_USR_BIN, BB_SUID_DROP))
//kbuild:lib-$(CONFIG_SSL_SERVER) += ssl_server.o
//usage:#define ssl_server_trivial_usage
//usage: "-f PRIVKEY_CERT.pem PROG ARGS"
//usage:#define ssl_server_full_usage ""
//usage: "Inetd-style TLS server\n"
//usage: "\n -f PEMFILE HAProxy-style CRT file"
/*
# Generate RSA key and certificate
openssl req -x509 -newkey rsa:4096 \
-keyout $HOSTNAME-rsa.key \
-out $HOSTNAME-rsa.crt \
-sha256 -days 9999 -nodes \
-subj /CN=$HOSTNAME \
-addext "subjectAltName=DNS:$HOSTNAME"
# Generate ECDSA key and certificate
openssl genpkey -algorithm EC \
-pkeyopt ec_paramgen_curve:prime256v1 \
-out $HOSTNAME-ecdsa.key
fopenssl req -new -x509 \
-key $HOSTNAME-ecdsa.key \
-out $HOSTNAME-ecdsa.crt \
-sha256 -days 9999 \
-subj "/CN=$HOSTNAME" \
-addext "subjectAltName=DNS:$HOSTNAME"
# Concatenate all these files into PRIVKEY_CERT.pem
{ cat $HOSTNAME-rsa.key
cat $HOSTNAME-rsa.crt
cat $HOSTNAME-ecdsa.key
cat $HOSTNAME-ecdsa.crt
} >PRIVKEY_CERT.pem
*/
#include "libbb.h"
/* TLS server applet.
*
* To generate a test RSA certificate and key:
* openssl req -x509 -newkey rsa:2048 -days 9999 -nodes \
* -subj '/CN=localhost' \
* -out cert.pem -keyout privkey.pem
* Convert to DER format:
* openssl x509 -in cert.pem -outform DER -out cert.der
* openssl rsa -in privkey.pem -outform DER -out privkey.der
*
* Run the server:
* tcpsvd 127.0.0.1 4433 ssl_server -p privkey.der -c cert.der -e echo 'Hello world'
*
* Test with:
* openssl s_client -connect localhost:4433
*/
int ssl_server_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int ssl_server_main(int argc UNUSED_PARAM, char **argv)
{
struct fd_pair to_prog;
struct fd_pair from_prog;
pid_t pid;
tls_state_t *tls;
const char *pem_file;
unsigned opt;
tls = new_tls_state();
/* "+": stop on first non-option */
opt = getopt32(argv, "+""vf:",
&pem_file
);
argv += optind;
if (!argv[0] || !(opt & 2))
bb_show_usage();
/* In inetd mode, stdin/stdout are the socket.
* But tls_run_copy_loop() needs *non-TLS* fds on STDIN and STDOUT.
* Shuffle them.
*/
xdup2(STDIN_FILENO, 3);
xdup2(STDOUT_FILENO, 4);
tls->ifd = 3;
tls->ofd = 4;
/* This can abort on errors */
tls_handshake_as_server(tls, pem_file);
/* Run PROG, wrap its data in TLS and I/O to socket */
xpiped_pair(to_prog);
xpiped_pair(from_prog);
pid = xvfork();
if (pid == 0) {
/* Child: run the program */
/* NB: close _first_, then move fds! */
close(to_prog.wr);
close(from_prog.rd);
xmove_fd(to_prog.rd, STDIN_FILENO);
xmove_fd(from_prog.wr, STDOUT_FILENO);
BB_EXECVP_or_die(argv);
}
/* Parent: close child ends of pipes */
close(to_prog.rd);
close(from_prog.wr);
/* tls_run_copy_loop() needs non-TLS fds on STDIN and STDOUT */
xmove_fd(from_prog.rd, STDIN_FILENO);
xmove_fd(to_prog.wr, STDOUT_FILENO);
tls_run_copy_loop(tls, /*flags*/ TLSLOOP_EXIT_ON_LOCAL_EOF);
return EXIT_SUCCESS;
}
|