Branch oldpackages for 14.07
[14.07/packages.git] / net / mini_httpd / files / matrixssl_helper.c
1 /*
2  * MatrixSSL helper functions
3  *
4  * Copyright (C) 2005 Nicolas Thill <nthill@free.fr>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * Portions borrowed from MatrixSSL example code
17  *
18  */
19
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netinet/tcp.h>
23 #include <arpa/inet.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "matrixssl_helper.h"
31
32 #define SSL_SOCKET_EOF  0x0001
33 #define SSL_SOCKET_CLOSE_NOTIFY  0x0002
34
35 #define min(a, b)  ( (a) < (b) ) ? (a) : (b)
36
37 static int _ssl_read(SSL *ssl, char *buf, int len);
38 static int _ssl_write(SSL *ssl, char *buf, int len);
39 static void _ssl_setSocketBlock(int fd);
40 static void _ssl_setSocketNonblock(int fd);
41 static void _ssl_closeSocket(int fd);
42
43
44 SSL * SSL_new(sslKeys_t *keys)
45 {
46         SSL * ssl;
47         ssl = (SSL *)malloc(sizeof(SSL));
48         
49         if (!ssl) return 0;
50         
51         ssl->keys = keys;
52         if ( matrixSslNewSession(&(ssl->ssl), ssl->keys, NULL, SSL_FLAGS_SERVER) < 0 ) {
53         }
54         
55         ssl->insock.size = 1024;
56         ssl->insock.buf = ssl->insock.start = ssl->insock.end =
57                 (unsigned char *)malloc(ssl->insock.size);
58         
59         ssl->outsock.size = 1024;
60         ssl->outsock.buf = ssl->outsock.start = ssl->outsock.end = 
61                 (unsigned char *)malloc(ssl->outsock.size);
62         
63         ssl->inbuf.size = 0;
64         ssl->inbuf.buf = ssl->inbuf.start = ssl->inbuf.end = NULL;
65         
66         return ssl;
67 }
68
69
70 int SSL_accept(SSL *ssl) {
71
72         unsigned char buf[1024];
73         int status, rc;
74         
75 readMore:
76         rc = _ssl_read(ssl, buf, sizeof(buf));
77         if (rc == 0) {
78                 if (ssl->status == SSL_SOCKET_EOF || ssl->status == SSL_SOCKET_CLOSE_NOTIFY) {
79                         SSL_free(ssl);
80                         return -1;
81                 }
82                 if (matrixSslHandshakeIsComplete(ssl->ssl) == 0) {
83                         goto readMore;
84                 }
85         } else if (rc > 0) {
86                 return 0;
87         } else {
88                 SSL_free(ssl);
89                 return -1;
90         }
91         
92         return 1;
93 }
94
95
96 void SSL_set_fd(SSL *ssl, int fd) {
97         ssl->fd = fd;
98 }
99
100
101 int SSL_read(SSL *ssl, char *buf, int len) {
102         int rc;
103 readMore:
104         rc = _ssl_read(ssl, buf, len);
105         if (rc <= 0) {
106                 if (rc < 0 || ssl->status == SSL_SOCKET_EOF || ssl->status == SSL_SOCKET_CLOSE_NOTIFY) {
107                         _ssl_closeSocket(ssl->fd);
108                         return rc;
109                 }
110                 goto readMore;
111         }
112         return rc;
113 }
114
115
116 int SSL_write(SSL *ssl, char *buf, int len) {
117         int rc;
118 writeMore:
119         rc = _ssl_write(ssl, buf, len);
120         if (rc <= 0) {
121                 if (rc < 0) {
122                         return rc;
123                 }
124                 goto writeMore;
125         }
126         return rc;
127 }
128
129
130 void SSL_free(SSL * ssl)
131 {
132         matrixSslDeleteSession(ssl->ssl);
133         if (ssl->insock.buf) {
134                 free(ssl->insock.buf);
135         }
136         if (ssl->outsock.buf) {
137                 free(ssl->outsock.buf);
138         }
139         if (ssl->inbuf.buf) {
140                 free(ssl->inbuf.buf);
141         }
142         free(ssl);
143 }
144
145
146
147 static void _ssl_setSocketBlock(int fd)
148 {
149         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
150         fcntl(fd, F_SETFD, FD_CLOEXEC);
151 }
152
153
154 static void _ssl_setSocketNonblock(int fd)
155 {
156         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
157 }
158
159
160 static void _ssl_closeSocket(int fd)
161 {
162         char buf[32];
163
164         if (fd != -1) {
165                 _ssl_setSocketNonblock(fd);
166                 if (shutdown(fd, 1) >= 0) {
167                         while (recv(fd, buf, sizeof(buf), 0) > 0);
168                 }
169                 close(fd);
170         }
171 }
172
173
174 static int _ssl_read(SSL *ssl, char *buf, int len)
175 {
176         int bytes, rc, remaining;
177         unsigned char error, alertLevel, alertDescription, performRead;
178
179         ssl->status = 0;
180
181         if (ssl->ssl == NULL || len <= 0) {
182                 return -1;
183         }
184 /*
185         If inbuf is valid, then we have previously decoded data that must be
186         returned, return as much as possible.  Once all buffered data is
187         returned, free the inbuf.
188 */
189         if (ssl->inbuf.buf) {
190                 if (ssl->inbuf.start < ssl->inbuf.end) {
191                         remaining = (int)(ssl->inbuf.end - ssl->inbuf.start);
192                         bytes = (int)min(len, remaining);
193                         memcpy(buf, ssl->inbuf.start, bytes);
194                         ssl->inbuf.start += bytes;
195                         return bytes;
196                 }
197                 free(ssl->inbuf.buf);
198                 ssl->inbuf.buf = NULL;
199         }
200 /*
201         Pack the buffered socket data (if any) so that start is at zero.
202 */
203         if (ssl->insock.buf < ssl->insock.start) {
204                 if (ssl->insock.start == ssl->insock.end) {
205                         ssl->insock.start = ssl->insock.end = ssl->insock.buf;
206                 } else {
207                         memmove(ssl->insock.buf, ssl->insock.start, ssl->insock.end - ssl->insock.start);
208                         ssl->insock.end -= (ssl->insock.start - ssl->insock.buf);
209                         ssl->insock.start = ssl->insock.buf;
210                 }
211         }
212 /*
213         Read up to as many bytes as there are remaining in the buffer.  We could
214         Have encrypted data already cached in conn->insock, but might as well read more
215         if we can.
216 */
217         performRead = 0;
218 readMore:
219         if (ssl->insock.end == ssl->insock.start || performRead) {
220                 performRead = 1;
221                 bytes = recv(ssl->fd, (char *)ssl->insock.end, 
222                         (int)((ssl->insock.buf + ssl->insock.size) - ssl->insock.end), MSG_NOSIGNAL);
223                 if (bytes == -1) {
224                         ssl->status = errno;
225                         return -1;
226                 }
227                 if (bytes == 0) {
228                         ssl->status = SSL_SOCKET_EOF;
229                         return 0;
230                 }
231                 ssl->insock.end += bytes;
232         }
233 /*
234         Define a temporary sslBuf
235 */
236         ssl->inbuf.start = ssl->inbuf.end = ssl->inbuf.buf = (unsigned char *)malloc(len);
237         ssl->inbuf.size = len;
238 /*
239         Decode the data we just read from the socket
240 */
241 decodeMore:
242         error = 0;
243         alertLevel = 0;
244         alertDescription = 0;
245
246         rc = matrixSslDecode(ssl->ssl, &ssl->insock, &ssl->inbuf, &error, &alertLevel, 
247                 &alertDescription);
248         switch (rc) {
249 /*
250         Successfully decoded a record that did not return data or require a response.
251 */
252         case SSL_SUCCESS:
253                 return 0;
254 /*
255         Successfully decoded an application data record, and placed in tmp buf
256 */
257         case SSL_PROCESS_DATA:
258 /*
259                 Copy as much as we can from the temp buffer into the caller's buffer
260                 and leave the remainder in conn->inbuf until the next call to read
261                 It is possible that len > data in buffer if the encoded record
262                 was longer than len, but the decoded record isn't!
263 */
264                 rc = (int)(ssl->inbuf.end - ssl->inbuf.start);
265                 rc = min(rc, len);
266                 memcpy(buf, ssl->inbuf.start, rc);
267                 ssl->inbuf.start += rc;
268                 return rc;
269 /*
270         We've decoded a record that requires a response into tmp
271         If there is no data to be flushed in the out buffer, we can write out
272         the contents of the tmp buffer.  Otherwise, we need to append the data 
273         to the outgoing data buffer and flush it out.
274 */
275         case SSL_SEND_RESPONSE:
276                 bytes = send(ssl->fd, (char *)ssl->inbuf.start, 
277                         (int)(ssl->inbuf.end - ssl->inbuf.start), MSG_NOSIGNAL);
278                 if (bytes == -1) {
279                         ssl->status = errno;
280                         if (ssl->status != EAGAIN) {
281                                 goto readError;
282                         }
283                         ssl->status = 0;
284                 }
285                 ssl->inbuf.start += bytes;
286                 if (ssl->inbuf.start < ssl->inbuf.end) {
287 /*
288                         This must be a non-blocking socket since it didn't all get sent
289                         out and there was no error.  We want to finish the send here
290                         simply because we are likely in the SSL handshake.
291 */
292                         _ssl_setSocketBlock(ssl->fd);
293                         bytes = send(ssl->fd, (char *)ssl->inbuf.start, 
294                                 (int)(ssl->inbuf.end - ssl->inbuf.start), MSG_NOSIGNAL);
295                         if (bytes == -1) {
296                                 ssl->status = errno;
297                                 goto readError;
298                         }
299                         ssl->inbuf.start += bytes;
300 /*
301                         Can safely set back to non-blocking because we wouldn't
302                         have got here if this socket wasn't non-blocking to begin with.
303 */
304                         _ssl_setSocketNonblock(ssl->fd);
305                 }
306                 ssl->inbuf.start = ssl->inbuf.end = ssl->inbuf.buf;
307                 return 0;
308 /*
309         There was an error decoding the data, or encoding the out buffer.
310         There may be a response data in the out buffer, so try to send.
311         We try a single hail-mary send of the data, and then close the socket.
312         Since we're closing on error, we don't worry too much about a clean flush.
313 */
314         case SSL_ERROR:
315                 if (ssl->inbuf.start < ssl->inbuf.end) {
316                         _ssl_setSocketNonblock(ssl->fd);
317                         bytes = send(ssl->fd, (char *)ssl->inbuf.start, 
318                                 (int)(ssl->inbuf.end - ssl->inbuf.start), MSG_NOSIGNAL);
319                 }
320                 goto readError;
321 /*
322         We've decoded an alert.  The level and description passed into
323         matrixSslDecode are filled in with the specifics.
324 */
325         case SSL_ALERT:
326                 if (alertDescription == SSL_ALERT_CLOSE_NOTIFY) {
327                         ssl->status = SSL_SOCKET_CLOSE_NOTIFY;
328                         goto readZero;
329                 }
330                 goto readError;
331 /*
332         We have a partial record, we need to read more data off the socket.
333         If we have a completely full conn->insock buffer, we'll need to grow it
334         here so that we CAN read more data when called the next time.
335 */
336         case SSL_PARTIAL:
337                 if (ssl->insock.start == ssl->insock.buf && ssl->insock.end == 
338                                 (ssl->insock.buf + ssl->insock.size)) {
339                         if (ssl->insock.size > SSL_MAX_BUF_SIZE) {
340                                 goto readError;
341                         }
342                         ssl->insock.size *= 2;
343                         ssl->insock.start = ssl->insock.buf = 
344                                 (unsigned char *)realloc(ssl->insock.buf, ssl->insock.size);
345                         ssl->insock.end = ssl->insock.buf + (ssl->insock.size / 2);
346                 }
347                 if (!performRead) {
348                         performRead = 1;
349                         free(ssl->inbuf.buf);
350                         ssl->inbuf.buf = NULL;
351                         goto readMore;
352                 } else {
353                         goto readZero;
354                 }
355 /*
356         The out buffer is too small to fit the decoded or response
357         data.  Increase the size of the buffer and call decode again
358 */
359         case SSL_FULL:
360                 ssl->inbuf.size *= 2;
361                 if (ssl->inbuf.buf != (unsigned char*)buf) {
362                         free(ssl->inbuf.buf);
363                         ssl->inbuf.buf = NULL;
364                 }
365                 ssl->inbuf.start = ssl->inbuf.end = ssl->inbuf.buf = 
366                         (unsigned char *)malloc(ssl->inbuf.size);
367                 goto decodeMore;
368         }
369 /*
370         We consolidated some of the returns here because we must ensure
371         that conn->inbuf is cleared if pointing at caller's buffer, otherwise
372         it will be freed later on.
373 */
374 readZero:
375         if (ssl->inbuf.buf == (unsigned char*)buf) {
376                 ssl->inbuf.buf = NULL;
377         }
378         return 0;
379 readError:
380         if (ssl->inbuf.buf == (unsigned char*)buf) {
381                 ssl->inbuf.buf = NULL;
382         }
383         return -1;
384 }
385
386
387 int _ssl_write(SSL *ssl, char *buf, int len)
388 {
389         int             rc;
390
391         ssl->status = 0;
392 /*
393         Pack the buffered socket data (if any) so that start is at zero.
394 */
395         if (ssl->outsock.buf < ssl->outsock.start) {
396                 if (ssl->outsock.start == ssl->outsock.end) {
397                         ssl->outsock.start = ssl->outsock.end = ssl->outsock.buf;
398                 } else {
399                         memmove(ssl->outsock.buf, ssl->outsock.start, ssl->outsock.end - ssl->outsock.start);
400                         ssl->outsock.end -= (ssl->outsock.start - ssl->outsock.buf);
401                         ssl->outsock.start = ssl->outsock.buf;
402                 }
403         }
404 /*
405         If there is buffered output data, the caller must be trying to
406         send the same amount of data as last time.  We don't support 
407         sending additional data until the original buffered request has
408         been completely sent.
409 */
410         if (ssl->outBufferCount > 0 && len != ssl->outBufferCount) {
411                 return -1;
412         }
413 /*
414         If we don't have buffered data, encode the caller's data
415 */
416         if (ssl->outBufferCount == 0) {
417 retryEncode:
418                 rc = matrixSslEncode(ssl->ssl, (unsigned char *)buf, len, &ssl->outsock);
419                 switch (rc) {
420                 case SSL_ERROR:
421                         return -1;
422                 case SSL_FULL:
423                         if (ssl->outsock.size > SSL_MAX_BUF_SIZE) {
424                                 return -1;
425                         }
426                         ssl->outsock.size *= 2;
427                         ssl->outsock.buf = 
428                                 (unsigned char *)realloc(ssl->outsock.buf, ssl->outsock.size);
429                         ssl->outsock.end = ssl->outsock.buf + (ssl->outsock.end - ssl->outsock.start);
430                         ssl->outsock.start = ssl->outsock.buf;
431                         goto retryEncode;
432                 }
433         }
434 /*
435         We've got data to send.
436 */
437         rc = send(ssl->fd, (char *)ssl->outsock.start, 
438                 (int)(ssl->outsock.end - ssl->outsock.start), MSG_NOSIGNAL);
439         if (rc == -1) {
440                 ssl->status = errno;
441                 return -1;
442         }
443         ssl->outsock.start += rc;
444 /*
445         If we wrote it all return the length, otherwise remember the number of
446         bytes passed in, and return 0 to be called again later.
447 */
448         if (ssl->outsock.start == ssl->outsock.end) {
449                 ssl->outBufferCount = 0;
450                 return len;
451         }
452         ssl->outBufferCount = len;
453         return 0;
454 }
455