/src/boringssl/crypto/bio/bio_mem.cc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/bio.h> |
16 | | |
17 | | #include <limits.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include <openssl/buf.h> |
21 | | #include <openssl/err.h> |
22 | | #include <openssl/mem.h> |
23 | | |
24 | | #include "../internal.h" |
25 | | #include "internal.h" |
26 | | |
27 | | |
28 | 13.7k | BIO *BIO_new_mem_buf(const void *buf, ossl_ssize_t len) { |
29 | 13.7k | BIO *ret; |
30 | 13.7k | BUF_MEM *b; |
31 | 13.7k | const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len; |
32 | | |
33 | 13.7k | if (!buf && len != 0) { |
34 | 0 | OPENSSL_PUT_ERROR(BIO, BIO_R_NULL_PARAMETER); |
35 | 0 | return nullptr; |
36 | 0 | } |
37 | | |
38 | 13.7k | ret = BIO_new(BIO_s_mem()); |
39 | 13.7k | if (ret == nullptr) { |
40 | 0 | return nullptr; |
41 | 0 | } |
42 | | |
43 | 13.7k | b = (BUF_MEM *)ret->ptr; |
44 | | // BIO_FLAGS_MEM_RDONLY ensures |b->data| is not written to. |
45 | 13.7k | b->data = reinterpret_cast<char *>(const_cast<void *>(buf)); |
46 | 13.7k | b->length = size; |
47 | 13.7k | b->max = size; |
48 | | |
49 | 13.7k | ret->flags |= BIO_FLAGS_MEM_RDONLY; |
50 | | |
51 | | // |num| is used to store the value that this BIO will return when it runs |
52 | | // out of data. If it's negative then the retry flags will also be set. Since |
53 | | // this is static data, retrying won't help |
54 | 13.7k | ret->num = 0; |
55 | | |
56 | 13.7k | return ret; |
57 | 13.7k | } |
58 | | |
59 | 49.0k | static int mem_new(BIO *bio) { |
60 | 49.0k | BUF_MEM *b; |
61 | | |
62 | 49.0k | b = BUF_MEM_new(); |
63 | 49.0k | if (b == nullptr) { |
64 | 0 | return 0; |
65 | 0 | } |
66 | | |
67 | | // |shutdown| is used to store the close flag: whether the BIO has ownership |
68 | | // of the BUF_MEM. |
69 | 49.0k | bio->shutdown = 1; |
70 | 49.0k | bio->init = 1; |
71 | 49.0k | bio->num = -1; |
72 | 49.0k | bio->ptr = (char *)b; |
73 | | |
74 | 49.0k | return 1; |
75 | 49.0k | } |
76 | | |
77 | 49.0k | static int mem_free(BIO *bio) { |
78 | 49.0k | if (!bio->shutdown || !bio->init || bio->ptr == nullptr) { |
79 | 0 | return 1; |
80 | 0 | } |
81 | | |
82 | 49.0k | BUF_MEM *b = (BUF_MEM *)bio->ptr; |
83 | 49.0k | if (bio->flags & BIO_FLAGS_MEM_RDONLY) { |
84 | 13.7k | b->data = nullptr; |
85 | 13.7k | } |
86 | 49.0k | BUF_MEM_free(b); |
87 | 49.0k | bio->ptr = nullptr; |
88 | 49.0k | return 1; |
89 | 49.0k | } |
90 | | |
91 | 300k | static int mem_read(BIO *bio, char *out, int outl) { |
92 | 300k | BIO_clear_retry_flags(bio); |
93 | 300k | if (outl <= 0) { |
94 | 25.1k | return 0; |
95 | 25.1k | } |
96 | | |
97 | 275k | BUF_MEM *b = reinterpret_cast<BUF_MEM *>(bio->ptr); |
98 | 275k | int ret = outl; |
99 | 275k | if ((size_t)ret > b->length) { |
100 | 0 | ret = (int)b->length; |
101 | 0 | } |
102 | | |
103 | 275k | if (ret > 0) { |
104 | 275k | OPENSSL_memcpy(out, b->data, ret); |
105 | 275k | b->length -= ret; |
106 | 275k | if (bio->flags & BIO_FLAGS_MEM_RDONLY) { |
107 | 275k | b->data += ret; |
108 | 275k | } else { |
109 | 0 | OPENSSL_memmove(b->data, &b->data[ret], b->length); |
110 | 0 | } |
111 | 275k | } else if (b->length == 0) { |
112 | 0 | ret = bio->num; |
113 | 0 | if (ret != 0) { |
114 | 0 | BIO_set_retry_read(bio); |
115 | 0 | } |
116 | 0 | } |
117 | 275k | return ret; |
118 | 300k | } |
119 | | |
120 | 1.08M | static int mem_write(BIO *bio, const char *in, int inl) { |
121 | 1.08M | BIO_clear_retry_flags(bio); |
122 | 1.08M | if (inl <= 0) { |
123 | 0 | return 0; // Successfully write zero bytes. |
124 | 0 | } |
125 | | |
126 | 1.08M | if (bio->flags & BIO_FLAGS_MEM_RDONLY) { |
127 | 0 | OPENSSL_PUT_ERROR(BIO, BIO_R_WRITE_TO_READ_ONLY_BIO); |
128 | 0 | return -1; |
129 | 0 | } |
130 | | |
131 | 1.08M | BUF_MEM *b = reinterpret_cast<BUF_MEM *>(bio->ptr); |
132 | 1.08M | if (!BUF_MEM_append(b, in, inl)) { |
133 | 0 | return -1; |
134 | 0 | } |
135 | | |
136 | 1.08M | return inl; |
137 | 1.08M | } |
138 | | |
139 | 300k | static int mem_gets(BIO *bio, char *buf, int size) { |
140 | 300k | BIO_clear_retry_flags(bio); |
141 | 300k | if (size <= 0) { |
142 | 0 | return 0; |
143 | 0 | } |
144 | | |
145 | | // The buffer size includes space for the trailing NUL, so we can read at most |
146 | | // one fewer byte. |
147 | 300k | BUF_MEM *b = reinterpret_cast<BUF_MEM *>(bio->ptr); |
148 | 300k | int ret = size - 1; |
149 | 300k | if ((size_t)ret > b->length) { |
150 | 68.4k | ret = (int)b->length; |
151 | 68.4k | } |
152 | | |
153 | | // Stop at the first newline. |
154 | 300k | const char *newline = |
155 | 300k | reinterpret_cast<char *>(OPENSSL_memchr(b->data, '\n', ret)); |
156 | 300k | if (newline != nullptr) { |
157 | 135k | ret = (int)(newline - b->data + 1); |
158 | 135k | } |
159 | | |
160 | 300k | ret = mem_read(bio, buf, ret); |
161 | 300k | if (ret >= 0) { |
162 | 300k | buf[ret] = '\0'; |
163 | 300k | } |
164 | 300k | return ret; |
165 | 300k | } |
166 | | |
167 | 167k | static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) { |
168 | 167k | BUF_MEM *b = static_cast<BUF_MEM *>(bio->ptr); |
169 | 167k | switch (cmd) { |
170 | 0 | case BIO_CTRL_RESET: |
171 | 0 | if (b->data != nullptr) { |
172 | | // For read only case reset to the start again |
173 | 0 | if (bio->flags & BIO_FLAGS_MEM_RDONLY) { |
174 | 0 | b->data -= b->max - b->length; |
175 | 0 | b->length = b->max; |
176 | 0 | } else { |
177 | 0 | OPENSSL_memset(b->data, 0, b->max); |
178 | 0 | b->length = 0; |
179 | 0 | } |
180 | 0 | } |
181 | 0 | return 1; |
182 | 0 | case BIO_CTRL_EOF: |
183 | 0 | return b->length == 0; |
184 | 0 | case BIO_C_SET_BUF_MEM_EOF_RETURN: |
185 | 0 | bio->num = static_cast<int>(num); |
186 | 0 | return 1; |
187 | 0 | case BIO_CTRL_INFO: |
188 | 0 | if (ptr != nullptr) { |
189 | 0 | char **out = reinterpret_cast<char **>(ptr); |
190 | 0 | *out = b->data; |
191 | 0 | } |
192 | | // This API can overflow on 64-bit Windows, where |long| is smaller than |
193 | | // |ptrdiff_t|. |BIO_mem_contents| is the overflow-safe API. |
194 | 0 | return static_cast<long>(b->length); |
195 | 0 | case BIO_C_SET_BUF_MEM: |
196 | 0 | mem_free(bio); |
197 | 0 | bio->shutdown = static_cast<int>(num); |
198 | 0 | bio->ptr = ptr; |
199 | 0 | return 1; |
200 | 0 | case BIO_C_GET_BUF_MEM_PTR: |
201 | 0 | if (ptr != nullptr) { |
202 | 0 | BUF_MEM **out = reinterpret_cast<BUF_MEM **>(ptr); |
203 | 0 | *out = b; |
204 | 0 | } |
205 | 0 | return 1; |
206 | 0 | case BIO_CTRL_GET_CLOSE: |
207 | 0 | return bio->shutdown; |
208 | 0 | case BIO_CTRL_SET_CLOSE: |
209 | 0 | bio->shutdown = static_cast<int>(num); |
210 | 0 | return 1; |
211 | 0 | case BIO_CTRL_WPENDING: |
212 | 0 | return 0; |
213 | 0 | case BIO_CTRL_PENDING: |
214 | | // TODO(crbug.com/412584975): This can overflow on 64-bit Windows. |
215 | 0 | return static_cast<long>(b->length); |
216 | 147k | case BIO_CTRL_FLUSH: |
217 | 147k | return 1; |
218 | 20.1k | default: |
219 | 20.1k | return 0; |
220 | 167k | } |
221 | 167k | } |
222 | | |
223 | | static const BIO_METHOD mem_method = { |
224 | | BIO_TYPE_MEM, "memory buffer", mem_write, |
225 | | mem_read, mem_gets, mem_ctrl, |
226 | | mem_new, mem_free, /*callback_ctrl=*/nullptr, |
227 | | }; |
228 | | |
229 | 49.0k | const BIO_METHOD *BIO_s_mem(void) { return &mem_method; } |
230 | | |
231 | | int BIO_mem_contents(const BIO *bio, const uint8_t **out_contents, |
232 | 0 | size_t *out_len) { |
233 | 0 | const BUF_MEM *b; |
234 | 0 | if (bio->method != &mem_method) { |
235 | 0 | return 0; |
236 | 0 | } |
237 | | |
238 | 0 | b = (BUF_MEM *)bio->ptr; |
239 | 0 | *out_contents = (uint8_t *)b->data; |
240 | 0 | *out_len = b->length; |
241 | 0 | return 1; |
242 | 0 | } |
243 | | |
244 | 0 | long BIO_get_mem_data(BIO *bio, char **contents) { |
245 | 0 | return BIO_ctrl(bio, BIO_CTRL_INFO, 0, contents); |
246 | 0 | } |
247 | | |
248 | 0 | int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) { |
249 | 0 | return (int)BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, out); |
250 | 0 | } |
251 | | |
252 | 0 | int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) { |
253 | 0 | return (int)BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, b); |
254 | 0 | } |
255 | | |
256 | 0 | int BIO_set_mem_eof_return(BIO *bio, int eof_value) { |
257 | 0 | return (int)BIO_ctrl(bio, BIO_C_SET_BUF_MEM_EOF_RETURN, eof_value, nullptr); |
258 | 0 | } |