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_encode.h>
19 #include <apr_strings.h>
20 
21 #include <httpd.h>
22 #include <http_connection.h>
23 #include <http_core.h>
24 #include <http_log.h>
25 
26 #include <rustls.h>
27 
28 #include "tls_cert.h"
29 #include "tls_util.h"
30 
31 extern module AP_MODULE_DECLARE_DATA tls_module;
32 APLOG_USE_MODULE(tls);
33 
34 
tls_cert_load_pem(apr_pool_t * p,const tls_cert_spec_t * cert,tls_cert_pem_t ** ppem)35 apr_status_t tls_cert_load_pem(
36     apr_pool_t *p, const tls_cert_spec_t *cert, tls_cert_pem_t **ppem)
37 {
38     apr_status_t rv;
39     const char *fpath;
40     tls_cert_pem_t *cpem;
41 
42     ap_assert(cert->cert_file);
43     cpem = apr_pcalloc(p, sizeof(*cpem));
44     fpath = ap_server_root_relative(p, cert->cert_file);
45     if (NULL == fpath) {
46         rv = APR_ENOENT; goto cleanup;
47     }
48     rv = tls_util_file_load(p, fpath, 0, 100*1024, &cpem->cert_pem);
49     if (APR_SUCCESS != rv) goto cleanup;
50 
51     if (cert->pkey_file) {
52         fpath = ap_server_root_relative(p, cert->pkey_file);
53         if (NULL == fpath) {
54             rv = APR_ENOENT; goto cleanup;
55         }
56         rv = tls_util_file_load(p, fpath, 0, 100*1024, &cpem->pkey_pem);
57         if (APR_SUCCESS != rv) goto cleanup;
58     }
59     else {
60         cpem->pkey_pem = cpem->cert_pem;
61     }
62 cleanup:
63     *ppem = (APR_SUCCESS == rv)? cpem : NULL;
64     return rv;
65 }
66 
67 #define PEM_IN_CHUNK    48      /* PEM demands at most 64 chars per line */
68 
tls_der_to_pem(const char ** ppem,apr_pool_t * p,const unsigned char * der_data,apr_size_t der_len,const char * header,const char * footer)69 static apr_status_t tls_der_to_pem(
70     const char **ppem, apr_pool_t *p,
71     const unsigned char *der_data, apr_size_t der_len,
72     const char *header, const char *footer)
73 {
74     apr_status_t rv = APR_SUCCESS;
75     char *pem = NULL, *s;
76     apr_size_t b64_len, n, hd_len, ft_len;
77     apr_ssize_t in_len, i;
78 
79     if (der_len > INT_MAX) {
80         rv = APR_ENOMEM;
81         goto cleanup;
82     }
83     in_len = (apr_ssize_t)der_len;
84     rv = apr_encode_base64(NULL, (const char*)der_data, in_len, APR_ENCODE_NONE, &b64_len);
85     if (APR_SUCCESS != rv) goto cleanup;
86     if (b64_len > INT_MAX) {
87         rv = APR_ENOMEM;
88         goto cleanup;
89     }
90     hd_len = header? strlen(header) : 0;
91     ft_len = footer? strlen(footer) : 0;
92     s = pem = apr_pcalloc(p,
93         + b64_len + (der_len/PEM_IN_CHUNK) + 1 /* \n per chunk */
94         + hd_len +1 + ft_len + 1 /* adding \n */
95         + 1); /* NUL-terminated */
96     if (header) {
97         strcpy(s, header);
98         s += hd_len;
99         *s++ = '\n';
100     }
101     for (i = 0; in_len > 0; i += PEM_IN_CHUNK, in_len -= PEM_IN_CHUNK) {
102         rv = apr_encode_base64(s,
103             (const char*)der_data + i, in_len > PEM_IN_CHUNK? PEM_IN_CHUNK : in_len,
104             APR_ENCODE_NONE, &n);
105         s += n;
106         *s++ = '\n';
107     }
108     if (footer) {
109         strcpy(s, footer);
110         s += ft_len;
111         *s++ = '\n';
112     }
113 cleanup:
114     *ppem = (APR_SUCCESS == rv)? pem : NULL;
115     return rv;
116 }
117 
118 #define PEM_CERT_HD     "-----BEGIN CERTIFICATE-----"
119 #define PEM_CERT_FT     "-----END CERTIFICATE-----"
120 
tls_cert_to_pem(const char ** ppem,apr_pool_t * p,const rustls_certificate * cert)121 apr_status_t tls_cert_to_pem(const char **ppem, apr_pool_t *p, const rustls_certificate *cert)
122 {
123     const unsigned char* der_data;
124     size_t der_len;
125     rustls_result rr = RUSTLS_RESULT_OK;
126     apr_status_t rv = APR_SUCCESS;
127     const char *pem = NULL;
128 
129     rr = rustls_certificate_get_der(cert, &der_data, &der_len);
130     if (RUSTLS_RESULT_OK != rr) goto cleanup;
131     rv = tls_der_to_pem(&pem, p, der_data, der_len, PEM_CERT_HD, PEM_CERT_FT);
132 cleanup:
133     if (RUSTLS_RESULT_OK != rr) {
134         rv = tls_util_rustls_error(p, rr, NULL);
135     }
136     *ppem = (APR_SUCCESS == rv)? pem : NULL;
137     return rv;
138 }
139 
nullify_key_pem(tls_cert_pem_t * pems)140 static void nullify_key_pem(tls_cert_pem_t *pems)
141 {
142     if (pems->pkey_pem.len) {
143         memset((void*)pems->pkey_pem.data, 0, pems->pkey_pem.len);
144     }
145 }
146 
make_certified_key(apr_pool_t * p,const char * name,const tls_data_t * cert_pem,const tls_data_t * pkey_pem,const rustls_certified_key ** pckey)147 static apr_status_t make_certified_key(
148     apr_pool_t *p, const char *name,
149     const tls_data_t *cert_pem, const tls_data_t *pkey_pem,
150     const rustls_certified_key **pckey)
151 {
152     const rustls_certified_key *ckey = NULL;
153     rustls_result rr = RUSTLS_RESULT_OK;
154     apr_status_t rv = APR_SUCCESS;
155 
156     rr = rustls_certified_key_build(
157         cert_pem->data, cert_pem->len,
158         pkey_pem->data, pkey_pem->len,
159         &ckey);
160 
161     if (RUSTLS_RESULT_OK != rr) {
162         const char *err_descr;
163         rv = tls_util_rustls_error(p, rr, &err_descr);
164         ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10363)
165                      "Failed to load certified key %s: [%d] %s",
166                      name, (int)rr, err_descr);
167     }
168     if (APR_SUCCESS == rv) {
169         *pckey = ckey;
170     }
171     else if (ckey) {
172         rustls_certified_key_free(ckey);
173     }
174     return rv;
175 }
176 
tls_cert_load_cert_key(apr_pool_t * p,const tls_cert_spec_t * spec,const char ** pcert_pem,const rustls_certified_key ** pckey)177 apr_status_t tls_cert_load_cert_key(
178     apr_pool_t *p, const tls_cert_spec_t *spec,
179     const char **pcert_pem, const rustls_certified_key **pckey)
180 {
181     apr_status_t rv = APR_SUCCESS;
182 
183     if (spec->cert_file) {
184         tls_cert_pem_t *pems;
185 
186         rv = tls_cert_load_pem(p, spec, &pems);
187         if (APR_SUCCESS != rv) goto cleanup;
188         if (pcert_pem) *pcert_pem = tls_data_to_str(p, &pems->cert_pem);
189         rv = make_certified_key(p, spec->cert_file, &pems->cert_pem, &pems->pkey_pem, pckey);
190         /* dont want them hanging around in memory unnecessarily. */
191         nullify_key_pem(pems);
192     }
193     else if (spec->cert_pem) {
194         tls_data_t pkey_pem, pem;
195         pem = tls_data_from_str(spec->cert_pem);
196         if (spec->pkey_pem) {
197             pkey_pem = tls_data_from_str(spec->pkey_pem);
198         }
199         else {
200             pkey_pem = pem;
201         }
202         if (pcert_pem) *pcert_pem = spec->cert_pem;
203         rv = make_certified_key(p, "memory", &pem, &pkey_pem, pckey);
204         /* pems provided from outside are responsibility of the caller */
205     }
206     else {
207         rv = APR_ENOENT; goto cleanup;
208     }
209 cleanup:
210     return rv;
211 }
212 
213 typedef struct {
214     const char *id;
215     const char *cert_pem;
216     server_rec *server;
217     const rustls_certified_key *certified_key;
218 } tls_cert_reg_entry_t;
219 
reg_entry_cleanup(void * ctx,const void * key,apr_ssize_t klen,const void * val)220 static int reg_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
221 {
222     tls_cert_reg_entry_t *entry = (tls_cert_reg_entry_t*)val;
223     (void)ctx; (void)key; (void)klen;
224     if (entry->certified_key) {
225         rustls_certified_key_free(entry->certified_key);
226         entry->certified_key = NULL;
227     }
228     return 1;
229 }
230 
reg_cleanup(void * data)231 static apr_status_t reg_cleanup(void *data)
232 {
233     tls_cert_reg_t *reg = data;
234     if (reg->id2entry) {
235         apr_hash_do(reg_entry_cleanup, reg, reg->id2entry);
236         apr_hash_clear(reg->id2entry);
237         if (reg->key2entry) apr_hash_clear(reg->key2entry);
238     }
239     return APR_SUCCESS;
240 }
241 
tls_cert_reg_make(apr_pool_t * p)242 tls_cert_reg_t *tls_cert_reg_make(apr_pool_t *p)
243 {
244     tls_cert_reg_t *reg;
245 
246     reg = apr_pcalloc(p, sizeof(*reg));
247     reg->pool = p;
248     reg->id2entry = apr_hash_make(p);
249     reg->key2entry = apr_hash_make(p);
250     apr_pool_cleanup_register(p, reg, reg_cleanup, apr_pool_cleanup_null);
251     return reg;
252 }
253 
tls_cert_reg_count(tls_cert_reg_t * reg)254 apr_size_t tls_cert_reg_count(tls_cert_reg_t *reg)
255 {
256     return apr_hash_count(reg->id2entry);
257 }
258 
cert_spec_to_id(const tls_cert_spec_t * spec)259 static const char *cert_spec_to_id(const tls_cert_spec_t *spec)
260 {
261     if (spec->cert_file) return spec->cert_file;
262     if (spec->cert_pem) return spec->cert_pem;
263     return NULL;
264 }
265 
tls_cert_reg_get_certified_key(tls_cert_reg_t * reg,server_rec * s,const tls_cert_spec_t * spec,const rustls_certified_key ** pckey)266 apr_status_t tls_cert_reg_get_certified_key(
267     tls_cert_reg_t *reg, server_rec *s, const tls_cert_spec_t *spec,
268     const rustls_certified_key **pckey)
269 {
270     apr_status_t rv = APR_SUCCESS;
271     const char *id;
272     tls_cert_reg_entry_t *entry;
273 
274     id = cert_spec_to_id(spec);
275     assert(id);
276     entry = apr_hash_get(reg->id2entry, id, APR_HASH_KEY_STRING);
277     if (!entry) {
278         const rustls_certified_key *certified_key;
279         const char *cert_pem;
280         rv = tls_cert_load_cert_key(reg->pool, spec, &cert_pem, &certified_key);
281         if (APR_SUCCESS != rv) goto cleanup;
282         entry = apr_pcalloc(reg->pool, sizeof(*entry));
283         entry->id = apr_pstrdup(reg->pool, id);
284         entry->cert_pem = cert_pem;
285         entry->server = s;
286         entry->certified_key = certified_key;
287         apr_hash_set(reg->id2entry, entry->id, APR_HASH_KEY_STRING, entry);
288         /* associates the pointer value */
289         apr_hash_set(reg->key2entry, &entry->certified_key, sizeof(entry->certified_key), entry);
290     }
291 
292 cleanup:
293     if (APR_SUCCESS == rv) {
294         *pckey = entry->certified_key;
295     }
296     else {
297         *pckey = NULL;
298     }
299     return rv;
300 }
301 
302 typedef struct {
303     void *userdata;
304     tls_cert_reg_visitor *visitor;
305 } reg_visit_ctx_t;
306 
reg_visit(void * vctx,const void * key,apr_ssize_t klen,const void * val)307 static int reg_visit(void *vctx, const void *key, apr_ssize_t klen, const void *val)
308 {
309     reg_visit_ctx_t *ctx = vctx;
310     tls_cert_reg_entry_t *entry = (tls_cert_reg_entry_t*)val;
311 
312     (void)key; (void)klen;
313     return ctx->visitor(ctx->userdata, entry->server, entry->id, entry->cert_pem, entry->certified_key);
314 }
315 
tls_cert_reg_do(tls_cert_reg_visitor * visitor,void * userdata,tls_cert_reg_t * reg)316 void tls_cert_reg_do(
317     tls_cert_reg_visitor *visitor, void *userdata, tls_cert_reg_t *reg)
318 {
319     reg_visit_ctx_t ctx;
320     ctx.visitor = visitor;
321     ctx.userdata = userdata;
322     apr_hash_do(reg_visit, &ctx, reg->id2entry);
323 }
324 
tls_cert_reg_get_id(tls_cert_reg_t * reg,const rustls_certified_key * certified_key)325 const char *tls_cert_reg_get_id(tls_cert_reg_t *reg, const rustls_certified_key *certified_key)
326 {
327     tls_cert_reg_entry_t *entry;
328 
329     entry = apr_hash_get(reg->key2entry, &certified_key, sizeof(certified_key));
330     return entry? entry->id : NULL;
331 }
332 
tls_cert_load_root_store(apr_pool_t * p,const char * store_file,rustls_root_cert_store ** pstore)333 apr_status_t tls_cert_load_root_store(
334     apr_pool_t *p, const char *store_file, rustls_root_cert_store **pstore)
335 {
336     const char *fpath;
337     tls_data_t pem;
338     rustls_root_cert_store *store = NULL;
339     rustls_result rr = RUSTLS_RESULT_OK;
340     apr_pool_t *ptemp = NULL;
341     apr_status_t rv;
342 
343     ap_assert(store_file);
344 
345     rv = apr_pool_create(&ptemp, p);
346     if (APR_SUCCESS != rv) goto cleanup;
347     apr_pool_tag(ptemp, "tls_load_root_cert_store");
348     fpath = ap_server_root_relative(ptemp, store_file);
349     if (NULL == fpath) {
350         rv = APR_ENOENT; goto cleanup;
351     }
352     /* we use this for client auth CAs. 1MB seems large enough. */
353     rv = tls_util_file_load(ptemp, fpath, 0, 1024*1024, &pem);
354     if (APR_SUCCESS != rv) goto cleanup;
355 
356     store = rustls_root_cert_store_new();
357     rr = rustls_root_cert_store_add_pem(store, pem.data, pem.len, 1);
358     if (RUSTLS_RESULT_OK != rr) goto cleanup;
359 
360 cleanup:
361     if (RUSTLS_RESULT_OK != rr) {
362         const char *err_descr;
363         rv = tls_util_rustls_error(p, rr, &err_descr);
364         ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10364)
365                      "Failed to load root store %s: [%d] %s",
366                      store_file, (int)rr, err_descr);
367     }
368     if (APR_SUCCESS == rv) {
369         *pstore = store;
370     }
371     else {
372         *pstore = NULL;
373         if (store) rustls_root_cert_store_free(store);
374     }
375     if (ptemp) apr_pool_destroy(ptemp);
376     return rv;
377 }
378 
379 typedef struct {
380     const char *id;
381     rustls_root_cert_store *store;
382 } tls_cert_root_stores_entry_t;
383 
stores_entry_cleanup(void * ctx,const void * key,apr_ssize_t klen,const void * val)384 static int stores_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
385 {
386     tls_cert_root_stores_entry_t *entry = (tls_cert_root_stores_entry_t*)val;
387     (void)ctx; (void)key; (void)klen;
388     if (entry->store) {
389         rustls_root_cert_store_free(entry->store);
390         entry->store = NULL;
391     }
392     return 1;
393 }
394 
stores_cleanup(void * data)395 static apr_status_t stores_cleanup(void *data)
396 {
397     tls_cert_root_stores_t *stores = data;
398     tls_cert_root_stores_clear(stores);
399     return APR_SUCCESS;
400 }
401 
tls_cert_root_stores_make(apr_pool_t * p)402 tls_cert_root_stores_t *tls_cert_root_stores_make(apr_pool_t *p)
403 {
404     tls_cert_root_stores_t *stores;
405 
406     stores = apr_pcalloc(p, sizeof(*stores));
407     stores->pool = p;
408     stores->file2store = apr_hash_make(p);
409     apr_pool_cleanup_register(p, stores, stores_cleanup, apr_pool_cleanup_null);
410     return stores;
411 }
412 
tls_cert_root_stores_clear(tls_cert_root_stores_t * stores)413 void tls_cert_root_stores_clear(tls_cert_root_stores_t *stores)
414 {
415     if (stores->file2store) {
416         apr_hash_do(stores_entry_cleanup, stores, stores->file2store);
417         apr_hash_clear(stores->file2store);
418     }
419 }
420 
tls_cert_root_stores_get(tls_cert_root_stores_t * stores,const char * store_file,rustls_root_cert_store ** pstore)421 apr_status_t tls_cert_root_stores_get(
422     tls_cert_root_stores_t *stores,
423     const char *store_file,
424     rustls_root_cert_store **pstore)
425 {
426     apr_status_t rv = APR_SUCCESS;
427     tls_cert_root_stores_entry_t *entry;
428 
429     entry = apr_hash_get(stores->file2store, store_file, APR_HASH_KEY_STRING);
430     if (!entry) {
431         rustls_root_cert_store *store;
432         rv = tls_cert_load_root_store(stores->pool, store_file, &store);
433         if (APR_SUCCESS != rv) goto cleanup;
434         entry = apr_pcalloc(stores->pool, sizeof(*entry));
435         entry->id = apr_pstrdup(stores->pool, store_file);
436         entry->store = store;
437         apr_hash_set(stores->file2store, entry->id, APR_HASH_KEY_STRING, entry);
438     }
439 
440 cleanup:
441     if (APR_SUCCESS == rv) {
442         *pstore = entry->store;
443     }
444     else {
445         *pstore = NULL;
446     }
447     return rv;
448 }
449 
450 typedef struct {
451     const char *id;
452     const rustls_client_cert_verifier *client_verifier;
453     const rustls_client_cert_verifier_optional *client_verifier_opt;
454 } tls_cert_verifiers_entry_t;
455 
verifiers_entry_cleanup(void * ctx,const void * key,apr_ssize_t klen,const void * val)456 static int verifiers_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
457 {
458     tls_cert_verifiers_entry_t *entry = (tls_cert_verifiers_entry_t*)val;
459     (void)ctx; (void)key; (void)klen;
460     if (entry->client_verifier) {
461         rustls_client_cert_verifier_free(entry->client_verifier);
462         entry->client_verifier = NULL;
463     }
464     if (entry->client_verifier_opt) {
465         rustls_client_cert_verifier_optional_free(entry->client_verifier_opt);
466         entry->client_verifier_opt = NULL;
467     }
468     return 1;
469 }
470 
verifiers_cleanup(void * data)471 static apr_status_t verifiers_cleanup(void *data)
472 {
473     tls_cert_verifiers_t *verifiers = data;
474     tls_cert_verifiers_clear(verifiers);
475     return APR_SUCCESS;
476 }
477 
tls_cert_verifiers_make(apr_pool_t * p,tls_cert_root_stores_t * stores)478 tls_cert_verifiers_t *tls_cert_verifiers_make(
479     apr_pool_t *p, tls_cert_root_stores_t *stores)
480 {
481     tls_cert_verifiers_t *verifiers;
482 
483     verifiers = apr_pcalloc(p, sizeof(*verifiers));
484     verifiers->pool = p;
485     verifiers->stores = stores;
486     verifiers->file2verifier = apr_hash_make(p);
487     apr_pool_cleanup_register(p, verifiers, verifiers_cleanup, apr_pool_cleanup_null);
488     return verifiers;
489 }
490 
tls_cert_verifiers_clear(tls_cert_verifiers_t * verifiers)491 void tls_cert_verifiers_clear(tls_cert_verifiers_t *verifiers)
492 {
493     if (verifiers->file2verifier) {
494         apr_hash_do(verifiers_entry_cleanup, verifiers, verifiers->file2verifier);
495         apr_hash_clear(verifiers->file2verifier);
496     }
497 }
498 
verifiers_get_or_make_entry(tls_cert_verifiers_t * verifiers,const char * store_file)499 static tls_cert_verifiers_entry_t * verifiers_get_or_make_entry(
500     tls_cert_verifiers_t *verifiers,
501     const char *store_file)
502 {
503     tls_cert_verifiers_entry_t *entry;
504 
505     entry = apr_hash_get(verifiers->file2verifier, store_file, APR_HASH_KEY_STRING);
506     if (!entry) {
507         entry = apr_pcalloc(verifiers->pool, sizeof(*entry));
508         entry->id = apr_pstrdup(verifiers->pool, store_file);
509         apr_hash_set(verifiers->file2verifier, entry->id, APR_HASH_KEY_STRING, entry);
510     }
511     return entry;
512 }
513 
tls_cert_client_verifiers_get(tls_cert_verifiers_t * verifiers,const char * store_file,const rustls_client_cert_verifier ** pverifier)514 apr_status_t tls_cert_client_verifiers_get(
515     tls_cert_verifiers_t *verifiers,
516     const char *store_file,
517     const rustls_client_cert_verifier **pverifier)
518 {
519     apr_status_t rv = APR_SUCCESS;
520     tls_cert_verifiers_entry_t *entry;
521 
522     entry = verifiers_get_or_make_entry(verifiers, store_file);
523     if (!entry->client_verifier) {
524         rustls_root_cert_store *store;
525         rv = tls_cert_root_stores_get(verifiers->stores, store_file, &store);
526         if (APR_SUCCESS != rv) goto cleanup;
527         entry->client_verifier = rustls_client_cert_verifier_new(store);
528     }
529 
530 cleanup:
531     if (APR_SUCCESS == rv) {
532         *pverifier = entry->client_verifier;
533     }
534     else {
535         *pverifier = NULL;
536     }
537     return rv;
538 }
539 
tls_cert_client_verifiers_get_optional(tls_cert_verifiers_t * verifiers,const char * store_file,const rustls_client_cert_verifier_optional ** pverifier)540 apr_status_t tls_cert_client_verifiers_get_optional(
541     tls_cert_verifiers_t *verifiers,
542     const char *store_file,
543     const rustls_client_cert_verifier_optional **pverifier)
544 {
545     apr_status_t rv = APR_SUCCESS;
546     tls_cert_verifiers_entry_t *entry;
547 
548     entry = verifiers_get_or_make_entry(verifiers, store_file);
549     if (!entry->client_verifier_opt) {
550         rustls_root_cert_store *store;
551         rv = tls_cert_root_stores_get(verifiers->stores, store_file, &store);
552         if (APR_SUCCESS != rv) goto cleanup;
553         entry->client_verifier_opt = rustls_client_cert_verifier_optional_new(store);
554     }
555 
556 cleanup:
557     if (APR_SUCCESS == rv) {
558         *pverifier = entry->client_verifier_opt;
559     }
560     else {
561         *pverifier = NULL;
562     }
563     return rv;
564 }
565