Apache HTTPD
tls_cert.c
Go to the documentation of this file.
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
31extern module AP_MODULE_DECLARE_DATA tls_module;
33
34
37{
38 apr_status_t rv;
39 const char *fpath;
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 }
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
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{
75 char *pem = NULL, *s;
78
79 if (der_len > INT_MAX) {
80 rv = APR_ENOMEM;
81 goto cleanup;
82 }
83 in_len = (apr_ssize_t)der_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,
105 s += n;
106 *s++ = '\n';
107 }
108 if (footer) {
109 strcpy(s, footer);
110 s += ft_len;
111 *s++ = '\n';
112 }
113cleanup:
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
122{
123 const unsigned char* der_data;
124 size_t der_len;
127 const char *pem = NULL;
128
130 if (RUSTLS_RESULT_OK != rr) goto cleanup;
132cleanup:
133 if (RUSTLS_RESULT_OK != rr) {
135 }
136 *ppem = (APR_SUCCESS == rv)? pem : NULL;
137 return rv;
138}
139
141{
142 if (pems->pkey_pem.len) {
143 memset((void*)pems->pkey_pem.data, 0, pems->pkey_pem.len);
144 }
145}
146
148 apr_pool_t *p, const char *name,
149 const tls_data_t *cert_pem, const tls_data_t *pkey_pem,
151{
155
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;
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) {
173 }
174 return rv;
175}
176
178 apr_pool_t *p, const tls_cert_spec_t *spec,
179 const char **pcert_pem, const rustls_certified_key **pckey)
180{
182
183 if (spec->cert_file) {
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. */
192 }
193 else if (spec->cert_pem) {
194 tls_data_t pkey_pem, 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 }
209cleanup:
210 return rv;
211}
212
213typedef struct {
214 const char *id;
215 const char *cert_pem;
219
220static int reg_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
221{
223 (void)ctx; (void)key; (void)klen;
224 if (entry->certified_key) {
226 entry->certified_key = NULL;
227 }
228 return 1;
229}
230
232{
233 tls_cert_reg_t *reg = data;
234 if (reg->id2entry) {
237 if (reg->key2entry) apr_hash_clear(reg->key2entry);
238 }
239 return APR_SUCCESS;
240}
241
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);
251 return reg;
252}
253
258
259static 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
267 tls_cert_reg_t *reg, server_rec *s, const tls_cert_spec_t *spec,
269{
271 const char *id;
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
292cleanup:
293 if (APR_SUCCESS == rv) {
294 *pckey = entry->certified_key;
295 }
296 else {
297 *pckey = NULL;
298 }
299 return rv;
300}
301
306
307static int reg_visit(void *vctx, const void *key, apr_ssize_t klen, const void *val)
308{
311
312 (void)key; (void)klen;
313 return ctx->visitor(ctx->userdata, entry->server, entry->id, entry->cert_pem, entry->certified_key);
314}
315
317 tls_cert_reg_visitor *visitor, void *userdata, tls_cert_reg_t *reg)
318{
320 ctx.visitor = visitor;
321 ctx.userdata = userdata;
323}
324
325const char *tls_cert_reg_get_id(tls_cert_reg_t *reg, const rustls_certified_key *certified_key)
326{
328
329 entry = apr_hash_get(reg->key2entry, &certified_key, sizeof(certified_key));
330 return entry? entry->id : NULL;
331}
332
334 apr_pool_t *p, const char *store_file, const rustls_root_cert_store **pstore)
335{
336 const char *fpath;
339 const rustls_root_cert_store *store = NULL;
341 apr_pool_t *ptemp = NULL;
342 apr_status_t rv;
343
345
346 rv = apr_pool_create(&ptemp, p);
347 if (APR_SUCCESS != rv) goto cleanup;
348 apr_pool_tag(ptemp, "tls_load_root_cert_store");
350 if (NULL == fpath) {
351 rv = APR_ENOENT; goto cleanup;
352 }
353 /* we use this for client auth CAs. 1MB seems large enough. */
354 rv = tls_util_file_load(ptemp, fpath, 0, 1024*1024, &pem);
355 if (APR_SUCCESS != rv) goto cleanup;
356
359 if (RUSTLS_RESULT_OK != rr) goto cleanup;
360
362 if (RUSTLS_RESULT_OK != rr) goto cleanup;
363
364cleanup:
365 if (store_builder != NULL) {
367 }
368 if (RUSTLS_RESULT_OK != rr) {
369 const char *err_descr;
372 "Failed to load root store %s: [%d] %s",
373 store_file, (int)rr, err_descr);
374 }
375 if (APR_SUCCESS == rv) {
376 *pstore = store;
377 }
378 else {
379 *pstore = NULL;
380 if (store) rustls_root_cert_store_free(store);
381 }
382 if (ptemp) apr_pool_destroy(ptemp);
383 return rv;
384}
385
386typedef struct {
387 const char *id;
390
391static int stores_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
392{
394 (void)ctx; (void)key; (void)klen;
395 if (entry->store) {
397 entry->store = NULL;
398 }
399 return 1;
400}
401
403{
406 return APR_SUCCESS;
407}
408
410{
412
413 stores = apr_pcalloc(p, sizeof(*stores));
414 stores->pool = p;
415 stores->file2store = apr_hash_make(p);
417 return stores;
418}
419
421{
422 if (stores->file2store) {
424 apr_hash_clear(stores->file2store);
425 }
426}
427
430 const char *store_file,
432{
435
437 if (!entry) {
438 const rustls_root_cert_store *store;
439 rv = tls_cert_load_root_store(stores->pool, store_file, &store);
440 if (APR_SUCCESS != rv) goto cleanup;
441 entry = apr_pcalloc(stores->pool, sizeof(*entry));
442 entry->id = apr_pstrdup(stores->pool, store_file);
443 entry->store = store;
444 apr_hash_set(stores->file2store, entry->id, APR_HASH_KEY_STRING, entry);
445 }
446
447cleanup:
448 if (APR_SUCCESS == rv) {
449 *pstore = entry->store;
450 }
451 else {
452 *pstore = NULL;
453 }
454 return rv;
455}
456
462
463static int verifiers_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
464{
466 (void)ctx; (void)key; (void)klen;
467 if (entry->client_verifier) {
469 entry->client_verifier = NULL;
470 }
471 if (entry->client_verifier_opt) {
473 entry->client_verifier_opt = NULL;
474 }
475 return 1;
476}
477
479{
480 tls_cert_verifiers_t *verifiers = data;
481 tls_cert_verifiers_clear(verifiers);
482 return APR_SUCCESS;
483}
484
487{
488 tls_cert_verifiers_t *verifiers;
489
490 verifiers = apr_pcalloc(p, sizeof(*verifiers));
491 verifiers->pool = p;
492 verifiers->stores = stores;
493 verifiers->file2verifier = apr_hash_make(p);
495 return verifiers;
496}
497
499{
500 if (verifiers->file2verifier) {
501 apr_hash_do(verifiers_entry_cleanup, verifiers, verifiers->file2verifier);
502 apr_hash_clear(verifiers->file2verifier);
503 }
504}
505
507 tls_cert_verifiers_t *verifiers,
508 const char *store_file)
509{
511
513 if (!entry) {
514 entry = apr_pcalloc(verifiers->pool, sizeof(*entry));
515 entry->id = apr_pstrdup(verifiers->pool, store_file);
516 apr_hash_set(verifiers->file2verifier, entry->id, APR_HASH_KEY_STRING, entry);
517 }
518 return entry;
519}
520
567
568
576
int n
Definition ap_regex.h:278
APR-UTIL Encoding.
APR general purpose library routines.
APR Strings library.
#define APLOG_USE_MODULE(foo)
char * ap_server_root_relative(apr_pool_t *p, const char *fname)
Definition config.c:1594
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_MARK
Definition http_log.h:283
#define ap_log_perror
Definition http_log.h:412
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_ENOENT
Definition apr_errno.h:662
apr_brigade_flush void * ctx
#define APR_ENCODE_NONE
Definition apr_encode.h:110
#define ap_assert(exp)
Definition httpd.h:2271
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
void * data
void const char apr_status_t(* cleanup)(void *))
apr_ssize_t * klen
Definition apr_hash.h:71
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
const char apr_uint32_t * id
#define apr_pool_create(newpool, parent)
Definition apr_pools.h:322
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
Apache connection library.
CORE HTTP Daemon.
Apache Logging library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
void * userdata
Definition tls_cert.c:303
tls_cert_reg_visitor * visitor
Definition tls_cert.c:304
A structure to store information for each virtual server.
Definition httpd.h:1322
Definition tls_cert.c:213
server_rec * server
Definition tls_cert.c:216
const rustls_certified_key * certified_key
Definition tls_cert.c:217
const char * cert_pem
Definition tls_cert.c:215
const char * id
Definition tls_cert.c:214
apr_pool_t * pool
Definition tls_cert.h:64
apr_hash_t * key2entry
Definition tls_cert.h:66
apr_hash_t * id2entry
Definition tls_cert.h:65
Definition tls_cert.c:386
const char * id
Definition tls_cert.c:387
const rustls_root_cert_store * store
Definition tls_cert.c:388
apr_hash_t * file2store
Definition tls_cert.h:136
apr_pool_t * pool
Definition tls_cert.h:135
const char * cert_file
Definition tls_cert.h:33
const char * pkey_pem
Definition tls_cert.h:36
const char * cert_pem
Definition tls_cert.h:35
Definition tls_cert.c:457
rustls_client_cert_verifier * client_verifier
Definition tls_cert.c:459
rustls_client_cert_verifier * client_verifier_opt
Definition tls_cert.c:460
const char * id
Definition tls_cert.c:458
apr_pool_t * pool
Definition tls_cert.h:164
tls_cert_root_stores_t * stores
Definition tls_cert.h:165
apr_hash_t * file2verifier
Definition tls_cert.h:166
apr_size_t len
Definition tls_util.h:28
const unsigned char * data
Definition tls_util.h:27
static void nullify_key_pem(tls_cert_pem_t *pems)
Definition tls_cert.c:140
static apr_status_t verifiers_cleanup(void *data)
Definition tls_cert.c:478
#define PEM_CERT_FT
Definition tls_cert.c:119
apr_size_t tls_cert_reg_count(tls_cert_reg_t *reg)
Definition tls_cert.c:254
apr_status_t tls_cert_client_verifiers_get_optional(tls_cert_verifiers_t *verifiers, const char *store_file, const rustls_client_cert_verifier **pverifier)
Definition tls_cert.c:577
apr_status_t tls_cert_root_stores_get(tls_cert_root_stores_t *stores, const char *store_file, const rustls_root_cert_store **pstore)
Definition tls_cert.c:428
static apr_status_t stores_cleanup(void *data)
Definition tls_cert.c:402
static apr_status_t 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)
Definition tls_cert.c:69
#define PEM_IN_CHUNK
Definition tls_cert.c:67
void tls_cert_reg_do(tls_cert_reg_visitor *visitor, void *userdata, tls_cert_reg_t *reg)
Definition tls_cert.c:316
void tls_cert_verifiers_clear(tls_cert_verifiers_t *verifiers)
Definition tls_cert.c:498
apr_status_t 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)
Definition tls_cert.c:266
void tls_cert_root_stores_clear(tls_cert_root_stores_t *stores)
Definition tls_cert.c:420
apr_status_t tls_cert_load_cert_key(apr_pool_t *p, const tls_cert_spec_t *spec, const char **pcert_pem, const rustls_certified_key **pckey)
Definition tls_cert.c:177
static apr_status_t tls_cert_client_verifiers_get_internal(tls_cert_verifiers_t *verifiers, const char *store_file, const rustls_client_cert_verifier **pverifier, bool allow_unauthenticated)
Definition tls_cert.c:521
#define PEM_CERT_HD
Definition tls_cert.c:118
static apr_status_t reg_cleanup(void *data)
Definition tls_cert.c:231
static const char * cert_spec_to_id(const tls_cert_spec_t *spec)
Definition tls_cert.c:259
apr_status_t tls_cert_to_pem(const char **ppem, apr_pool_t *p, const rustls_certificate *cert)
Definition tls_cert.c:121
apr_status_t tls_cert_load_root_store(apr_pool_t *p, const char *store_file, const rustls_root_cert_store **pstore)
Definition tls_cert.c:333
static tls_cert_verifiers_entry_t * verifiers_get_or_make_entry(tls_cert_verifiers_t *verifiers, const char *store_file)
Definition tls_cert.c:506
static int stores_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
Definition tls_cert.c:391
const char * tls_cert_reg_get_id(tls_cert_reg_t *reg, const rustls_certified_key *certified_key)
Definition tls_cert.c:325
static int reg_visit(void *vctx, const void *key, apr_ssize_t klen, const void *val)
Definition tls_cert.c:307
static int reg_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
Definition tls_cert.c:220
static int verifiers_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val)
Definition tls_cert.c:463
static apr_status_t 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)
Definition tls_cert.c:147
tls_cert_verifiers_t * tls_cert_verifiers_make(apr_pool_t *p, tls_cert_root_stores_t *stores)
Definition tls_cert.c:485
apr_status_t tls_cert_load_pem(apr_pool_t *p, const tls_cert_spec_t *cert, tls_cert_pem_t **ppem)
Definition tls_cert.c:35
tls_cert_reg_t * tls_cert_reg_make(apr_pool_t *p)
Definition tls_cert.c:242
apr_status_t tls_cert_client_verifiers_get(tls_cert_verifiers_t *verifiers, const char *store_file, const rustls_client_cert_verifier **pverifier)
Definition tls_cert.c:569
tls_cert_root_stores_t * tls_cert_root_stores_make(apr_pool_t *p)
Definition tls_cert.c:409
int tls_cert_reg_visitor(void *userdata, server_rec *s, const char *id, const char *cert_pem, const rustls_certified_key *certified_key)
Definition tls_cert.h:102
tls_data_t tls_data_from_str(const char *s)
Definition tls_util.c:35
apr_status_t tls_util_rustls_error(apr_pool_t *p, rustls_result rr, const char **perr_descr)
Definition tls_util.c:66
apr_status_t 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)
Definition tls_util.c:89
const char * tls_data_to_str(apr_pool_t *p, const tls_data_t *d)
Definition tls_util.c:59