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