1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include <assert.h>
17 #include <apr_lib.h>
18 #include <apr_file_info.h>
19 #include <apr_strings.h>
20
21 #include <httpd.h>
22 #include <http_core.h>
23 #include <http_log.h>
24
25 #include <rustls.h>
26
27 #include "tls_proto.h"
28 #include "tls_util.h"
29
30
31 extern module AP_MODULE_DECLARE_DATA tls_module;
32 APLOG_USE_MODULE(tls);
33
34
tls_data_from_str(const char * s)35 tls_data_t tls_data_from_str(const char *s)
36 {
37 tls_data_t d;
38 d.data = (const unsigned char*)s;
39 d.len = s? strlen(s) : 0;
40 return d;
41 }
42
tls_data_assign_copy(apr_pool_t * p,const tls_data_t * d)43 tls_data_t tls_data_assign_copy(apr_pool_t *p, const tls_data_t *d)
44 {
45 tls_data_t copy;
46 copy.data = apr_pmemdup(p, d->data, d->len);
47 copy.len = d->len;
48 return copy;
49 }
50
tls_data_copy(apr_pool_t * p,const tls_data_t * d)51 tls_data_t *tls_data_copy(apr_pool_t *p, const tls_data_t *d)
52 {
53 tls_data_t *copy;
54 copy = apr_pcalloc(p, sizeof(*copy));
55 *copy = tls_data_assign_copy(p, d);
56 return copy;
57 }
58
tls_data_to_str(apr_pool_t * p,const tls_data_t * d)59 const char *tls_data_to_str(apr_pool_t *p, const tls_data_t *d)
60 {
61 char *s = apr_pcalloc(p, d->len+1);
62 memcpy(s, d->data, d->len);
63 return s;
64 }
65
tls_util_rustls_error(apr_pool_t * p,rustls_result rr,const char ** perr_descr)66 apr_status_t tls_util_rustls_error(
67 apr_pool_t *p, rustls_result rr, const char **perr_descr)
68 {
69 if (perr_descr) {
70 char buffer[HUGE_STRING_LEN];
71 apr_size_t len = 0;
72
73 rustls_error(rr, buffer, sizeof(buffer), &len);
74 *perr_descr = apr_pstrndup(p, buffer, len);
75 }
76 return APR_EGENERAL;
77 }
78
tls_util_is_file(apr_pool_t * p,const char * fpath)79 int tls_util_is_file(
80 apr_pool_t *p, const char *fpath)
81 {
82 apr_finfo_t finfo;
83
84 return (fpath != NULL
85 && apr_stat(&finfo, fpath, APR_FINFO_TYPE|APR_FINFO_SIZE, p) == 0
86 && finfo.filetype == APR_REG);
87 }
88
tls_util_file_load(apr_pool_t * p,const char * fpath,apr_size_t min_len,apr_size_t max_len,tls_data_t * data)89 apr_status_t tls_util_file_load(
90 apr_pool_t *p, const char *fpath, apr_size_t min_len, apr_size_t max_len, tls_data_t *data)
91 {
92 apr_finfo_t finfo;
93 apr_status_t rv;
94 apr_file_t *f = NULL;
95 unsigned char *buffer;
96 apr_size_t len;
97 const char *err = NULL;
98 tls_data_t *d;
99
100 rv = apr_stat(&finfo, fpath, APR_FINFO_TYPE|APR_FINFO_SIZE, p);
101 if (APR_SUCCESS != rv) {
102 err = "cannot stat"; goto cleanup;
103 }
104 if (finfo.filetype != APR_REG) {
105 err = "not a plain file";
106 rv = APR_EINVAL; goto cleanup;
107 }
108 if (finfo.size > LONG_MAX) {
109 err = "file is too large";
110 rv = APR_EINVAL; goto cleanup;
111 }
112 len = (apr_size_t)finfo.size;
113 if (len < min_len || len > max_len) {
114 err = "file size not in allowed range";
115 rv = APR_EINVAL; goto cleanup;
116 }
117 d = apr_pcalloc(p, sizeof(*d));
118 buffer = apr_pcalloc(p, len+1); /* keep it NUL terminated in any case */
119 rv = apr_file_open(&f, fpath, APR_FOPEN_READ, 0, p);
120 if (APR_SUCCESS != rv) {
121 err = "error opening"; goto cleanup;
122 }
123 rv = apr_file_read(f, buffer, &len);
124 if (APR_SUCCESS != rv) {
125 err = "error reading"; goto cleanup;
126 }
127 cleanup:
128 if (f) apr_file_close(f);
129 if (APR_SUCCESS == rv) {
130 data->data = buffer;
131 data->len = len;
132 }
133 else {
134 memset(data, 0, sizeof(*data));
135 ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10361)
136 "Failed to load file %s: %s", fpath, err? err: "-");
137 }
138 return rv;
139 }
140
tls_util_array_uint16_contains(const apr_array_header_t * a,apr_uint16_t n)141 int tls_util_array_uint16_contains(const apr_array_header_t* a, apr_uint16_t n)
142 {
143 int i;
144 for (i = 0; i < a->nelts; ++i) {
145 if (APR_ARRAY_IDX(a, i, apr_uint16_t) == n) return 1;
146 }
147 return 0;
148 }
149
tls_util_array_uint16_remove(apr_pool_t * pool,const apr_array_header_t * from,const apr_array_header_t * others)150 const apr_array_header_t *tls_util_array_uint16_remove(
151 apr_pool_t *pool, const apr_array_header_t* from, const apr_array_header_t* others)
152 {
153 apr_array_header_t *na = NULL;
154 apr_uint16_t id;
155 int i, j;
156
157 for (i = 0; i < from->nelts; ++i) {
158 id = APR_ARRAY_IDX(from, i, apr_uint16_t);
159 if (tls_util_array_uint16_contains(others, id)) {
160 if (na == NULL) {
161 /* first removal, make a new result array, copy elements before */
162 na = apr_array_make(pool, from->nelts, sizeof(apr_uint16_t));
163 for (j = 0; j < i; ++j) {
164 APR_ARRAY_PUSH(na, apr_uint16_t) = APR_ARRAY_IDX(from, j, apr_uint16_t);
165 }
166 }
167 }
168 else if (na) {
169 APR_ARRAY_PUSH(na, apr_uint16_t) = id;
170 }
171 }
172 return na? na : from;
173 }
174
tls_util_brigade_transfer(apr_bucket_brigade * dest,apr_bucket_brigade * src,apr_off_t length,apr_off_t * pnout)175 apr_status_t tls_util_brigade_transfer(
176 apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length,
177 apr_off_t *pnout)
178 {
179 apr_bucket *b;
180 apr_off_t remain = length;
181 apr_status_t rv = APR_SUCCESS;
182 const char *ign;
183 apr_size_t ilen;
184
185 *pnout = 0;
186 while (!APR_BRIGADE_EMPTY(src)) {
187 b = APR_BRIGADE_FIRST(src);
188
189 if (APR_BUCKET_IS_METADATA(b)) {
190 APR_BUCKET_REMOVE(b);
191 APR_BRIGADE_INSERT_TAIL(dest, b);
192 }
193 else {
194 if (remain == (apr_off_t)b->length) {
195 /* fall through */
196 }
197 else if (remain <= 0) {
198 goto cleanup;
199 }
200 else {
201 if (b->length == ((apr_size_t)-1)) {
202 rv= apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
203 if (APR_SUCCESS != rv) goto cleanup;
204 }
205 if (remain < (apr_off_t)b->length) {
206 apr_bucket_split(b, (apr_size_t)remain);
207 }
208 }
209 APR_BUCKET_REMOVE(b);
210 APR_BRIGADE_INSERT_TAIL(dest, b);
211 remain -= (apr_off_t)b->length;
212 *pnout += (apr_off_t)b->length;
213 }
214 }
215 cleanup:
216 return rv;
217 }
218
tls_util_brigade_copy(apr_bucket_brigade * dest,apr_bucket_brigade * src,apr_off_t length,apr_off_t * pnout)219 apr_status_t tls_util_brigade_copy(
220 apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length,
221 apr_off_t *pnout)
222 {
223 apr_bucket *b, *next;
224 apr_off_t remain = length;
225 apr_status_t rv = APR_SUCCESS;
226 const char *ign;
227 apr_size_t ilen;
228
229 *pnout = 0;
230 for (b = APR_BRIGADE_FIRST(src);
231 b != APR_BRIGADE_SENTINEL(src);
232 b = next) {
233 next = APR_BUCKET_NEXT(b);
234
235 if (APR_BUCKET_IS_METADATA(b)) {
236 /* fall through */
237 }
238 else {
239 if (remain == (apr_off_t)b->length) {
240 /* fall through */
241 }
242 else if (remain <= 0) {
243 goto cleanup;
244 }
245 else {
246 if (b->length == ((apr_size_t)-1)) {
247 rv = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ);
248 if (APR_SUCCESS != rv) goto cleanup;
249 }
250 if (remain < (apr_off_t)b->length) {
251 apr_bucket_split(b, (apr_size_t)remain);
252 }
253 }
254 }
255 rv = apr_bucket_copy(b, &b);
256 if (APR_SUCCESS != rv) goto cleanup;
257 APR_BRIGADE_INSERT_TAIL(dest, b);
258 remain -= (apr_off_t)b->length;
259 *pnout += (apr_off_t)b->length;
260 }
261 cleanup:
262 return rv;
263 }
264
tls_util_brigade_split_line(apr_bucket_brigade * dest,apr_bucket_brigade * src,apr_read_type_e block,apr_off_t length,apr_off_t * pnout)265 apr_status_t tls_util_brigade_split_line(
266 apr_bucket_brigade *dest, apr_bucket_brigade *src,
267 apr_read_type_e block, apr_off_t length,
268 apr_off_t *pnout)
269 {
270 apr_off_t nstart, nend;
271 apr_status_t rv;
272
273 apr_brigade_length(dest, 0, &nstart);
274 rv = apr_brigade_split_line(dest, src, block, length);
275 if (APR_SUCCESS != rv) goto cleanup;
276 apr_brigade_length(dest, 0, &nend);
277 /* apr_brigade_split_line() has the nasty habit of leaving a 0-length bucket
278 * at the start of the brigade when it transferred the whole content. Get rid of it.
279 */
280 if (!APR_BRIGADE_EMPTY(src)) {
281 apr_bucket *b = APR_BRIGADE_FIRST(src);
282 if (!APR_BUCKET_IS_METADATA(b) && 0 == b->length) {
283 APR_BUCKET_REMOVE(b);
284 apr_bucket_delete(b);
285 }
286 }
287 cleanup:
288 *pnout = (APR_SUCCESS == rv)? (nend - nstart) : 0;
289 return rv;
290 }
291
tls_util_name_matches_server(const char * name,server_rec * s)292 int tls_util_name_matches_server(const char *name, server_rec *s)
293 {
294 apr_array_header_t *names;
295 char **alias;
296 int i;
297
298 if (!s || !s->server_hostname) return 0;
299 if (!strcasecmp(name, s->server_hostname)) return 1;
300 /* first the fast equality match, then the pattern wild_name matches */
301 names = s->names;
302 if (!names) return 0;
303 alias = (char **)names->elts;
304 for (i = 0; i < names->nelts; ++i) {
305 if (alias[i] && !strcasecmp(name, alias[i])) return 1;
306 }
307 names = s->wild_names;
308 if (!names) return 0;
309 alias = (char **)names->elts;
310 for (i = 0; i < names->nelts; ++i) {
311 if (alias[i] && !ap_strcasecmp_match(name, alias[i])) return 1;
312 }
313 return 0;
314 }
315
tls_util_bucket_print(char * buffer,apr_size_t bmax,apr_bucket * b,const char * sep)316 apr_size_t tls_util_bucket_print(char *buffer, apr_size_t bmax,
317 apr_bucket *b, const char *sep)
318 {
319 apr_size_t off = 0;
320 if (sep && *sep) {
321 off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s", sep);
322 }
323
324 if (bmax <= off) {
325 return off;
326 }
327 else if (APR_BUCKET_IS_METADATA(b)) {
328 off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s", b->type->name);
329 }
330 else if (bmax > off) {
331 off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s[%ld]",
332 b->type->name, (long)(b->length == ((apr_size_t)-1)?
333 -1 : (int)b->length));
334 }
335 return off;
336 }
337
tls_util_bb_print(char * buffer,apr_size_t bmax,const char * tag,const char * sep,apr_bucket_brigade * bb)338 apr_size_t tls_util_bb_print(char *buffer, apr_size_t bmax,
339 const char *tag, const char *sep,
340 apr_bucket_brigade *bb)
341 {
342 apr_size_t off = 0;
343 const char *sp = "";
344 apr_bucket *b;
345
346 if (bmax > 1) {
347 if (bb) {
348 memset(buffer, 0, bmax--);
349 off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s(", tag);
350 for (b = APR_BRIGADE_FIRST(bb);
351 (bmax > off) && (b != APR_BRIGADE_SENTINEL(bb));
352 b = APR_BUCKET_NEXT(b)) {
353
354 off += tls_util_bucket_print(buffer+off, bmax-off, b, sp);
355 sp = " ";
356 }
357 if (bmax > off) {
358 off += (size_t)apr_snprintf(buffer+off, bmax-off, ")%s", sep);
359 }
360 }
361 else {
362 off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep);
363 }
364 }
365 return off;
366 }
367
368