Tomato 1.26 beta (1786)
[tomato.git] / release / src / router / mssl / mssl.c
blob26ab5ee9471bdc0f22f76ce70fd201947acd4271
1 /*
3 Minimal MatrixSSL Helper
4 Copyright (C) 2006-2009 Jonathan Zarate
6 Licensed under GNU GPL v2 or later.
8 */
10 #define _GNU_SOURCE
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <syslog.h>
16 #include <sys/socket.h>
17 #include <fcntl.h>
18 #include <stdarg.h>
19 #include <errno.h>
21 #include <shutils.h>
23 #include "../matrixssl/matrixSsl.h"
25 #include "mssl.h"
29 #define _dprintf(args...) do { } while(0)
30 // #define _dprintf cprintf
33 typedef struct {
34 ssl_t *ssl;
35 sslBuf_t inbuf; // buffer for decoded data
36 sslBuf_t insock; // buffer for recv() data
37 sslBuf_t outsock; // buffer for send() data
38 int sslend;
39 int sd;
40 } mssl_cookie_t;
42 static sslKeys_t *keys;
46 inline int sb_used(sslBuf_t *b)
48 return b->end - b->start;
51 inline int sb_unused(sslBuf_t *b)
53 return (b->buf + b->size) - b->end;
56 static void sb_free(sslBuf_t *b)
58 free(b->buf);
59 b->start = b->end = b->buf = NULL;
60 b->size = 0;
63 // - expects ->buf to be valid or NULL
64 // - malloc error is fatal
65 static int sb_alloc(sslBuf_t *b, int size)
67 void *p;
69 sb_free(b);
70 if ((p = malloc(size)) == NULL) {
71 syslog(LOG_CRIT, "Not enough memory");
72 exit(1);
74 b->start = b->end = b->buf = p;
75 b->size = size;
76 return 1;
79 // - expects ->buf to be valid or NULL
80 // - malloc error is fatal
81 static int sb_realloc(sslBuf_t *b, int size)
83 void *p;
85 if ((p = realloc(b->buf, size)) == NULL) {
86 syslog(LOG_CRIT, "Not enough memory");
87 exit(1);
89 b->start = p + (b->start - b->buf);
90 b->end = p + (b->end - b->buf);
91 b->buf = p;
92 b->size = size;
93 return 1;
96 static void sb_pack(sslBuf_t *b)
98 int n;
100 if (b->start == b->end) {
101 b->start = b->end = b->buf;
103 else {
104 n = sb_used(b);
105 memmove(b->buf, b->start, n);
106 b->end = b->buf + n;
107 b->start = b->buf;
111 static int sb_read(sslBuf_t *b, unsigned char *buf, int len)
113 int n;
114 n = min(sb_used(b), len);
115 memcpy(buf, b->start, n);
116 b->start += n;
117 if (b->start == b->end) b->start = b->end = b->buf;
118 return n;
122 // -----------------------------------------------------------------------------
125 static ssize_t mssl_read(void *cookie, char *buf, size_t len)
127 mssl_cookie_t *kuki = cookie;
128 int r;
129 unsigned char err, alevel, adesc;
132 _dprintf("%s\n", __FUNCTION__);
134 if (kuki->inbuf.buf) {
135 if (kuki->inbuf.start < kuki->inbuf.end) {
136 r = sb_read(&kuki->inbuf, buf, len);
137 _dprintf("sb_read r=%d\n", r);
138 return r;
140 sb_free(&kuki->inbuf);
143 sb_pack(&kuki->insock);
145 if (kuki->insock.start == kuki->insock.end) {
146 READ:
147 _dprintf("READ\n");
149 while ((r = recv(kuki->sd, kuki->insock.end, sb_unused(&kuki->insock), 0)) == -1) {
150 if (errno != EINTR) {
151 _dprintf("recv failed errno=%d\n", errno);
152 return -1;
155 if (r == 0) {
156 kuki->sslend = 1;
157 return 0;
159 kuki->insock.end += r;
162 sb_alloc(&kuki->inbuf, len);
164 DECODE:
165 _dprintf("DECODE\n");
167 err = 0;
168 alevel = 0;
169 adesc = 0;
171 switch (matrixSslDecode(kuki->ssl, &kuki->insock, &kuki->inbuf, &err, &alevel, &adesc)) {
172 case SSL_SUCCESS:
173 _dprintf("SSL_SUCCESS\n");
174 return 0;
175 case SSL_PROCESS_DATA:
176 _dprintf("SSL_PROCESS_DATA\n");
178 r = sb_used(&kuki->inbuf);
179 _dprintf(" r = %d len = %d\n", r, len);
180 r = min(r, len);
181 memcpy(buf, kuki->inbuf.start, r);
182 kuki->inbuf.start += r;
183 return r;
184 case SSL_SEND_RESPONSE:
185 _dprintf("SSL_SEND_RESPONSE\n");
186 _dprintf("send %d\n", sb_used(&kuki->inbuf));
188 while ((r = send(kuki->sd, kuki->inbuf.start, sb_used(&kuki->inbuf), MSG_NOSIGNAL)) == -1) {
189 if (errno != EINTR) {
190 _dprintf("send error\n");
191 return -1;
194 kuki->inbuf.start += r;
195 if (kuki->inbuf.start != kuki->inbuf.end) _dprintf("inbuf.start != inbuf.end\n");
196 kuki->inbuf.start = kuki->inbuf.end = kuki->inbuf.buf;
197 return 0;
198 case SSL_ERROR:
199 _dprintf("ssl error %d\n", err);
201 if (kuki->inbuf.start < kuki->inbuf.end) {
202 send(kuki->sd, kuki->inbuf.start, sb_used(&kuki->inbuf), MSG_NOSIGNAL);
204 errno = EIO;
205 return -1;
206 case SSL_ALERT:
207 _dprintf("SSL_ALERT\n");
209 if (adesc == SSL_ALERT_CLOSE_NOTIFY) {
210 kuki->sslend = 1;
211 return 0;
214 _dprintf("ssl closing on alert level=%d desc=%d\n", alevel, adesc);
215 errno = EIO;
216 return -1;
217 case SSL_PARTIAL:
218 _dprintf("SSL_PARTIAL insock.size=%d %d\n", kuki->insock.size, SSL_MAX_BUF_SIZE);
220 if ((kuki->insock.start == kuki->insock.buf) && (kuki->insock.end == (kuki->insock.buf + kuki->insock.size))) {
221 if (kuki->insock.size > SSL_MAX_BUF_SIZE) return -1;
222 sb_realloc(&kuki->insock, kuki->insock.size * 2);
225 if (kuki->inbuf.start != kuki->inbuf.end) {
226 _dprintf("!! inbuf.start != inbuf.end\n");
229 sb_free(&kuki->inbuf);
230 goto READ;
231 case SSL_FULL:
232 _dprintf("SSL_FULL\n");
234 sb_alloc(&kuki->inbuf, kuki->inbuf.size * 2);
235 goto DECODE;
238 return 0;
241 static ssize_t mssl_write(void *cookie, const char *buf, size_t len)
243 mssl_cookie_t *kuki = cookie;
244 int r;
245 int nw;
247 _dprintf("%s\n", __FUNCTION__);
249 nw = 0;
250 sb_pack(&kuki->outsock);
251 if (buf == NULL) goto PUMP;
253 RETRY:
254 switch (matrixSslEncode(kuki->ssl, (unsigned char *)buf, len, &kuki->outsock)) {
255 case SSL_ERROR:
256 errno = EIO;
257 _dprintf("SSL_ERROR\n");
258 return -1;
259 case SSL_FULL:
260 if (kuki->outsock.size > SSL_MAX_BUF_SIZE) {
261 errno = EFBIG;
262 _dprintf("outsock.size > max\n");
263 return -1;
265 sb_realloc(&kuki->outsock, kuki->outsock.size * 2);
266 goto RETRY;
269 PUMP:
270 while ((r = send(kuki->sd, kuki->outsock.start, sb_used(&kuki->outsock), MSG_NOSIGNAL)) == -1) {
271 if (errno != EINTR) {
272 _dprintf("send error %d\n", errno);
273 return -1;
276 kuki->outsock.start += r;
277 nw += r;
279 if (kuki->outsock.start < kuki->outsock.end) {
280 _dprintf("start < end\n");
281 goto PUMP;
284 return nw;
287 static int mssl_seek(void *cookie, __offmax_t *pos, int whence)
289 _dprintf("%s()\n", __FUNCTION__);
290 errno = EIO;
291 return -1;
294 static int mssl_close(void *cookie)
296 mssl_cookie_t *kuki = cookie;
298 _dprintf("%s()\n", __FUNCTION__);
300 if (!kuki) return 0;
302 if (kuki->ssl) {
303 if (kuki->outsock.buf) {
304 mssl_write(kuki, NULL, 0);
306 kuki->outsock.start = kuki->outsock.end = kuki->outsock.buf;
307 matrixSslEncodeClosureAlert(kuki->ssl, &kuki->outsock);
308 fcntl(kuki->sd, F_SETFL, fcntl(kuki->sd, F_GETFL) | O_NONBLOCK);
309 send(kuki->sd, kuki->outsock.start, sb_used(&kuki->outsock), MSG_NOSIGNAL);
312 matrixSslDeleteSession(kuki->ssl);
313 kuki->ssl = NULL;
315 sb_free(&kuki->inbuf);
316 sb_free(&kuki->insock);
317 sb_free(&kuki->outsock);
319 free(kuki);
320 return 0;
323 static int cert_valid(sslCertInfo_t *cert, void *arg)
325 // note: no validation!
326 return SSL_ALLOW_ANON_CONNECTION;
329 static const cookie_io_functions_t mssl = {
330 mssl_read, mssl_write, mssl_seek, mssl_close
333 static FILE *_ssl_fopen(int sd, int client)
335 unsigned char buf[1024];
336 int r;
337 int n;
338 mssl_cookie_t *kuki;
339 FILE *f;
341 _dprintf("%s()\n", __FUNCTION__);
343 if ((kuki = calloc(1, sizeof(*kuki))) == NULL) {
344 errno = ENOMEM;
345 return NULL;
347 kuki->sd = sd;
349 if (matrixSslNewSession(&kuki->ssl, keys, NULL, client ? 0 : SSL_FLAGS_SERVER) < 0) {
350 _dprintf("%s: matrixSslNewSession failed\n", __FUNCTION__);
351 goto ERROR;
354 sb_alloc(&kuki->insock, 1024);
355 sb_alloc(&kuki->outsock, 2048);
357 if (client) {
358 matrixSslSetCertValidator(kuki->ssl, cert_valid, NULL);
360 n = matrixSslEncodeClientHello(kuki->ssl, &kuki->outsock, 0);
361 if (n < 0) {
362 _dprintf("%s: matrixSslEncodeClientHello failed\n", __FUNCTION__);
363 goto ERROR;
365 if (mssl_write(kuki, NULL, 0) <= 0) {
366 _dprintf("%s: error while writing HELLO\n", __FUNCTION__);
367 goto ERROR;
371 MORE:
372 r = mssl_read(kuki, buf, sizeof(buf));
373 if (r == 0) {
374 if (kuki->sslend) {
375 _dprintf("%s: end reached\n", __FUNCTION__);
376 errno = EIO;
377 goto ERROR;
379 if (matrixSslHandshakeIsComplete(kuki->ssl) == 0) {
380 _dprintf("%s: =0 goto more\n", __FUNCTION__);
381 goto MORE;
383 if ((f = fopencookie(kuki, "r+", mssl)) == NULL) {
384 _dprintf("%s: fopencookie failed\n", __FUNCTION__);
385 goto ERROR;
387 return f;
390 _dprintf("%s: read error r=%d errno=%d\n", __FUNCTION__, r, errno);
391 errno = EIO;
393 ERROR:
394 mssl_close(kuki);
395 return NULL;
398 FILE *ssl_server_fopen(int sd)
400 _dprintf("%s()\n", __FUNCTION__);
401 return _ssl_fopen(sd, 0);
404 FILE *ssl_client_fopen(int sd)
406 _dprintf("%s()\n", __FUNCTION__);
407 return _ssl_fopen(sd, 1);
410 int ssl_init(char *cert, char *priv)
412 if (matrixSslOpen() < 0) {
413 _dprintf("matrixSslOpen failed");
414 return 0;
416 if (matrixSslReadKeys(&keys, cert, priv, NULL, NULL) < 0) {
417 matrixSslClose();
418 _dprintf("matrixSslReadKeys failed");
419 return 0;
421 return 1;