source: MondoRescue/branches/3.3/mindi-busybox/networking/ssl_helper/ssl_helper.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 9.4 KB
Line 
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
56static 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
67static 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
94static 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
106static 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
125static 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
134static 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
143static 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
156static 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
177static 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
193static 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
209static 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);
226dbg("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;
266dbg("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);
290dbg("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:
305dbg("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);
333dbg("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
343static 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
378int 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}
Note: See TracBrowser for help on using the repository browser.