Annotation of embedaddon/strongswan/src/libtls/tls_socket.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2010 Martin Willi
3: * Copyright (C) 2010 revosec AG
4: *
5: * This program is free software; you can redistribute it and/or modify it
6: * under the terms of the GNU General Public License as published by the
7: * Free Software Foundation; either version 2 of the License, or (at your
8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9: *
10: * This program is distributed in the hope that it will be useful, but
11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13: * for more details.
14: */
15:
16: #include "tls_socket.h"
17:
18: #include <unistd.h>
19: #include <errno.h>
20:
21: #include <utils/debug.h>
22: #include <threading/thread.h>
23:
24: /**
25: * Buffer size for plain side I/O
26: */
27: #define PLAIN_BUF_SIZE TLS_MAX_FRAGMENT_LEN
28:
29: /**
30: * Buffer size for encrypted side I/O
31: */
32: #define CRYPTO_BUF_SIZE TLS_MAX_FRAGMENT_LEN + 2048
33:
34: typedef struct private_tls_socket_t private_tls_socket_t;
35: typedef struct private_tls_application_t private_tls_application_t;
36:
37: struct private_tls_application_t {
38:
39: /**
40: * Implements tls_application layer.
41: */
42: tls_application_t application;
43:
44: /**
45: * Output buffer to write to
46: */
47: chunk_t out;
48:
49: /**
50: * Number of bytes written to out
51: */
52: size_t out_done;
53:
54: /**
55: * Input buffer to read to
56: */
57: chunk_t in;
58:
59: /**
60: * Number of bytes read to in
61: */
62: size_t in_done;
63:
64: /**
65: * Cached input data
66: */
67: chunk_t cache;
68:
69: /**
70: * Bytes consumed in cache
71: */
72: size_t cache_done;
73:
74: /**
75: * Close TLS connection?
76: */
77: bool close;
78: };
79:
80: /**
81: * Private data of an tls_socket_t object.
82: */
83: struct private_tls_socket_t {
84:
85: /**
86: * Public tls_socket_t interface.
87: */
88: tls_socket_t public;
89:
90: /**
91: * TLS application implementation
92: */
93: private_tls_application_t app;
94:
95: /**
96: * TLS stack
97: */
98: tls_t *tls;
99:
100: /**
101: * Underlying OS socket
102: */
103: int fd;
104: };
105:
106: METHOD(tls_application_t, process, status_t,
107: private_tls_application_t *this, bio_reader_t *reader)
108: {
109: chunk_t data;
110: size_t len;
111:
112: if (this->close)
113: {
114: return SUCCESS;
115: }
116: len = min(reader->remaining(reader), this->in.len - this->in_done);
117: if (len)
118: { /* copy to read buffer as much as fits in */
119: if (!reader->read_data(reader, len, &data))
120: {
121: return FAILED;
122: }
123: memcpy(this->in.ptr + this->in_done, data.ptr, data.len);
124: this->in_done += data.len;
125: }
126: else
127: { /* read buffer is full, cache for next read */
128: if (!reader->read_data(reader, reader->remaining(reader), &data))
129: {
130: return FAILED;
131: }
132: this->cache = chunk_cat("mc", this->cache, data);
133: }
134: return NEED_MORE;
135: }
136:
137: METHOD(tls_application_t, build, status_t,
138: private_tls_application_t *this, bio_writer_t *writer)
139: {
140: if (this->close)
141: {
142: return SUCCESS;
143: }
144: if (this->out.len > this->out_done)
145: {
146: writer->write_data(writer, this->out);
147: this->out_done = this->out.len;
148: return NEED_MORE;
149: }
150: return INVALID_STATE;
151: }
152:
153: /**
154: * TLS data exchange loop
155: */
156: static bool exchange(private_tls_socket_t *this, bool wr, bool block)
157: {
158: char buf[CRYPTO_BUF_SIZE], *pos;
159: ssize_t in, out;
160: size_t len;
161: int flags;
162:
163: while (TRUE)
164: {
165: while (TRUE)
166: {
167: len = sizeof(buf);
168: switch (this->tls->build(this->tls, buf, &len, NULL))
169: {
170: case NEED_MORE:
171: case ALREADY_DONE:
172: pos = buf;
173: while (len)
174: {
175: out = write(this->fd, pos, len);
176: if (out == -1)
177: {
178: DBG1(DBG_TLS, "TLS crypto write error: %s",
179: strerror(errno));
180: return FALSE;
181: }
182: len -= out;
183: pos += out;
184: }
185: continue;
186: case INVALID_STATE:
187: break;
188: case SUCCESS:
189: return TRUE;
190: default:
191: return FALSE;
192: }
193: break;
194: }
195: if (wr)
196: {
197: if (this->app.out_done == this->app.out.len)
198: { /* all data written */
199: return TRUE;
200: }
201: }
202: else
203: {
204: if (this->app.in_done == this->app.in.len)
205: { /* buffer fully received */
206: return TRUE;
207: }
208: }
209:
210: flags = 0;
211: if (this->app.out_done == this->app.out.len)
212: {
213: if (!block || this->app.in_done)
214: {
215: flags |= MSG_DONTWAIT;
216: }
217: }
218: in = recv(this->fd, buf, sizeof(buf), flags);
219: if (in < 0)
220: {
221: if (errno == EAGAIN || errno == EWOULDBLOCK)
222: {
223: if (this->app.in_done == 0)
224: {
225: /* reading, nothing got yet, and call would block */
226: errno = EWOULDBLOCK;
227: this->app.in_done = -1;
228: }
229: return TRUE;
230: }
231: return FALSE;
232: }
233: if (in == 0)
234: { /* EOF */
235: return TRUE;
236: }
237: switch (this->tls->process(this->tls, buf, in))
238: {
239: case NEED_MORE:
240: break;
241: case SUCCESS:
242: return TRUE;
243: default:
244: return FALSE;
245: }
246: }
247: }
248:
249: METHOD(tls_socket_t, read_, ssize_t,
250: private_tls_socket_t *this, void *buf, size_t len, bool block)
251: {
252: if (this->app.cache.len)
253: {
254: size_t cache;
255:
256: cache = min(len, this->app.cache.len - this->app.cache_done);
257: memcpy(buf, this->app.cache.ptr + this->app.cache_done, cache);
258:
259: this->app.cache_done += cache;
260: if (this->app.cache_done == this->app.cache.len)
261: {
262: chunk_free(&this->app.cache);
263: this->app.cache_done = 0;
264: }
265: return cache;
266: }
267: this->app.in.ptr = buf;
268: this->app.in.len = len;
269: this->app.in_done = 0;
270: if (exchange(this, FALSE, block))
271: {
272: return this->app.in_done;
273: }
274: return -1;
275: }
276:
277: METHOD(tls_socket_t, write_, ssize_t,
278: private_tls_socket_t *this, void *buf, size_t len)
279: {
280: this->app.out.ptr = buf;
281: this->app.out.len = len;
282: this->app.out_done = 0;
283: if (exchange(this, TRUE, FALSE))
284: {
285: return this->app.out_done;
286: }
287: return -1;
288: }
289:
290: METHOD(tls_socket_t, splice, bool,
291: private_tls_socket_t *this, int rfd, int wfd)
292: {
293: char buf[PLAIN_BUF_SIZE], *pos;
294: ssize_t in, out;
295: bool old, plain_eof = FALSE, crypto_eof = FALSE;
296: struct pollfd pfd[] = {
297: { .fd = this->fd, .events = POLLIN, },
298: { .fd = rfd, .events = POLLIN, },
299: };
300:
301: while (!plain_eof && !crypto_eof)
302: {
303: old = thread_cancelability(TRUE);
304: in = poll(pfd, countof(pfd), -1);
305: thread_cancelability(old);
306: if (in == -1)
307: {
308: DBG1(DBG_TLS, "TLS select error: %s", strerror(errno));
309: return FALSE;
310: }
311: while (!plain_eof && pfd[0].revents & (POLLIN | POLLHUP | POLLNVAL))
312: {
313: in = read_(this, buf, sizeof(buf), FALSE);
314: switch (in)
315: {
316: case 0:
317: plain_eof = TRUE;
318: break;
319: case -1:
320: if (errno != EWOULDBLOCK)
321: {
322: DBG1(DBG_TLS, "TLS read error: %s", strerror(errno));
323: return FALSE;
324: }
325: break;
326: default:
327: pos = buf;
328: while (in)
329: {
330: out = write(wfd, pos, in);
331: if (out == -1)
332: {
333: DBG1(DBG_TLS, "TLS plain write error: %s",
334: strerror(errno));
335: return FALSE;
336: }
337: in -= out;
338: pos += out;
339: }
340: continue;
341: }
342: break;
343: }
344: if (!crypto_eof && pfd[1].revents & (POLLIN | POLLHUP | POLLNVAL))
345: {
346: in = read(rfd, buf, sizeof(buf));
347: switch (in)
348: {
349: case 0:
350: crypto_eof = TRUE;
351: break;
352: case -1:
353: DBG1(DBG_TLS, "TLS plain read error: %s", strerror(errno));
354: return FALSE;
355: default:
356: pos = buf;
357: while (in)
358: {
359: out = write_(this, pos, in);
360: if (out == -1)
361: {
362: DBG1(DBG_TLS, "TLS write error");
363: return FALSE;
364: }
365: in -= out;
366: pos += out;
367: }
368: break;
369: }
370: }
371: }
372: return TRUE;
373: }
374:
375: METHOD(tls_socket_t, get_fd, int,
376: private_tls_socket_t *this)
377: {
378: return this->fd;
379: }
380:
381: METHOD(tls_socket_t, get_server_id, identification_t*,
382: private_tls_socket_t *this)
383: {
384: return this->tls->get_server_id(this->tls);
385: }
386:
387: METHOD(tls_socket_t, get_peer_id, identification_t*,
388: private_tls_socket_t *this)
389: {
390: return this->tls->get_peer_id(this->tls);
391: }
392:
393: METHOD(tls_socket_t, destroy, void,
394: private_tls_socket_t *this)
395: {
396: /* send a TLS close notify if not done yet */
397: this->app.close = TRUE;
398: write_(this, NULL, 0);
399: free(this->app.cache.ptr);
400: this->tls->destroy(this->tls);
401: free(this);
402: }
403:
404: /**
405: * See header
406: */
407: tls_socket_t *tls_socket_create(bool is_server, identification_t *server,
408: identification_t *peer, int fd, tls_cache_t *cache,
409: tls_version_t max_version, bool nullok)
410: {
411: private_tls_socket_t *this;
412: tls_purpose_t purpose;
413:
414: INIT(this,
415: .public = {
416: .read = _read_,
417: .write = _write_,
418: .splice = _splice,
419: .get_fd = _get_fd,
420: .get_server_id = _get_server_id,
421: .get_peer_id = _get_peer_id,
422: .destroy = _destroy,
423: },
424: .app = {
425: .application = {
426: .build = _build,
427: .process = _process,
428: .destroy = (void*)nop,
429: },
430: },
431: .fd = fd,
432: );
433:
434: if (nullok)
435: {
436: purpose = TLS_PURPOSE_GENERIC_NULLOK;
437: }
438: else
439: {
440: purpose = TLS_PURPOSE_GENERIC;
441: }
442:
443: this->tls = tls_create(is_server, server, peer, purpose,
444: &this->app.application, cache);
445: if (!this->tls)
446: {
447: free(this);
448: return NULL;
449: }
450: this->tls->set_version(this->tls, max_version);
451:
452: return &this->public;
453: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>