diff options
-rw-r--r-- | networking/ssl_helper/README | 16 | ||||
-rw-r--r-- | networking/ssl_helper/ssl_helper.c | 406 | ||||
-rwxr-xr-x | networking/ssl_helper/ssl_helper.sh | 11 |
3 files changed, 433 insertions, 0 deletions
diff --git a/networking/ssl_helper/README b/networking/ssl_helper/README new file mode 100644 index 000000000..4d0508fbb --- /dev/null +++ b/networking/ssl_helper/README | |||
@@ -0,0 +1,16 @@ | |||
1 | Build instructions: | ||
2 | |||
3 | * Unpack matrixssl-3-4-2-open.tgz. | ||
4 | * Build it: "make" | ||
5 | * Drop this directory into matrixssl-3-4-2-open/ssl_helper | ||
6 | * Run ssl_helper.sh to compile and link the helper | ||
7 | |||
8 | Usage: "ssl_helper -d <FILE_DESCRIPTOR>" where FILE_DESCRIPTOR is open to the peer. | ||
9 | |||
10 | In bash, you can do it this way: | ||
11 | $ ssl_helper -d3 3<>/dev/tcp/HOST/PORT | ||
12 | |||
13 | Stdin will be SSL-encrypted and sent to FILE_DESCRIPTOR. | ||
14 | Data from FILE_DESCRIPTOR will be decrypted and sent to stdout. | ||
15 | |||
16 | The plan is to adapt it for wget https helper, and for ssl support in nc. | ||
diff --git a/networking/ssl_helper/ssl_helper.c b/networking/ssl_helper/ssl_helper.c new file mode 100644 index 000000000..d840b1b88 --- /dev/null +++ b/networking/ssl_helper/ssl_helper.c | |||
@@ -0,0 +1,406 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013 INSIDE Secure Corporation | ||
3 | * Copyright (c) PeerSec Networks, 2002-2011 | ||
4 | * All Rights Reserved | ||
5 | * | ||
6 | * The latest version of this code is available at http://www.matrixssl.org | ||
7 | * | ||
8 | * This software is open source; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in WITHOUT ANY WARRANTY; without even the | ||
14 | * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | * See the GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * http://www.gnu.org/copyleft/gpl.html | ||
21 | */ | ||
22 | #include <errno.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <unistd.h> | ||
25 | #include <stdarg.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <stdio.h> | ||
28 | #include <time.h> | ||
29 | #include <poll.h> | ||
30 | #include <sys/socket.h> | ||
31 | |||
32 | #include "matrixssl/matrixsslApi.h" | ||
33 | |||
34 | //#warning "DO NOT USE THESE DEFAULT KEYS IN PRODUCTION ENVIRONMENTS." | ||
35 | |||
36 | /* | ||
37 | * If supporting client authentication, pick ONE identity to auto select a | ||
38 | * certificate and private key that support desired algorithms. | ||
39 | */ | ||
40 | #define ID_RSA /* RSA Certificate and Key */ | ||
41 | |||
42 | #define USE_HEADER_KEYS | ||
43 | |||
44 | /* If the algorithm type is supported, load a CA for it */ | ||
45 | #ifdef USE_HEADER_KEYS | ||
46 | /* CAs */ | ||
47 | # include "sampleCerts/RSA/ALL_RSA_CAS.h" | ||
48 | /* Identity Certs and Keys for use with Client Authentication */ | ||
49 | # ifdef ID_RSA | ||
50 | # define EXAMPLE_RSA_KEYS | ||
51 | # include "sampleCerts/RSA/2048_RSA.h" | ||
52 | # include "sampleCerts/RSA/2048_RSA_KEY.h" | ||
53 | # endif | ||
54 | #endif | ||
55 | |||
56 | static ssize_t safe_write(int fd, const void *buf, size_t count) | ||
57 | { | ||
58 | ssize_t n; | ||
59 | |||
60 | do { | ||
61 | n = write(fd, buf, count); | ||
62 | } while (n < 0 && errno == EINTR); | ||
63 | |||
64 | return n; | ||
65 | } | ||
66 | |||
67 | static ssize_t full_write(int fd, const void *buf, size_t len) | ||
68 | { | ||
69 | ssize_t cc; | ||
70 | ssize_t total; | ||
71 | |||
72 | total = 0; | ||
73 | |||
74 | while (len) { | ||
75 | cc = safe_write(fd, buf, len); | ||
76 | |||
77 | if (cc < 0) { | ||
78 | if (total) { | ||
79 | /* we already wrote some! */ | ||
80 | /* user can do another write to know the error code */ | ||
81 | return total; | ||
82 | } | ||
83 | return cc; /* write() returns -1 on failure. */ | ||
84 | } | ||
85 | |||
86 | total += cc; | ||
87 | buf = ((const char *)buf) + cc; | ||
88 | len -= cc; | ||
89 | } | ||
90 | |||
91 | return total; | ||
92 | } | ||
93 | |||
94 | static void say(const char *s, ...) | ||
95 | { | ||
96 | char buf[256]; | ||
97 | va_list p; | ||
98 | int sz; | ||
99 | |||
100 | va_start(p, s); | ||
101 | sz = vsnprintf(buf, sizeof(buf), s, p); | ||
102 | full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf)); | ||
103 | va_end(p); | ||
104 | } | ||
105 | |||
106 | static void die(const char *s, ...) | ||
107 | { | ||
108 | char buf[256]; | ||
109 | va_list p; | ||
110 | int sz; | ||
111 | |||
112 | va_start(p, s); | ||
113 | sz = vsnprintf(buf, sizeof(buf), s, p); | ||
114 | full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf)); | ||
115 | exit(1); | ||
116 | va_end(p); | ||
117 | } | ||
118 | |||
119 | #if 0 | ||
120 | # define dbg(...) say(__VA_ARGS__) | ||
121 | #else | ||
122 | # define dbg(...) ((void)0) | ||
123 | #endif | ||
124 | |||
125 | static struct pollfd pfd[2] = { | ||
126 | { -1, POLLIN|POLLERR|POLLHUP, 0 }, | ||
127 | { -1, POLLIN|POLLERR|POLLHUP, 0 }, | ||
128 | }; | ||
129 | #define STDIN pfd[0] | ||
130 | #define NETWORK pfd[1] | ||
131 | #define STDIN_READY() (pfd[0].revents & (POLLIN|POLLERR|POLLHUP)) | ||
132 | #define NETWORK_READY() (pfd[1].revents & (POLLIN|POLLERR|POLLHUP)) | ||
133 | |||
134 | static int wait_for_input(void) | ||
135 | { | ||
136 | if (STDIN.fd == NETWORK.fd) /* means both are -1 */ | ||
137 | exit(0); | ||
138 | dbg("polling\n"); | ||
139 | STDIN.revents = NETWORK.revents = 0; | ||
140 | return poll(pfd, 2, -1); | ||
141 | } | ||
142 | |||
143 | static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert) | ||
144 | { | ||
145 | /* Example to allow anonymous connections based on a define */ | ||
146 | if (alert > 0) { | ||
147 | return SSL_ALLOW_ANON_CONNECTION; // = 254 | ||
148 | } | ||
149 | #if 0 | ||
150 | /* Validate the 'not before' and 'not after' dates, etc */ | ||
151 | return PS_FAILURE; /* if we don't like this cert */ | ||
152 | #endif | ||
153 | return PS_SUCCESS; | ||
154 | } | ||
155 | |||
156 | static void close_conn_and_exit(ssl_t *ssl, int fd) | ||
157 | { | ||
158 | unsigned char *buf; | ||
159 | int len; | ||
160 | |||
161 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); | ||
162 | /* Quick attempt to send a closure alert, don't worry about failure */ | ||
163 | if (matrixSslEncodeClosureAlert(ssl) >= 0) { | ||
164 | len = matrixSslGetOutdata(ssl, &buf); | ||
165 | if (len > 0) { | ||
166 | len = safe_write(fd, buf, len); | ||
167 | //if (len > 0) { | ||
168 | // matrixSslSentData(ssl, len); | ||
169 | //} | ||
170 | } | ||
171 | } | ||
172 | //matrixSslDeleteSession(ssl); | ||
173 | shutdown(fd, SHUT_WR); | ||
174 | exit(0); | ||
175 | } | ||
176 | |||
177 | static int encode_data(ssl_t *ssl, const void *data, int len) | ||
178 | { | ||
179 | unsigned char *buf; | ||
180 | int available; | ||
181 | |||
182 | available = matrixSslGetWritebuf(ssl, &buf, len); | ||
183 | if (available < 0) | ||
184 | die("matrixSslGetWritebuf\n"); | ||
185 | if (len > available) | ||
186 | die("len > available\n"); | ||
187 | memcpy(buf, data, len); | ||
188 | if (matrixSslEncodeWritebuf(ssl, len) < 0) | ||
189 | die("matrixSslEncodeWritebuf\n"); | ||
190 | return len; | ||
191 | } | ||
192 | |||
193 | static void flush_to_net(ssl_t *ssl, int fd) | ||
194 | { | ||
195 | int rc; | ||
196 | int len; | ||
197 | unsigned char *buf; | ||
198 | |||
199 | while ((len = matrixSslGetOutdata(ssl, &buf)) > 0) { | ||
200 | dbg("writing net %d bytes\n", len); | ||
201 | if (full_write(fd, buf, len) != len) | ||
202 | die("write to network\n"); | ||
203 | rc = matrixSslSentData(ssl, len); | ||
204 | if (rc < 0) | ||
205 | die("matrixSslSentData\n"); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | static void do_io_until_eof_and_exit(int fd, sslKeys_t *keys) | ||
210 | { | ||
211 | int rc; | ||
212 | int len; | ||
213 | uint32_t len32u; | ||
214 | sslSessionId_t *sid; | ||
215 | ssl_t *ssl; | ||
216 | unsigned char *buf; | ||
217 | |||
218 | NETWORK.fd = fd; | ||
219 | /* Note! STDIN.fd is disabled (-1) until SSL handshake is over: | ||
220 | * we do not attempt to feed any user data to MatrixSSL | ||
221 | * before it is ready. | ||
222 | */ | ||
223 | |||
224 | matrixSslNewSessionId(&sid); | ||
225 | rc = matrixSslNewClientSession(&ssl, keys, sid, 0, certCb, NULL, NULL, 0); | ||
226 | dbg("matrixSslNewClientSession:rc=%d\n", rc); | ||
227 | if (rc != MATRIXSSL_REQUEST_SEND) | ||
228 | die("matrixSslNewClientSession\n"); | ||
229 | |||
230 | len = 0; /* only to suppress compiler warning */ | ||
231 | again: | ||
232 | switch (rc) { | ||
233 | case MATRIXSSL_REQUEST_SEND: | ||
234 | dbg("MATRIXSSL_REQUEST_SEND\n"); | ||
235 | flush_to_net(ssl, fd); | ||
236 | goto poll_input; | ||
237 | |||
238 | case 0: | ||
239 | dbg("rc==0\n"); | ||
240 | flush_to_net(ssl, fd); | ||
241 | goto poll_input; | ||
242 | |||
243 | case MATRIXSSL_REQUEST_CLOSE: | ||
244 | /* what does this mean if we are here? */ | ||
245 | dbg("MATRIXSSL_REQUEST_CLOSE\n"); | ||
246 | close_conn_and_exit(ssl, fd); | ||
247 | |||
248 | case MATRIXSSL_HANDSHAKE_COMPLETE: | ||
249 | dbg("MATRIXSSL_HANDSHAKE_COMPLETE\n"); | ||
250 | /* Init complete, can start reading local user's data: */ | ||
251 | STDIN.fd = STDIN_FILENO; | ||
252 | poll_input: | ||
253 | wait_for_input(); | ||
254 | if (STDIN_READY()) { | ||
255 | char ibuf[4 * 1024]; | ||
256 | dbg("reading stdin\n"); | ||
257 | len = read(STDIN_FILENO, ibuf, sizeof(ibuf)); | ||
258 | if (len < 0) | ||
259 | die("read error on stdin\n"); | ||
260 | if (len == 0) | ||
261 | STDIN.fd = -1; | ||
262 | else { | ||
263 | len = encode_data(ssl, ibuf, len); | ||
264 | if (len) { | ||
265 | rc = MATRIXSSL_REQUEST_SEND; | ||
266 | dbg("rc=%d\n", rc); | ||
267 | goto again; | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | read_network: | ||
272 | if (NETWORK_READY()) { | ||
273 | dbg("%s%s%s\n", | ||
274 | (pfd[1].revents & POLLIN) ? "POLLIN" : "", | ||
275 | (pfd[1].revents & POLLERR) ? "|POLLERR" : "", | ||
276 | (pfd[1].revents & POLLHUP) ? "|POLLHUP" : "" | ||
277 | ); | ||
278 | len = matrixSslGetReadbuf(ssl, &buf); | ||
279 | if (len <= 0) | ||
280 | die("matrixSslGetReadbuf\n"); | ||
281 | dbg("reading net up to %d\n", len); | ||
282 | len = read(fd, buf, len); | ||
283 | dbg("reading net:%d\n", len); | ||
284 | if (len < 0) | ||
285 | die("read error on network\n"); | ||
286 | if (len == 0) /*eof*/ | ||
287 | NETWORK.fd = -1; | ||
288 | len32u = len; | ||
289 | rc = matrixSslReceivedData(ssl, len, &buf, &len32u); | ||
290 | dbg("matrixSslReceivedData:rc=%d\n", rc); | ||
291 | len = len32u; | ||
292 | if (rc < 0) | ||
293 | die("matrixSslReceivedData\n"); | ||
294 | } | ||
295 | goto again; | ||
296 | |||
297 | case MATRIXSSL_APP_DATA: | ||
298 | dbg("MATRIXSSL_APP_DATA: writing stdout\n"); | ||
299 | do { | ||
300 | if (full_write(STDOUT_FILENO, buf, len) != len) | ||
301 | die("write to stdout\n"); | ||
302 | len32u = len; | ||
303 | rc = matrixSslProcessedData(ssl, &buf, &len32u); | ||
304 | //this was seen returning rc=0: | ||
305 | dbg("matrixSslProcessedData:rc=%d\n", rc); | ||
306 | len = len32u; | ||
307 | } while (rc == MATRIXSSL_APP_DATA); | ||
308 | if (pfd[1].fd == -1) { | ||
309 | /* Already saw EOF on network, and we processed | ||
310 | * and wrote out all ssl data. Signal it: | ||
311 | */ | ||
312 | close(STDOUT_FILENO); | ||
313 | } | ||
314 | goto again; | ||
315 | |||
316 | case MATRIXSSL_REQUEST_RECV: | ||
317 | dbg("MATRIXSSL_REQUEST_RECV\n"); | ||
318 | wait_for_input(); | ||
319 | goto read_network; | ||
320 | |||
321 | case MATRIXSSL_RECEIVED_ALERT: | ||
322 | dbg("MATRIXSSL_RECEIVED_ALERT\n"); | ||
323 | /* The first byte of the buffer is the level */ | ||
324 | /* The second byte is the description */ | ||
325 | if (buf[0] == SSL_ALERT_LEVEL_FATAL) | ||
326 | die("Fatal alert\n"); | ||
327 | /* Closure alert is normal (and best) way to close */ | ||
328 | if (buf[1] == SSL_ALERT_CLOSE_NOTIFY) | ||
329 | close_conn_and_exit(ssl, fd); | ||
330 | die("Warning alert\n"); | ||
331 | len32u = len; | ||
332 | rc = matrixSslProcessedData(ssl, &buf, &len32u); | ||
333 | dbg("matrixSslProcessedData:rc=%d\n", rc); | ||
334 | len = len32u; | ||
335 | goto again; | ||
336 | |||
337 | default: | ||
338 | /* If rc < 0 it is an error */ | ||
339 | die("bad rc:%d\n", rc); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | static sslKeys_t* make_keys(void) | ||
344 | { | ||
345 | int rc, CAstreamLen; | ||
346 | char *CAstream; | ||
347 | sslKeys_t *keys; | ||
348 | |||
349 | if (matrixSslNewKeys(&keys) < 0) | ||
350 | die("matrixSslNewKeys\n"); | ||
351 | |||
352 | #ifdef USE_HEADER_KEYS | ||
353 | /* | ||
354 | * In-memory based keys | ||
355 | * Build the CA list first for potential client auth usage | ||
356 | */ | ||
357 | CAstream = NULL; | ||
358 | CAstreamLen = sizeof(RSACAS); | ||
359 | if (CAstreamLen > 0) { | ||
360 | CAstream = psMalloc(NULL, CAstreamLen); | ||
361 | memcpy(CAstream, RSACAS, sizeof(RSACAS)); | ||
362 | } | ||
363 | |||
364 | #ifdef ID_RSA | ||
365 | rc = matrixSslLoadRsaKeysMem(keys, RSA2048, sizeof(RSA2048), | ||
366 | RSA2048KEY, sizeof(RSA2048KEY), (unsigned char*)CAstream, | ||
367 | CAstreamLen); | ||
368 | if (rc < 0) | ||
369 | die("matrixSslLoadRsaKeysMem\n"); | ||
370 | #endif | ||
371 | |||
372 | if (CAstream) | ||
373 | psFree(CAstream); | ||
374 | #endif /* USE_HEADER_KEYS */ | ||
375 | return keys; | ||
376 | } | ||
377 | |||
378 | int main(int argc, char **argv) | ||
379 | { | ||
380 | int fd; | ||
381 | char *fd_str; | ||
382 | |||
383 | if (!argv[1]) | ||
384 | die("Syntax error\n"); | ||
385 | if (argv[1][0] != '-') | ||
386 | die("Syntax error\n"); | ||
387 | if (argv[1][1] != 'd') | ||
388 | die("Syntax error\n"); | ||
389 | fd_str = argv[1] + 2; | ||
390 | if (!fd_str[0]) | ||
391 | fd_str = argv[2]; | ||
392 | if (!fd_str || fd_str[0] < '0' || fd_str[0] > '9') | ||
393 | die("Syntax error\n"); | ||
394 | |||
395 | fd = atoi(fd_str); | ||
396 | if (fd < 3) | ||
397 | die("Syntax error\n"); | ||
398 | |||
399 | if (matrixSslOpen() < 0) | ||
400 | die("matrixSslOpen\n"); | ||
401 | |||
402 | do_io_until_eof_and_exit(fd, make_keys()); | ||
403 | /* does not return */ | ||
404 | |||
405 | return 0; | ||
406 | } | ||
diff --git a/networking/ssl_helper/ssl_helper.sh b/networking/ssl_helper/ssl_helper.sh new file mode 100755 index 000000000..dc52de778 --- /dev/null +++ b/networking/ssl_helper/ssl_helper.sh | |||
@@ -0,0 +1,11 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # I use this to build static uclibc based binary using Aboriginal Linux toolchain: | ||
4 | PREFIX=x86_64- | ||
5 | STATIC=-static | ||
6 | # Standard build: | ||
7 | PREFIX="" | ||
8 | STATIC="" | ||
9 | |||
10 | ${PREFIX}gcc -Os -DPOSIX -I.. -I../sampleCerts -Wall -c ssl_helper.c -o ssl_helper.o | ||
11 | ${PREFIX}gcc $STATIC ssl_helper.o ../libmatrixssl.a -lc ../libmatrixssl.a -o ssl_helper | ||