1 |
|
|
/* $OpenBSD: tls_bio_cb.c,v 1.19 2017/01/12 16:18:39 jsing Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2016 Tobias Pape <tobias@netshed.de> |
4 |
|
|
* |
5 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
6 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
7 |
|
|
* copyright notice and this permission notice appear in all copies. |
8 |
|
|
* |
9 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 |
|
|
*/ |
17 |
|
|
|
18 |
|
|
#include <fcntl.h> |
19 |
|
|
#include <stdlib.h> |
20 |
|
|
#include <unistd.h> |
21 |
|
|
|
22 |
|
|
#include <openssl/bio.h> |
23 |
|
|
|
24 |
|
|
#include <tls.h> |
25 |
|
|
#include "tls_internal.h" |
26 |
|
|
|
27 |
|
|
static int bio_cb_write(BIO *bio, const char *buf, int num); |
28 |
|
|
static int bio_cb_read(BIO *bio, char *buf, int size); |
29 |
|
|
static int bio_cb_puts(BIO *bio, const char *str); |
30 |
|
|
static long bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr); |
31 |
|
|
|
32 |
|
|
static BIO_METHOD bio_cb_method = { |
33 |
|
|
.type = BIO_TYPE_MEM, |
34 |
|
|
.name = "libtls_callbacks", |
35 |
|
|
.bwrite = bio_cb_write, |
36 |
|
|
.bread = bio_cb_read, |
37 |
|
|
.bputs = bio_cb_puts, |
38 |
|
|
.ctrl = bio_cb_ctrl, |
39 |
|
|
}; |
40 |
|
|
|
41 |
|
|
static BIO_METHOD * |
42 |
|
|
bio_s_cb(void) |
43 |
|
|
{ |
44 |
|
32 |
return (&bio_cb_method); |
45 |
|
|
} |
46 |
|
|
|
47 |
|
|
static int |
48 |
|
|
bio_cb_puts(BIO *bio, const char *str) |
49 |
|
|
{ |
50 |
|
|
return (bio_cb_write(bio, str, strlen(str))); |
51 |
|
|
} |
52 |
|
|
|
53 |
|
|
static long |
54 |
|
|
bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr) |
55 |
|
|
{ |
56 |
|
|
long ret = 1; |
57 |
|
|
|
58 |
✗✗✓✗ ✓ |
144 |
switch (cmd) { |
59 |
|
|
case BIO_CTRL_GET_CLOSE: |
60 |
|
|
ret = (long)bio->shutdown; |
61 |
|
|
break; |
62 |
|
|
case BIO_CTRL_SET_CLOSE: |
63 |
|
|
bio->shutdown = (int)num; |
64 |
|
|
break; |
65 |
|
|
case BIO_CTRL_DUP: |
66 |
|
|
case BIO_CTRL_FLUSH: |
67 |
|
|
break; |
68 |
|
|
case BIO_CTRL_INFO: |
69 |
|
|
case BIO_CTRL_GET: |
70 |
|
|
case BIO_CTRL_SET: |
71 |
|
|
default: |
72 |
|
32 |
ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); |
73 |
|
32 |
} |
74 |
|
|
|
75 |
|
56 |
return (ret); |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
static int |
79 |
|
|
bio_cb_write(BIO *bio, const char *buf, int num) |
80 |
|
|
{ |
81 |
|
160 |
struct tls *ctx = bio->ptr; |
82 |
|
|
int rv; |
83 |
|
|
|
84 |
|
80 |
BIO_clear_retry_flags(bio); |
85 |
|
80 |
rv = (ctx->write_cb)(ctx, buf, num, ctx->cb_arg); |
86 |
✗✓ |
80 |
if (rv == TLS_WANT_POLLIN) { |
87 |
|
|
BIO_set_retry_read(bio); |
88 |
|
|
rv = -1; |
89 |
✓✓ |
80 |
} else if (rv == TLS_WANT_POLLOUT) { |
90 |
|
16 |
BIO_set_retry_write(bio); |
91 |
|
|
rv = -1; |
92 |
|
16 |
} |
93 |
|
80 |
return (rv); |
94 |
|
|
} |
95 |
|
|
|
96 |
|
|
static int |
97 |
|
|
bio_cb_read(BIO *bio, char *buf, int size) |
98 |
|
|
{ |
99 |
|
432 |
struct tls *ctx = bio->ptr; |
100 |
|
|
int rv; |
101 |
|
|
|
102 |
|
216 |
BIO_clear_retry_flags(bio); |
103 |
|
216 |
rv = (ctx->read_cb)(ctx, buf, size, ctx->cb_arg); |
104 |
✓✓ |
216 |
if (rv == TLS_WANT_POLLIN) { |
105 |
|
40 |
BIO_set_retry_read(bio); |
106 |
|
|
rv = -1; |
107 |
✗✓ |
216 |
} else if (rv == TLS_WANT_POLLOUT) { |
108 |
|
|
BIO_set_retry_write(bio); |
109 |
|
|
rv = -1; |
110 |
|
|
} |
111 |
|
216 |
return (rv); |
112 |
|
|
} |
113 |
|
|
|
114 |
|
|
int |
115 |
|
|
tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb, |
116 |
|
|
void *cb_arg) |
117 |
|
|
{ |
118 |
|
|
int rv = -1; |
119 |
|
|
BIO *bio; |
120 |
|
|
|
121 |
✗✓ |
32 |
if (read_cb == NULL || write_cb == NULL) { |
122 |
|
|
tls_set_errorx(ctx, "no callbacks provided"); |
123 |
|
|
goto err; |
124 |
|
|
} |
125 |
|
|
|
126 |
|
16 |
ctx->read_cb = read_cb; |
127 |
|
16 |
ctx->write_cb = write_cb; |
128 |
|
16 |
ctx->cb_arg = cb_arg; |
129 |
|
|
|
130 |
✗✓ |
16 |
if ((bio = BIO_new(bio_s_cb())) == NULL) { |
131 |
|
|
tls_set_errorx(ctx, "failed to create callback i/o"); |
132 |
|
|
goto err; |
133 |
|
|
} |
134 |
|
16 |
bio->ptr = ctx; |
135 |
|
16 |
bio->init = 1; |
136 |
|
|
|
137 |
|
16 |
SSL_set_bio(ctx->ssl_conn, bio, bio); |
138 |
|
|
|
139 |
|
16 |
rv = 0; |
140 |
|
|
|
141 |
|
|
err: |
142 |
|
16 |
return (rv); |
143 |
|
|
} |