blob: fe834507b1827183604cd83b0b11a7d890e7ae53 [file] [log] [blame]
Adam Langleyf5b30cc2016-12-07 10:55:27 -08001/*
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
David Benjamine8703a32017-07-09 16:17:55 -040015static SSL *get_ssl(BIO *bio) {
16 return reinterpret_cast<SSL *>(bio->ptr);
17}
18
Adam Langleyf5b30cc2016-12-07 10:55:27 -080019static int ssl_read(BIO *bio, char *out, int outl) {
David Benjamine8703a32017-07-09 16:17:55 -040020 SSL *ssl = get_ssl(bio);
Adam Langleyf5b30cc2016-12-07 10:55:27 -080021 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
Adam Langleyf5b30cc2016-12-07 10:55:27 -080038 case SSL_ERROR_WANT_ACCEPT:
39 BIO_set_retry_special(bio);
David Benjamin3989c992020-10-09 14:12:06 -040040 BIO_set_retry_reason(bio, BIO_RR_ACCEPT);
Adam Langleyf5b30cc2016-12-07 10:55:27 -080041 break;
42
43 case SSL_ERROR_WANT_CONNECT:
44 BIO_set_retry_special(bio);
David Benjamin3989c992020-10-09 14:12:06 -040045 BIO_set_retry_reason(bio, BIO_RR_CONNECT);
Adam Langleyf5b30cc2016-12-07 10:55:27 -080046 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) {
David Benjamine8703a32017-07-09 16:17:55 -040060 SSL *ssl = get_ssl(bio);
Adam Langleyf5b30cc2016-12-07 10:55:27 -080061 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
Adam Langleyf5b30cc2016-12-07 10:55:27 -080078 case SSL_ERROR_WANT_CONNECT:
79 BIO_set_retry_special(bio);
David Benjamin3989c992020-10-09 14:12:06 -040080 BIO_set_retry_reason(bio, BIO_RR_CONNECT);
Adam Langleyf5b30cc2016-12-07 10:55:27 -080081 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) {
David Benjamine8703a32017-07-09 16:17:55 -040094 SSL *ssl = get_ssl(bio);
Adam Langleyf5b30cc2016-12-07 10:55:27 -080095 if (ssl == NULL && cmd != BIO_C_SET_SSL) {
96 return 0;
97 }
98
99 switch (cmd) {
100 case BIO_C_SET_SSL:
David Benjamin3989c992020-10-09 14:12:06 -0400101 if (ssl != NULL) {
102 // OpenSSL allows reusing an SSL BIO with a different SSL object. We do
103 // not support this.
104 OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
105 return 0;
106 }
107
108 // Note this differs from upstream OpenSSL, which synchronizes
109 // |bio->next_bio| with |ssl|'s rbio here, and on |BIO_CTRL_PUSH|. We call
110 // into the corresponding |BIO| directly. (We can implement the upstream
111 // behavior if it ends up necessary.)
David Benjamin9d64d8d2022-08-31 19:27:56 -0400112 bio->shutdown = static_cast<int>(num);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800113 bio->ptr = ptr;
114 bio->init = 1;
115 return 1;
116
117 case BIO_CTRL_GET_CLOSE:
118 return bio->shutdown;
119
120 case BIO_CTRL_SET_CLOSE:
David Benjamin9d64d8d2022-08-31 19:27:56 -0400121 bio->shutdown = static_cast<int>(num);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800122 return 1;
123
124 case BIO_CTRL_WPENDING:
David Benjamin3c0e0372017-02-03 12:05:01 -0500125 return BIO_ctrl(SSL_get_wbio(ssl), cmd, num, ptr);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800126
127 case BIO_CTRL_PENDING:
128 return SSL_pending(ssl);
129
130 case BIO_CTRL_FLUSH: {
David Benjamin3989c992020-10-09 14:12:06 -0400131 BIO *wbio = SSL_get_wbio(ssl);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800132 BIO_clear_retry_flags(bio);
David Benjamin3989c992020-10-09 14:12:06 -0400133 long ret = BIO_ctrl(wbio, cmd, num, ptr);
134 BIO_set_flags(bio, BIO_get_retry_flags(wbio));
135 BIO_set_retry_reason(bio, BIO_get_retry_reason(wbio));
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800136 return ret;
137 }
138
139 case BIO_CTRL_PUSH:
140 case BIO_CTRL_POP:
141 case BIO_CTRL_DUP:
142 return -1;
143
144 default:
David Benjamin3c0e0372017-02-03 12:05:01 -0500145 return BIO_ctrl(SSL_get_rbio(ssl), cmd, num, ptr);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800146 }
147}
148
149static int ssl_new(BIO *bio) {
150 return 1;
151}
152
153static int ssl_free(BIO *bio) {
David Benjamine8703a32017-07-09 16:17:55 -0400154 SSL *ssl = get_ssl(bio);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800155
156 if (ssl == NULL) {
157 return 1;
158 }
159
160 SSL_shutdown(ssl);
161 if (bio->shutdown) {
162 SSL_free(ssl);
163 }
164
165 return 1;
166}
167
168static long ssl_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
David Benjamine8703a32017-07-09 16:17:55 -0400169 SSL *ssl = get_ssl(bio);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800170 if (ssl == NULL) {
171 return 0;
172 }
173
174 switch (cmd) {
175 case BIO_CTRL_SET_CALLBACK:
176 return -1;
177
178 default:
David Benjamin3c0e0372017-02-03 12:05:01 -0500179 return BIO_callback_ctrl(SSL_get_rbio(ssl), cmd, fp);
Adam Langleyf5b30cc2016-12-07 10:55:27 -0800180 }
181}
182
183static const BIO_METHOD ssl_method = {
184 BIO_TYPE_SSL, "SSL", ssl_write, ssl_read, NULL,
185 NULL, ssl_ctrl, ssl_new, ssl_free, ssl_callback_ctrl,
186};
187
188const BIO_METHOD *BIO_f_ssl(void) { return &ssl_method; }
189
190long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership) {
191 return BIO_ctrl(bio, BIO_C_SET_SSL, take_owership, ssl);
192}