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