3 Minimal MatrixSSL Helper
4 Copyright (C) 2006-2009 Jonathan Zarate
6 Licensed under GNU GPL v2 or later.
16 #include <sys/socket.h>
19 #include <netinet/in.h>
23 #include "matrixSsl.h"
28 #define _dprintf(args...) while (0) {}
32 sslBuf_t inbuf
; // buffer for decoded data
33 sslBuf_t insock
; // buffer for recv() data
34 sslBuf_t outsock
; // buffer for send() data
40 static sslKeys_t
*keys
;
44 static inline int sb_used(sslBuf_t
*b
)
46 return b
->end
- b
->start
;
49 static inline int sb_unused(sslBuf_t
*b
)
51 return (b
->buf
+ b
->size
) - b
->end
;
54 static inline void sb_free(sslBuf_t
*b
)
57 b
->start
= b
->end
= b
->buf
= NULL
;
61 // - expects ->buf to be valid or NULL
62 // - malloc error is fatal
63 static inline int sb_alloc(sslBuf_t
*b
, int size
)
65 _dprintf("%s()\n", __FUNCTION__
);
70 if ((p
= malloc(size
)) == NULL
) {
71 syslog(LOG_CRIT
, "Not enough memory");
75 b
->start
= b
->end
= b
->buf
= p
;
80 // - expects ->buf to be valid or NULL
81 // - malloc error is fatal
82 static inline int sb_realloc(sslBuf_t
*b
, int size
)
84 _dprintf("%s()\n", __FUNCTION__
);
87 if ((p
= realloc(b
->buf
, size
)) == NULL
) {
88 syslog(LOG_CRIT
, "Not enough memory");
91 b
->start
= p
+ (b
->start
- b
->buf
);
92 b
->end
= p
+ (b
->end
- b
->buf
);
98 static inline void sb_pack(sslBuf_t
*b
)
100 _dprintf("%s()\n", __FUNCTION__
);
101 if (b
->buf
< b
->start
) {
102 if (b
->start
== b
->end
) {
103 b
->start
= b
->end
= b
->buf
;
106 memmove(b
->buf
, b
->start
, sb_used(b
));
107 b
->end
-= b
->start
- b
->buf
;
113 static inline int sb_read(sslBuf_t
*b
, unsigned char *buf
, int len
)
115 _dprintf("%s()\n", __FUNCTION__
);
117 n
= min(sb_used(b
), len
);
118 memcpy(buf
, b
->start
, n
);
120 if (b
->start
== b
->end
) b
->start
= b
->end
= b
->buf
;
125 // -----------------------------------------------------------------------------
128 static ssize_t
mssl_read(void *cookie
, char *buf
, size_t len
)
130 mssl_cookie_t
*kuki
= cookie
;
132 unsigned char err
, alevel
, adesc
;
134 _dprintf("%s\n", __FUNCTION__
);
136 if (kuki
->ssl
== NULL
|| len
<= 0) {
141 If inbuf is valid, then we have previously decoded data that must be
142 returned, return as much as possible. Once all buffered data is
143 returned, free the inbuf.
145 if (kuki
->inbuf
.buf
) {
146 if (kuki
->inbuf
.start
< kuki
->inbuf
.end
) {
147 r
= sb_read(&(kuki
->inbuf
), buf
, len
);
148 _dprintf("sb_read r=%d\n", r
);
151 sb_free(&(kuki
->inbuf
));
154 /* Pack the buffered socket data (if any) so that start is at zero. */
155 sb_pack(&(kuki
->insock
));
158 Read up to as many bytes as there are remaining in the buffer. We could
159 Have encrypted data already cached in conn->insock, but might as well read more
162 if (kuki
->insock
.start
== kuki
->insock
.end
) {
166 while ((r
= recv(kuki
->sd
, kuki
->insock
.end
, sb_unused(&kuki
->insock
), 0)) == -1) {
167 if (errno
!= EINTR
) {
168 _dprintf("recv failed errno=%d\n", errno
);
176 kuki
->insock
.end
+= r
;
179 /* Define a temporary sslBuf */
180 if (kuki
->inbuf
.buf
== (unsigned char*)buf
) kuki
->inbuf
.buf
= NULL
;
181 sb_alloc(&(kuki
->inbuf
), len
);
184 _dprintf("DECODE\n");
186 /* Decode the data we just read from the socket */
191 r
= matrixSslDecode(kuki
->ssl
, &kuki
->insock
, &kuki
->inbuf
, &err
, &alevel
, &adesc
);
194 /* Successfully decoded an application data record, and placed in tmp buf */
195 _dprintf("SSL_SUCCESS\n");
197 case SSL_PROCESS_DATA
:
199 Copy as much as we can from the temp buffer into the caller's buffer
200 and leave the remainder in conn->inbuf until the next call to read
201 It is possible that len > data in buffer if the encoded record
202 was longer than len, but the decoded record isn't!
204 _dprintf("SSL_PROCESS_DATA\n");
206 r
= sb_used(&kuki
->inbuf
);
207 _dprintf(" r = %d len = %d\n", r
, len
);
209 memcpy(buf
, kuki
->inbuf
.start
, r
);
210 kuki
->inbuf
.start
+= r
;
212 case SSL_SEND_RESPONSE
:
214 We've decoded a record that requires a response into tmp
215 If there is no data to be flushed in the out buffer, we can write out
216 the contents of the tmp buffer. Otherwise, we need to append the data
217 to the outgoing data buffer and flush it out.
219 _dprintf("SSL_SEND_RESPONSE\n");
220 _dprintf("send %d\n", sb_used(&kuki
->inbuf
));
222 while ((r
= send(kuki
->sd
, (char *)kuki
->inbuf
.start
, sb_used(&kuki
->inbuf
), MSG_NOSIGNAL
)) == -1) {
223 if (errno
!= EINTR
) {
224 _dprintf("send error\n");
228 kuki
->inbuf
.start
+= r
;
229 if (kuki
->inbuf
.start
!= kuki
->inbuf
.end
) {
230 _dprintf("inbuf.start != inbuf.end\n");
232 kuki
->inbuf
.start
= kuki
->inbuf
.end
= kuki
->inbuf
.buf
;
236 There was an error decoding the data, or encoding the out buffer.
237 There may be a response data in the out buffer, so try to send.
238 We try a single hail-mary send of the data, and then close the socket.
239 Since we're closing on error, we don't worry too much about a clean flush.
241 _dprintf("ssl error %d\n", err
);
243 if (kuki
->inbuf
.start
< kuki
->inbuf
.end
) {
244 fcntl(kuki
->sd
, F_SETFL
, fcntl(kuki
->sd
, F_GETFL
) | O_NONBLOCK
);
245 send(kuki
->sd
, kuki
->inbuf
.start
, sb_used(&kuki
->inbuf
), MSG_NOSIGNAL
);
251 We've decoded an alert. The level and description passed into
252 matrixSslDecode are filled in with the specifics.
254 _dprintf("SSL_ALERT\n");
256 if (adesc
== SSL_ALERT_CLOSE_NOTIFY
) {
261 _dprintf("ssl closing on alert level=%d desc=%d\n", alevel
, adesc
);
266 We have a partial record, we need to read more data off the socket.
267 If we have a completely full conn->insock buffer, we'll need to grow it
268 here so that we CAN read more data when called the next time.
270 _dprintf("SSL_PARTIAL insock.size=%d %d\n", kuki
->insock
.size
, SSL_MAX_BUF_SIZE
);
272 if ((kuki
->insock
.start
== kuki
->insock
.buf
) && (kuki
->insock
.end
== (kuki
->insock
.buf
+ kuki
->insock
.size
))) {
273 if (kuki
->insock
.size
> SSL_MAX_BUF_SIZE
)
275 sb_realloc(&kuki
->insock
, kuki
->insock
.size
* 2);
278 if (kuki
->inbuf
.start
!= kuki
->inbuf
.end
) {
279 _dprintf("!! inbuf.start != inbuf.end\n");
282 sb_free(&kuki
->inbuf
);
286 The out buffer is too small to fit the decoded or response
287 data. Increase the size of the buffer and call decode again
289 _dprintf("SSL_FULL\n");
291 if (kuki
->inbuf
.buf
== (unsigned char*)buf
) kuki
->inbuf
.buf
= NULL
;
292 sb_alloc(&(kuki
->inbuf
), kuki
->inbuf
.size
* 2);
297 We consolidated some of the returns here because we must ensure
298 that conn->inbuf is cleared if pointing at caller's buffer, otherwise
299 it will be freed later on.
302 if (kuki
->inbuf
.buf
== (unsigned char*)buf
) {
303 kuki
->inbuf
.buf
= NULL
;
307 if (kuki
->inbuf
.buf
== (unsigned char*)buf
) {
308 kuki
->inbuf
.buf
= NULL
;
313 static int _socket_write(int sd
, sslBuf_t
*out
)
315 _dprintf("%s\n", __FUNCTION__
);
321 while (out
->start
< out
->end
) {
322 while ((r
= send(sd
, out
->start
, sb_used(out
), MSG_NOSIGNAL
)) == -1) {
323 if (errno
!= EINTR
) {
324 _dprintf("send error %d\n", errno
);
330 return (int)(out
->start
- s
);
333 static ssize_t
_mssl_write(void *cookie
, const char *buf
, size_t len
)
335 mssl_cookie_t
*kuki
= cookie
;
338 _dprintf("%s(len=%d), outbufcnt=%d\n", __FUNCTION__
, len
, kuki
->outbufcnt
);
341 /* Pack the buffered socket data (if any) so that start is at zero. */
342 sb_pack(&kuki
->outsock
);
345 If there is buffered output data, the caller must be trying to
346 send the same amount of data as last time. We don't support
347 sending additional data until the original buffered request has
348 been completely sent.
350 if (kuki
->outbufcnt
> 0 && len
!= kuki
->outbufcnt
)
353 /* Encode the caller's data */
354 if (kuki
->outbufcnt
== 0) {
356 r
= matrixSslEncode(kuki
->ssl
, (unsigned char *)buf
, len
, &kuki
->outsock
);
357 _dprintf("%s: encode r=%d\n", __FUNCTION__
, r
);
361 _dprintf("SSL_ERROR\n");
364 if (kuki
->outsock
.size
> SSL_MAX_BUF_SIZE
) {
366 _dprintf("outsock.size > max\n");
369 sb_realloc(&kuki
->outsock
, kuki
->outsock
.size
* 2);
374 /* We've got data to send. */
375 _dprintf("%s: sending %d bytes\n", __FUNCTION__
, sb_used(&kuki
->outsock
));
376 while ((r
= send(kuki
->sd
, kuki
->outsock
.start
, sb_used(&kuki
->outsock
), MSG_NOSIGNAL
)) == -1) {
377 if (errno
!= EINTR
) {
378 _dprintf("send error %d\n", errno
);
382 kuki
->outsock
.start
+= r
;
385 If we wrote it all return the length, otherwise remember the number of
386 bytes passed in, and return 0 to be called again later.
388 _dprintf("exiting %s(): outbufcnt=%d, len=%d\n", __FUNCTION__
, kuki
->outbufcnt
, len
);
389 if (kuki
->outsock
.start
== kuki
->outsock
.end
) {
393 kuki
->outbufcnt
= len
;
397 static ssize_t
mssl_write(void *cookie
, const char *buf
, size_t len
)
399 _dprintf("%s\n", __FUNCTION__
);
404 int maxwrite
= SSL_MAX_BUF_SIZE
/ 2;
406 if (len
> maxwrite
) {
407 while (offset
< len
&& r
>= 0) {
410 r
= _mssl_write(cookie
, (char*)(buf
+ offset
), min(len
- offset
, maxwrite
));
412 _dprintf("multiple write: r = %d\n", r
);
420 r
= _mssl_write(cookie
, buf
, len
);
421 _dprintf("single write: r = %d\n", r
);
428 static int mssl_seek(void *cookie
, __offmax_t
*pos
, int whence
)
430 _dprintf("%s()\n", __FUNCTION__
);
435 static int mssl_close(void *cookie
)
437 mssl_cookie_t
*kuki
= cookie
;
439 _dprintf("%s()\n", __FUNCTION__
);
444 if (kuki
->outsock
.buf
) {
445 sb_pack(&kuki
->outsock
);
446 _socket_write(kuki
->sd
, &(kuki
->outsock
));
448 kuki
->outsock
.start
= kuki
->outsock
.end
= kuki
->outsock
.buf
;
449 matrixSslEncodeClosureAlert(kuki
->ssl
, &kuki
->outsock
);
450 fcntl(kuki
->sd
, F_SETFL
, fcntl(kuki
->sd
, F_GETFL
) | O_NONBLOCK
);
451 send(kuki
->sd
, kuki
->outsock
.start
, sb_used(&kuki
->outsock
), MSG_NOSIGNAL
);
454 matrixSslDeleteSession(kuki
->ssl
);
457 sb_free(&kuki
->inbuf
);
458 sb_free(&kuki
->insock
);
459 sb_free(&kuki
->outsock
);
465 static int cert_valid(sslCertInfo_t
*cert
, void *arg
)
467 // note: no validation!
468 return SSL_ALLOW_ANON_CONNECTION
;
471 static const cookie_io_functions_t mssl
= {
472 mssl_read
, mssl_write
, mssl_seek
, mssl_close
475 static FILE *_ssl_fopen(int sd
, int client
)
477 unsigned char buf
[1024];
483 _dprintf("%s()\n", __FUNCTION__
);
485 if ((kuki
= calloc(1, sizeof(*kuki
))) == NULL
) {
492 if (matrixSslNewSession(&(kuki
->ssl
), keys
, NULL
, client
? 0 : SSL_FLAGS_SERVER
) < 0) {
493 _dprintf("%s: matrixSslNewSession failed\n", __FUNCTION__
);
497 sb_alloc(&(kuki
->insock
), 1024);
498 sb_alloc(&(kuki
->outsock
), 2048);
499 sb_alloc(&(kuki
->inbuf
), 0);
502 matrixSslSetCertValidator(kuki
->ssl
, cert_valid
, keys
);
504 n
= matrixSslEncodeClientHello(kuki
->ssl
, &(kuki
->outsock
), 0);
506 _dprintf("%s: matrixSslEncodeClientHello failed\n", __FUNCTION__
);
509 if (_socket_write(kuki
->sd
, &(kuki
->outsock
)) < 0) {
510 _dprintf("%s: error while writing HELLO\n", __FUNCTION__
);
513 kuki
->outsock
.start
= kuki
->outsock
.end
= kuki
->outsock
.buf
;
517 r
= mssl_read(kuki
, buf
, sizeof(buf
));
518 if (r
> 0 || (r
== 0 && matrixSslHandshakeIsComplete(kuki
->ssl
) == 0)) {
520 _dprintf("%s: end reached\n", __FUNCTION__
);
524 _dprintf("%s: =0 goto more\n", __FUNCTION__
);
528 _dprintf("%s: read error r=%d errno=%d\n", __FUNCTION__
, r
, errno
);
533 if ((f
= fopencookie(kuki
, "r+", mssl
)) == NULL
) {
534 _dprintf("%s: fopencookie failed\n", __FUNCTION__
);
544 FILE *ssl_server_fopen(int sd
)
546 _dprintf("%s()\n", __FUNCTION__
);
547 return _ssl_fopen(sd
, 0);
550 FILE *ssl_client_fopen(int sd
)
552 _dprintf("%s()\n", __FUNCTION__
);
553 return _ssl_fopen(sd
, 1);
556 int mssl_init(char *cert
, char *priv
)
558 _dprintf("%s()\n", __FUNCTION__
);
559 if (matrixSslOpen() < 0) {
560 _dprintf("matrixSslOpen failed");
563 if (matrixSslReadKeys(&keys
, cert
, priv
, NULL
, NULL
) < 0) {
565 _dprintf("matrixSslReadKeys failed");