1/*
2 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10#include <openssl/ssl.h>
11
12#include <openssl/bio.h>
13
14
15static SSL *get_ssl(BIO *bio) {
16 return reinterpret_cast<SSL *>(bio->ptr);
17}
18
19static int ssl_read(BIO *bio, char *out, int outl) {
20 SSL *ssl = get_ssl(bio);
21 if (ssl == NULL) {
22 return 0;
23 }
24
25 BIO_clear_retry_flags(bio);
26
27 const int ret = SSL_read(ssl, out, outl);
28
29 switch (SSL_get_error(ssl, ret)) {
30 case SSL_ERROR_WANT_READ:
31 BIO_set_retry_read(bio);
32 break;
33
34 case SSL_ERROR_WANT_WRITE:
35 BIO_set_retry_write(bio);
36 break;
37
38 case SSL_ERROR_WANT_ACCEPT:
39 BIO_set_retry_special(bio);
40 bio->retry_reason = BIO_RR_ACCEPT;
41 break;
42
43 case SSL_ERROR_WANT_CONNECT:
44 BIO_set_retry_special(bio);
45 bio->retry_reason = BIO_RR_CONNECT;
46 break;
47
48 case SSL_ERROR_NONE:
49 case SSL_ERROR_SYSCALL:
50 case SSL_ERROR_SSL:
51 case SSL_ERROR_ZERO_RETURN:
52 default:
53 break;
54 }
55
56 return ret;
57}
58
59static int ssl_write(BIO *bio, const char *out, int outl) {
60 SSL *ssl = get_ssl(bio);
61 if (ssl == NULL) {
62 return 0;
63 }
64
65 BIO_clear_retry_flags(bio);
66
67 const int ret = SSL_write(ssl, out, outl);
68
69 switch (SSL_get_error(ssl, ret)) {
70 case SSL_ERROR_WANT_WRITE:
71 BIO_set_retry_write(bio);
72 break;
73
74 case SSL_ERROR_WANT_READ:
75 BIO_set_retry_read(bio);
76 break;
77
78 case SSL_ERROR_WANT_CONNECT:
79 BIO_set_retry_special(bio);
80 bio->retry_reason = BIO_RR_CONNECT;
81 break;
82
83 case SSL_ERROR_NONE:
84 case SSL_ERROR_SYSCALL:
85 case SSL_ERROR_SSL:
86 default:
87 break;
88 }
89
90 return ret;
91}
92
93static long ssl_ctrl(BIO *bio, int cmd, long num, void *ptr) {
94 SSL *ssl = get_ssl(bio);
95 if (ssl == NULL && cmd != BIO_C_SET_SSL) {
96 return 0;
97 }
98
99 switch (cmd) {
100 case BIO_C_SET_SSL:
101 bio->shutdown = num;
102 bio->ptr = ptr;
103 bio->init = 1;
104 return 1;
105
106 case BIO_CTRL_GET_CLOSE:
107 return bio->shutdown;
108
109 case BIO_CTRL_SET_CLOSE:
110 bio->shutdown = num;
111 return 1;
112
113 case BIO_CTRL_WPENDING:
114 return BIO_ctrl(SSL_get_wbio(ssl), cmd, num, ptr);
115
116 case BIO_CTRL_PENDING:
117 return SSL_pending(ssl);
118
119 case BIO_CTRL_FLUSH: {
120 BIO_clear_retry_flags(bio);
121 long ret = BIO_ctrl(SSL_get_wbio(ssl), cmd, num, ptr);
122 BIO_copy_next_retry(bio);
123 return ret;
124 }
125
126 case BIO_CTRL_PUSH:
127 case BIO_CTRL_POP:
128 case BIO_CTRL_DUP:
129 return -1;
130
131 default:
132 return BIO_ctrl(SSL_get_rbio(ssl), cmd, num, ptr);
133 }
134}
135
136static int ssl_new(BIO *bio) {
137 return 1;
138}
139
140static int ssl_free(BIO *bio) {
141 SSL *ssl = get_ssl(bio);
142
143 if (ssl == NULL) {
144 return 1;
145 }
146
147 SSL_shutdown(ssl);
148 if (bio->shutdown) {
149 SSL_free(ssl);
150 }
151
152 return 1;
153}
154
155static long ssl_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
156 SSL *ssl = get_ssl(bio);
157 if (ssl == NULL) {
158 return 0;
159 }
160
161 switch (cmd) {
162 case BIO_CTRL_SET_CALLBACK:
163 return -1;
164
165 default:
166 return BIO_callback_ctrl(SSL_get_rbio(ssl), cmd, fp);
167 }
168}
169
170static const BIO_METHOD ssl_method = {
171 BIO_TYPE_SSL, "SSL", ssl_write, ssl_read, NULL,
172 NULL, ssl_ctrl, ssl_new, ssl_free, ssl_callback_ctrl,
173};
174
175const BIO_METHOD *BIO_f_ssl(void) { return &ssl_method; }
176
177long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership) {
178 return BIO_ctrl(bio, BIO_C_SET_SSL, take_owership, ssl);
179}
180