File Coverage

src/ssl/ssl_io.c
Criterion Covered Total %
statement 0 86 0.0
branch 0 44 0.0
condition n/a
subroutine n/a
pod n/a
total 0 130 0.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (c) 2016 Thomas Pornin
3             *
4             * Permission is hereby granted, free of charge, to any person obtaining
5             * a copy of this software and associated documentation files (the
6             * "Software"), to deal in the Software without restriction, including
7             * without limitation the rights to use, copy, modify, merge, publish,
8             * distribute, sublicense, and/or sell copies of the Software, and to
9             * permit persons to whom the Software is furnished to do so, subject to
10             * the following conditions:
11             *
12             * The above copyright notice and this permission notice shall be
13             * included in all copies or substantial portions of the Software.
14             *
15             * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16             * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17             * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18             * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19             * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20             * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21             * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22             * SOFTWARE.
23             */
24              
25             #include "inner.h"
26              
27             /* see bearssl_ssl.h */
28             void
29 0           br_sslio_init(br_sslio_context *ctx,
30             br_ssl_engine_context *engine,
31             int (*low_read)(void *read_context,
32             unsigned char *data, size_t len),
33             void *read_context,
34             int (*low_write)(void *write_context,
35             const unsigned char *data, size_t len),
36             void *write_context)
37             {
38 0           ctx->engine = engine;
39 0           ctx->low_read = low_read;
40 0           ctx->read_context = read_context;
41 0           ctx->low_write = low_write;
42 0           ctx->write_context = write_context;
43 0           }
44              
45             /*
46             * Run the engine, until the specified target state is achieved, or
47             * an error occurs. The target state is SENDAPP, RECVAPP, or the
48             * combination of both (the combination matches either). When a match is
49             * achieved, this function returns 0. On error, it returns -1.
50             */
51             static int
52 0           run_until(br_sslio_context *ctx, unsigned target)
53             {
54 0           for (;;) {
55             unsigned state;
56              
57 0           state = br_ssl_engine_current_state(ctx->engine);
58 0 0         if (state & BR_SSL_CLOSED) {
59 0           return -1;
60             }
61              
62             /*
63             * If there is some record data to send, do it. This takes
64             * precedence over everything else.
65             */
66 0 0         if (state & BR_SSL_SENDREC) {
67             unsigned char *buf;
68             size_t len;
69             int wlen;
70              
71 0           buf = br_ssl_engine_sendrec_buf(ctx->engine, &len);
72 0           wlen = ctx->low_write(ctx->write_context, buf, len);
73 0 0         if (wlen < 0) {
74             /*
75             * If we received a close_notify and we
76             * still send something, then we have our
77             * own response close_notify to send, and
78             * the peer is allowed by RFC 5246 not to
79             * wait for it.
80             */
81 0 0         if (!ctx->engine->shutdown_recv) {
82 0           br_ssl_engine_fail(
83             ctx->engine, BR_ERR_IO);
84             }
85 0           return -1;
86             }
87 0 0         if (wlen > 0) {
88 0           br_ssl_engine_sendrec_ack(ctx->engine, wlen);
89             }
90 0           continue;
91             }
92              
93             /*
94             * If we reached our target, then we are finished.
95             */
96 0 0         if (state & target) {
97 0           return 0;
98             }
99              
100             /*
101             * If some application data must be read, and we did not
102             * exit, then this means that we are trying to write data,
103             * and that's not possible until the application data is
104             * read. This may happen if using a shared in/out buffer,
105             * and the underlying protocol is not strictly half-duplex.
106             * This is unrecoverable here, so we report an error.
107             */
108 0 0         if (state & BR_SSL_RECVAPP) {
109 0           return -1;
110             }
111              
112             /*
113             * If we reached that point, then either we are trying
114             * to read data and there is some, or the engine is stuck
115             * until a new record is obtained.
116             */
117 0 0         if (state & BR_SSL_RECVREC) {
118             unsigned char *buf;
119             size_t len;
120             int rlen;
121              
122 0           buf = br_ssl_engine_recvrec_buf(ctx->engine, &len);
123 0           rlen = ctx->low_read(ctx->read_context, buf, len);
124 0 0         if (rlen < 0) {
125 0           br_ssl_engine_fail(ctx->engine, BR_ERR_IO);
126 0           return -1;
127             }
128 0 0         if (rlen > 0) {
129 0           br_ssl_engine_recvrec_ack(ctx->engine, rlen);
130             }
131 0           continue;
132             }
133              
134             /*
135             * We can reach that point if the target RECVAPP, and
136             * the state contains SENDAPP only. This may happen with
137             * a shared in/out buffer. In that case, we must flush
138             * the buffered data to "make room" for a new incoming
139             * record.
140             */
141 0           br_ssl_engine_flush(ctx->engine, 0);
142             }
143             }
144              
145             /* see bearssl_ssl.h */
146             int
147 0           br_sslio_read(br_sslio_context *ctx, void *dst, size_t len)
148             {
149             unsigned char *buf;
150             size_t alen;
151              
152 0 0         if (len == 0) {
153 0           return 0;
154             }
155 0 0         if (run_until(ctx, BR_SSL_RECVAPP) < 0) {
156 0           return -1;
157             }
158 0           buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen);
159 0 0         if (alen > len) {
160 0           alen = len;
161             }
162 0           memcpy(dst, buf, alen);
163 0           br_ssl_engine_recvapp_ack(ctx->engine, alen);
164 0           return (int)alen;
165             }
166              
167             /* see bearssl_ssl.h */
168             int
169 0           br_sslio_read_all(br_sslio_context *ctx, void *dst, size_t len)
170             {
171             unsigned char *buf;
172              
173 0           buf = dst;
174 0 0         while (len > 0) {
175             int rlen;
176              
177 0           rlen = br_sslio_read(ctx, buf, len);
178 0 0         if (rlen < 0) {
179 0           return -1;
180             }
181 0           buf += rlen;
182 0           len -= (size_t)rlen;
183             }
184 0           return 0;
185             }
186              
187             /* see bearssl_ssl.h */
188             int
189 0           br_sslio_write(br_sslio_context *ctx, const void *src, size_t len)
190             {
191             unsigned char *buf;
192             size_t alen;
193              
194 0 0         if (len == 0) {
195 0           return 0;
196             }
197 0 0         if (run_until(ctx, BR_SSL_SENDAPP) < 0) {
198 0           return -1;
199             }
200 0           buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen);
201 0 0         if (alen > len) {
202 0           alen = len;
203             }
204 0           memcpy(buf, src, alen);
205 0           br_ssl_engine_sendapp_ack(ctx->engine, alen);
206 0           return (int)alen;
207             }
208              
209             /* see bearssl_ssl.h */
210             int
211 0           br_sslio_write_all(br_sslio_context *ctx, const void *src, size_t len)
212             {
213             const unsigned char *buf;
214              
215 0           buf = src;
216 0 0         while (len > 0) {
217             int wlen;
218              
219 0           wlen = br_sslio_write(ctx, buf, len);
220 0 0         if (wlen < 0) {
221 0           return -1;
222             }
223 0           buf += wlen;
224 0           len -= (size_t)wlen;
225             }
226 0           return 0;
227             }
228              
229             /* see bearssl_ssl.h */
230             int
231 0           br_sslio_flush(br_sslio_context *ctx)
232             {
233             /*
234             * We trigger a flush. We know the data is gone when there is
235             * no longer any record data to send, and we can either read
236             * or write application data. The call to run_until() does the
237             * job because it ensures that any assembled record data is
238             * first sent down the wire before considering anything else.
239             */
240 0           br_ssl_engine_flush(ctx->engine, 0);
241 0           return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
242             }
243              
244             /* see bearssl_ssl.h */
245             int
246 0           br_sslio_close(br_sslio_context *ctx)
247             {
248 0           br_ssl_engine_close(ctx->engine);
249 0 0         while (br_ssl_engine_current_state(ctx->engine) != BR_SSL_CLOSED) {
250             /*
251             * Discard any incoming application data.
252             */
253             size_t len;
254              
255 0           run_until(ctx, BR_SSL_RECVAPP);
256 0 0         if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) {
257 0           br_ssl_engine_recvapp_ack(ctx->engine, len);
258             }
259             }
260 0           return br_ssl_engine_last_error(ctx->engine) == BR_ERR_OK;
261             }