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