1 /* 2 * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 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 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 ctx->engine = engine; 39 ctx->low_read = low_read; 40 ctx->read_context = read_context; 41 ctx->low_write = low_write; 42 ctx->write_context = write_context; 43 } 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 run_until(br_sslio_context *ctx, unsigned target) 53 { 54 for (;;) { 55 unsigned state; 56 57 state = br_ssl_engine_current_state(ctx->engine); 58 if (state & BR_SSL_CLOSED) { 59 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 if (state & BR_SSL_SENDREC) { 67 unsigned char *buf; 68 size_t len; 69 int wlen; 70 71 buf = br_ssl_engine_sendrec_buf(ctx->engine, &len); 72 wlen = ctx->low_write(ctx->write_context, buf, len); 73 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 if (!ctx->engine->shutdown_recv) { 82 br_ssl_engine_fail( 83 ctx->engine, BR_ERR_IO); 84 } 85 return -1; 86 } 87 if (wlen > 0) { 88 br_ssl_engine_sendrec_ack(ctx->engine, wlen); 89 } 90 continue; 91 } 92 93 /* 94 * If we reached our target, then we are finished. 95 */ 96 if (state & target) { 97 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 if (state & BR_SSL_RECVAPP) { 109 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 if (state & BR_SSL_RECVREC) { 118 unsigned char *buf; 119 size_t len; 120 int rlen; 121 122 buf = br_ssl_engine_recvrec_buf(ctx->engine, &len); 123 rlen = ctx->low_read(ctx->read_context, buf, len); 124 if (rlen < 0) { 125 br_ssl_engine_fail(ctx->engine, BR_ERR_IO); 126 return -1; 127 } 128 if (rlen > 0) { 129 br_ssl_engine_recvrec_ack(ctx->engine, rlen); 130 } 131 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 br_ssl_engine_flush(ctx->engine, 0); 142 } 143 } 144 145 /* see bearssl_ssl.h */ 146 int 147 br_sslio_read(br_sslio_context *ctx, void *dst, size_t len) 148 { 149 unsigned char *buf; 150 size_t alen; 151 152 if (len == 0) { 153 return 0; 154 } 155 if (run_until(ctx, BR_SSL_RECVAPP) < 0) { 156 return -1; 157 } 158 buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen); 159 if (alen > len) { 160 alen = len; 161 } 162 memcpy(dst, buf, alen); 163 br_ssl_engine_recvapp_ack(ctx->engine, alen); 164 return (int)alen; 165 } 166 167 /* see bearssl_ssl.h */ 168 int 169 br_sslio_read_all(br_sslio_context *ctx, void *dst, size_t len) 170 { 171 unsigned char *buf; 172 173 buf = dst; 174 while (len > 0) { 175 int rlen; 176 177 rlen = br_sslio_read(ctx, buf, len); 178 if (rlen < 0) { 179 return -1; 180 } 181 buf += rlen; 182 len -= (size_t)rlen; 183 } 184 return 0; 185 } 186 187 /* see bearssl_ssl.h */ 188 int 189 br_sslio_write(br_sslio_context *ctx, const void *src, size_t len) 190 { 191 unsigned char *buf; 192 size_t alen; 193 194 if (len == 0) { 195 return 0; 196 } 197 if (run_until(ctx, BR_SSL_SENDAPP) < 0) { 198 return -1; 199 } 200 buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen); 201 if (alen > len) { 202 alen = len; 203 } 204 memcpy(buf, src, alen); 205 br_ssl_engine_sendapp_ack(ctx->engine, alen); 206 return (int)alen; 207 } 208 209 /* see bearssl_ssl.h */ 210 int 211 br_sslio_write_all(br_sslio_context *ctx, const void *src, size_t len) 212 { 213 const unsigned char *buf; 214 215 buf = src; 216 while (len > 0) { 217 int wlen; 218 219 wlen = br_sslio_write(ctx, buf, len); 220 if (wlen < 0) { 221 return -1; 222 } 223 buf += wlen; 224 len -= (size_t)wlen; 225 } 226 return 0; 227 } 228 229 /* see bearssl_ssl.h */ 230 int 231 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 br_ssl_engine_flush(ctx->engine, 0); 241 return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP); 242 } 243 244 /* see bearssl_ssl.h */ 245 int 246 br_sslio_close(br_sslio_context *ctx) 247 { 248 br_ssl_engine_close(ctx->engine); 249 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 run_until(ctx, BR_SSL_RECVAPP); 256 if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) { 257 br_ssl_engine_recvapp_ack(ctx->engine, len); 258 } 259 } 260 return br_ssl_engine_last_error(ctx->engine) == BR_ERR_OK; 261 } 262