xref: /dflybsd-src/crypto/libressl/tls/tls_bio_cb.c (revision 961e30ea7dc61d1112b778ea4981eac68129fb86)
1*de0e0e4dSAntonio Huete Jimenez /* $OpenBSD: tls_bio_cb.c,v 1.20 2022/01/10 23:39:48 tb Exp $ */
272c33676SMaxim Ag /*
372c33676SMaxim Ag  * Copyright (c) 2016 Tobias Pape <tobias@netshed.de>
472c33676SMaxim Ag  *
572c33676SMaxim Ag  * Permission to use, copy, modify, and distribute this software for any
672c33676SMaxim Ag  * purpose with or without fee is hereby granted, provided that the above
772c33676SMaxim Ag  * copyright notice and this permission notice appear in all copies.
872c33676SMaxim Ag  *
972c33676SMaxim Ag  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1072c33676SMaxim Ag  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1172c33676SMaxim Ag  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1272c33676SMaxim Ag  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1372c33676SMaxim Ag  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1472c33676SMaxim Ag  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1572c33676SMaxim Ag  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1672c33676SMaxim Ag  */
1772c33676SMaxim Ag 
1872c33676SMaxim Ag #include <fcntl.h>
1972c33676SMaxim Ag #include <stdlib.h>
2072c33676SMaxim Ag #include <unistd.h>
2172c33676SMaxim Ag 
2272c33676SMaxim Ag #include <openssl/bio.h>
2372c33676SMaxim Ag 
2472c33676SMaxim Ag #include <tls.h>
2572c33676SMaxim Ag #include "tls_internal.h"
2672c33676SMaxim Ag 
2772c33676SMaxim Ag static int bio_cb_write(BIO *bio, const char *buf, int num);
2872c33676SMaxim Ag static int bio_cb_read(BIO *bio, char *buf, int size);
2972c33676SMaxim Ag static int bio_cb_puts(BIO *bio, const char *str);
3072c33676SMaxim Ag static long bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr);
3172c33676SMaxim Ag 
32*de0e0e4dSAntonio Huete Jimenez static BIO_METHOD *bio_cb_method;
33*de0e0e4dSAntonio Huete Jimenez 
34*de0e0e4dSAntonio Huete Jimenez static pthread_mutex_t bio_cb_method_lock = PTHREAD_MUTEX_INITIALIZER;
35*de0e0e4dSAntonio Huete Jimenez 
36*de0e0e4dSAntonio Huete Jimenez static void
bio_cb_method_init(void)37*de0e0e4dSAntonio Huete Jimenez bio_cb_method_init(void)
38*de0e0e4dSAntonio Huete Jimenez {
39*de0e0e4dSAntonio Huete Jimenez 	BIO_METHOD *bio_method;
40*de0e0e4dSAntonio Huete Jimenez 
41*de0e0e4dSAntonio Huete Jimenez 	if (bio_cb_method != NULL)
42*de0e0e4dSAntonio Huete Jimenez 		return;
43*de0e0e4dSAntonio Huete Jimenez 
44*de0e0e4dSAntonio Huete Jimenez 	bio_method = BIO_meth_new(BIO_TYPE_MEM, "libtls_callbacks");
45*de0e0e4dSAntonio Huete Jimenez 	if (bio_method == NULL)
46*de0e0e4dSAntonio Huete Jimenez 		return;
47*de0e0e4dSAntonio Huete Jimenez 
48*de0e0e4dSAntonio Huete Jimenez 	BIO_meth_set_write(bio_method, bio_cb_write);
49*de0e0e4dSAntonio Huete Jimenez 	BIO_meth_set_read(bio_method, bio_cb_read);
50*de0e0e4dSAntonio Huete Jimenez 	BIO_meth_set_puts(bio_method, bio_cb_puts);
51*de0e0e4dSAntonio Huete Jimenez 	BIO_meth_set_ctrl(bio_method, bio_cb_ctrl);
52*de0e0e4dSAntonio Huete Jimenez 
53*de0e0e4dSAntonio Huete Jimenez 	bio_cb_method = bio_method;
54*de0e0e4dSAntonio Huete Jimenez }
5572c33676SMaxim Ag 
5672c33676SMaxim Ag static BIO_METHOD *
bio_s_cb(void)5772c33676SMaxim Ag bio_s_cb(void)
5872c33676SMaxim Ag {
59*de0e0e4dSAntonio Huete Jimenez 	if (bio_cb_method != NULL)
60*de0e0e4dSAntonio Huete Jimenez 		return (bio_cb_method);
61*de0e0e4dSAntonio Huete Jimenez 
62*de0e0e4dSAntonio Huete Jimenez 	pthread_mutex_lock(&bio_cb_method_lock);
63*de0e0e4dSAntonio Huete Jimenez 	bio_cb_method_init();
64*de0e0e4dSAntonio Huete Jimenez 	pthread_mutex_unlock(&bio_cb_method_lock);
65*de0e0e4dSAntonio Huete Jimenez 
66*de0e0e4dSAntonio Huete Jimenez 	return (bio_cb_method);
6772c33676SMaxim Ag }
6872c33676SMaxim Ag 
6972c33676SMaxim Ag static int
bio_cb_puts(BIO * bio,const char * str)7072c33676SMaxim Ag bio_cb_puts(BIO *bio, const char *str)
7172c33676SMaxim Ag {
7272c33676SMaxim Ag 	return (bio_cb_write(bio, str, strlen(str)));
7372c33676SMaxim Ag }
7472c33676SMaxim Ag 
7572c33676SMaxim Ag static long
bio_cb_ctrl(BIO * bio,int cmd,long num,void * ptr)7672c33676SMaxim Ag bio_cb_ctrl(BIO *bio, int cmd, long num, void *ptr)
7772c33676SMaxim Ag {
7872c33676SMaxim Ag 	long ret = 1;
7972c33676SMaxim Ag 
8072c33676SMaxim Ag 	switch (cmd) {
8172c33676SMaxim Ag 	case BIO_CTRL_GET_CLOSE:
82*de0e0e4dSAntonio Huete Jimenez 		ret = (long)BIO_get_shutdown(bio);
8372c33676SMaxim Ag 		break;
8472c33676SMaxim Ag 	case BIO_CTRL_SET_CLOSE:
85*de0e0e4dSAntonio Huete Jimenez 		BIO_set_shutdown(bio, (int)num);
8672c33676SMaxim Ag 		break;
8772c33676SMaxim Ag 	case BIO_CTRL_DUP:
8872c33676SMaxim Ag 	case BIO_CTRL_FLUSH:
8972c33676SMaxim Ag 		break;
9072c33676SMaxim Ag 	case BIO_CTRL_INFO:
9172c33676SMaxim Ag 	case BIO_CTRL_GET:
9272c33676SMaxim Ag 	case BIO_CTRL_SET:
9372c33676SMaxim Ag 	default:
94*de0e0e4dSAntonio Huete Jimenez 		ret = BIO_ctrl(BIO_next(bio), cmd, num, ptr);
9572c33676SMaxim Ag 	}
9672c33676SMaxim Ag 
9772c33676SMaxim Ag 	return (ret);
9872c33676SMaxim Ag }
9972c33676SMaxim Ag 
10072c33676SMaxim Ag static int
bio_cb_write(BIO * bio,const char * buf,int num)10172c33676SMaxim Ag bio_cb_write(BIO *bio, const char *buf, int num)
10272c33676SMaxim Ag {
103*de0e0e4dSAntonio Huete Jimenez 	struct tls *ctx = BIO_get_data(bio);
10472c33676SMaxim Ag 	int rv;
10572c33676SMaxim Ag 
10672c33676SMaxim Ag 	BIO_clear_retry_flags(bio);
10772c33676SMaxim Ag 	rv = (ctx->write_cb)(ctx, buf, num, ctx->cb_arg);
10872c33676SMaxim Ag 	if (rv == TLS_WANT_POLLIN) {
10972c33676SMaxim Ag 		BIO_set_retry_read(bio);
11072c33676SMaxim Ag 		rv = -1;
11172c33676SMaxim Ag 	} else if (rv == TLS_WANT_POLLOUT) {
11272c33676SMaxim Ag 		BIO_set_retry_write(bio);
11372c33676SMaxim Ag 		rv = -1;
11472c33676SMaxim Ag 	}
11572c33676SMaxim Ag 	return (rv);
11672c33676SMaxim Ag }
11772c33676SMaxim Ag 
11872c33676SMaxim Ag static int
bio_cb_read(BIO * bio,char * buf,int size)11972c33676SMaxim Ag bio_cb_read(BIO *bio, char *buf, int size)
12072c33676SMaxim Ag {
121*de0e0e4dSAntonio Huete Jimenez 	struct tls *ctx = BIO_get_data(bio);
12272c33676SMaxim Ag 	int rv;
12372c33676SMaxim Ag 
12472c33676SMaxim Ag 	BIO_clear_retry_flags(bio);
12572c33676SMaxim Ag 	rv = (ctx->read_cb)(ctx, buf, size, ctx->cb_arg);
12672c33676SMaxim Ag 	if (rv == TLS_WANT_POLLIN) {
12772c33676SMaxim Ag 		BIO_set_retry_read(bio);
12872c33676SMaxim Ag 		rv = -1;
12972c33676SMaxim Ag 	} else if (rv == TLS_WANT_POLLOUT) {
13072c33676SMaxim Ag 		BIO_set_retry_write(bio);
13172c33676SMaxim Ag 		rv = -1;
13272c33676SMaxim Ag 	}
13372c33676SMaxim Ag 	return (rv);
13472c33676SMaxim Ag }
13572c33676SMaxim Ag 
13672c33676SMaxim Ag int
tls_set_cbs(struct tls * ctx,tls_read_cb read_cb,tls_write_cb write_cb,void * cb_arg)13772c33676SMaxim Ag tls_set_cbs(struct tls *ctx, tls_read_cb read_cb, tls_write_cb write_cb,
13872c33676SMaxim Ag     void *cb_arg)
13972c33676SMaxim Ag {
140*de0e0e4dSAntonio Huete Jimenez 	const BIO_METHOD *bio_cb;
14172c33676SMaxim Ag 	BIO *bio;
142*de0e0e4dSAntonio Huete Jimenez 	int rv = -1;
14372c33676SMaxim Ag 
14472c33676SMaxim Ag 	if (read_cb == NULL || write_cb == NULL) {
14572c33676SMaxim Ag 		tls_set_errorx(ctx, "no callbacks provided");
14672c33676SMaxim Ag 		goto err;
14772c33676SMaxim Ag 	}
14872c33676SMaxim Ag 
14972c33676SMaxim Ag 	ctx->read_cb = read_cb;
15072c33676SMaxim Ag 	ctx->write_cb = write_cb;
15172c33676SMaxim Ag 	ctx->cb_arg = cb_arg;
15272c33676SMaxim Ag 
153*de0e0e4dSAntonio Huete Jimenez 	if ((bio_cb = bio_s_cb()) == NULL) {
154*de0e0e4dSAntonio Huete Jimenez 		tls_set_errorx(ctx, "failed to create callback method");
155*de0e0e4dSAntonio Huete Jimenez 		goto err;
156*de0e0e4dSAntonio Huete Jimenez 	}
157*de0e0e4dSAntonio Huete Jimenez 	if ((bio = BIO_new(bio_cb)) == NULL) {
15872c33676SMaxim Ag 		tls_set_errorx(ctx, "failed to create callback i/o");
15972c33676SMaxim Ag 		goto err;
16072c33676SMaxim Ag 	}
161*de0e0e4dSAntonio Huete Jimenez 	BIO_set_data(bio, ctx);
162*de0e0e4dSAntonio Huete Jimenez 	BIO_set_init(bio, 1);
16372c33676SMaxim Ag 
16472c33676SMaxim Ag 	SSL_set_bio(ctx->ssl_conn, bio, bio);
16572c33676SMaxim Ag 
16672c33676SMaxim Ag 	rv = 0;
16772c33676SMaxim Ag 
16872c33676SMaxim Ag  err:
16972c33676SMaxim Ag 	return (rv);
17072c33676SMaxim Ag }
171