Apache HTTPD
md_core.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
17#include <assert.h>
18#include <stdlib.h>
19
20#include <apr_lib.h>
21#include <apr_strings.h>
22#include <apr_uri.h>
23#include <apr_tables.h>
24#include <apr_time.h>
25#include <apr_date.h>
26
27#include "md_json.h"
28#include "md.h"
29#include "md_crypt.h"
30#include "md_log.h"
31#include "md_store.h"
32#include "md_util.h"
33
34
35int md_contains(const md_t *md, const char *domain, int case_sensitive)
36{
37 if (md_array_str_index(md->domains, domain, 0, case_sensitive) >= 0) {
38 return 1;
39 }
40 return md_dns_domains_match(md->domains, domain);
41}
42
43const char *md_common_name(const md_t *md1, const md_t *md2)
44{
45 int i;
46
47 if (md1 == NULL || md1->domains == NULL
48 || md2 == NULL || md2->domains == NULL) {
49 return NULL;
50 }
51
52 for (i = 0; i < md1->domains->nelts; ++i) {
53 const char *name1 = APR_ARRAY_IDX(md1->domains, i, const char*);
54 if (md_contains(md2, name1, 0)) {
55 return name1;
56 }
57 }
58 return NULL;
59}
60
61int md_domains_overlap(const md_t *md1, const md_t *md2)
62{
63 return md_common_name(md1, md2) != NULL;
64}
65
67{
68 int i;
70
71 if (md1 == NULL || md1->domains == NULL
72 || md2 == NULL || md2->domains == NULL) {
73 return 0;
74 }
75
76 hits = 0;
77 for (i = 0; i < md1->domains->nelts; ++i) {
78 const char *name1 = APR_ARRAY_IDX(md1->domains, i, const char*);
79 if (md_contains(md2, name1, 0)) {
80 ++hits;
81 }
82 }
83 return hits;
84}
85
87{
88 const char *name;
89 int i;
90
91 if (alt_names) {
92 for (i = 0; i < md->domains->nelts; ++i) {
93 name = APR_ARRAY_IDX(md->domains, i, const char *);
95 return 0;
96 }
97 }
98 return 1;
99 }
100 return 0;
101}
102
104{
105 md_t *md = apr_pcalloc(p, sizeof(*md));
106 if (md) {
107 md->domains = apr_array_make(p, 5, sizeof(const char *));
108 md->contacts = apr_array_make(p, 5, sizeof(const char *));
111 md->must_staple = -1;
112 md->transitive = -1;
113 md->acme_tls_1_domains = apr_array_make(p, 5, sizeof(const char *));
114 md->stapling = -1;
115 md->defn_name = "unknown";
116 md->defn_line_number = 0;
117 }
118 return md;
119}
120
122{
123 int i;
124 if (md1->domains->nelts == md2->domains->nelts) {
125 for (i = 0; i < md1->domains->nelts; ++i) {
126 const char *name1 = APR_ARRAY_IDX(md1->domains, i, const char*);
128 return 0;
129 }
130 }
131 return 1;
132 }
133 return 0;
134}
135
137{
138 int i;
139 if (md1->domains->nelts >= md2->domains->nelts) {
140 for (i = 0; i < md2->domains->nelts; ++i) {
141 const char *name2 = APR_ARRAY_IDX(md2->domains, i, const char*);
142 if (!md_contains(md1, name2, 0)) {
143 return 0;
144 }
145 }
146 return 1;
147 }
148 return 0;
149}
150
151md_t *md_get_by_name(struct apr_array_header_t *mds, const char *name)
152{
153 int i;
154 for (i = 0; i < mds->nelts; ++i) {
155 md_t *md = APR_ARRAY_IDX(mds, i, md_t *);
156 if (!strcmp(name, md->name)) {
157 return md;
158 }
159 }
160 return NULL;
161}
162
163md_t *md_get_by_domain(struct apr_array_header_t *mds, const char *domain)
164{
165 int i;
166 for (i = 0; i < mds->nelts; ++i) {
167 md_t *md = APR_ARRAY_IDX(mds, i, md_t *);
168 if (md_contains(md, domain, 0)) {
169 return md;
170 }
171 }
172 return NULL;
173}
174
176{
177 int i;
178 for (i = 0; i < mds->nelts; ++i) {
179 md_t *o = APR_ARRAY_IDX(mds, i, md_t *);
180 if (strcmp(o->name, md->name) && md_common_name(o, md)) {
181 return o;
182 }
183 }
184 return NULL;
185}
186
187int md_cert_count(const md_t *md)
188{
189 /* cert are defined as a list of static files or a list of private key specs */
190 if (md->cert_files && md->cert_files->nelts) {
191 return md->cert_files->nelts;
192 }
193 return md_pkeys_spec_count(md->pks);
194}
195
197{
198 md_t *md;
199
200 md = md_create_empty(p);
201 md->domains = md_array_str_compact(p, domains, 0);
202 md->name = APR_ARRAY_IDX(md->domains, 0, const char *);
203
204 return md;
205}
206
207/**************************************************************************************************/
208/* lifetime */
209
211{
212 md_t *md;
213
214 md = apr_pcalloc(p, sizeof(*md));
215 if (md) {
216 memcpy(md, src, sizeof(*md));
217 md->domains = apr_array_copy(p, src->domains);
218 md->contacts = apr_array_copy(p, src->contacts);
219 if (src->ca_challenges) {
220 md->ca_challenges = apr_array_copy(p, src->ca_challenges);
221 }
222 md->acme_tls_1_domains = apr_array_copy(p, src->acme_tls_1_domains);
223 md->pks = md_pkeys_spec_clone(p, src->pks);
224 }
225 return md;
226}
227
229{
230 md_t *md;
231
232 md = apr_pcalloc(p, sizeof(*md));
233 if (md) {
234 md->state = src->state;
235 md->name = apr_pstrdup(p, src->name);
236 md->require_https = src->require_https;
237 md->must_staple = src->must_staple;
238 md->renew_mode = src->renew_mode;
239 md->domains = md_array_str_compact(p, src->domains, 0);
240 md->pks = md_pkeys_spec_clone(p, src->pks);
241 md->renew_window = src->renew_window;
242 md->warn_window = src->warn_window;
243 md->contacts = md_array_str_clone(p, src->contacts);
244 if (src->ca_proto) md->ca_proto = apr_pstrdup(p, src->ca_proto);
245 if (src->ca_urls) {
246 md->ca_urls = md_array_str_clone(p, src->ca_urls);
247 }
248 if (src->ca_effective) md->ca_effective = apr_pstrdup(p, src->ca_effective);
249 if (src->ca_account) md->ca_account = apr_pstrdup(p, src->ca_account);
250 if (src->ca_agreement) md->ca_agreement = apr_pstrdup(p, src->ca_agreement);
251 if (src->defn_name) md->defn_name = apr_pstrdup(p, src->defn_name);
252 md->defn_line_number = src->defn_line_number;
253 if (src->ca_challenges) {
254 md->ca_challenges = md_array_str_clone(p, src->ca_challenges);
255 }
256 md->acme_tls_1_domains = md_array_str_compact(p, src->acme_tls_1_domains, 0);
257 md->stapling = src->stapling;
258 if (src->dns01_cmd) md->dns01_cmd = apr_pstrdup(p, src->dns01_cmd);
259 if (src->cert_files) md->cert_files = md_array_str_clone(p, src->cert_files);
260 if (src->pkey_files) md->pkey_files = md_array_str_clone(p, src->pkey_files);
261 }
262 return md;
263}
264
265/**************************************************************************************************/
266/* format conversion */
267
269{
270 md_json_t *json = md_json_create(p);
271 if (json) {
273 md_json_sets(md->name, json, MD_KEY_NAME, NULL);
274 md_json_setsa(domains, json, MD_KEY_DOMAINS, NULL);
280 if (md->ca_urls && !apr_is_empty_array(md->ca_urls)) {
282 }
284 if (!md_pkeys_spec_is_empty(md->pks)) {
286 }
287 md_json_setl(md->state, json, MD_KEY_STATE, NULL);
288 if (md->state_descr)
291 if (md->renew_window)
293 if (md->warn_window)
295 if (md->ca_challenges && md->ca_challenges->nelts > 0) {
299 }
300 switch (md->require_https) {
303 break;
306 break;
307 default:
308 break;
309 }
314 md_json_setb(md->stapling > 0, json, MD_KEY_STAPLING, NULL);
316 if (md->ca_eab_kid && strcmp("none", md->ca_eab_kid)) {
319 }
320 return json;
321 }
322 return NULL;
323}
324
326{
327 const char *s;
328 md_t *md = md_create_empty(p);
329 if (md) {
330 md->name = md_json_dups(p, json, MD_KEY_NAME, NULL);
337 md->ca_urls = apr_array_make(p, 5, sizeof(const char*));
339 }
340 else if (md->ca_effective) {
341 /* compat for old format where we had only a single url */
342 md->ca_urls = apr_array_make(p, 5, sizeof(const char*));
343 APR_ARRAY_PUSH(md->ca_urls, const char*) = md->ca_effective;
344 }
346 if (md_json_has_key(json, MD_KEY_PKEY, NULL)) {
348 }
353 md->domains = md_array_str_compact(p, md->domains, 0);
360 md->ca_challenges = apr_array_make(p, 5, sizeof(const char*));
362 }
365 if (s && !strcmp(MD_KEY_TEMPORARY, s)) {
367 }
368 else if (s && !strcmp(MD_KEY_PERMANENT, s)) {
370 }
373
375 md->cert_files = apr_array_make(p, 3, sizeof(char*));
376 md->pkey_files = apr_array_make(p, 3, sizeof(char*));
379 }
382 if (md_json_has_key(json, MD_KEY_EAB, NULL)) {
385 }
386 return md;
387 }
388 return NULL;
389}
390
392{
393 md_json_t *json = md_to_json(md, p);
395 md_json_sets("***", json, MD_KEY_EAB, MD_KEY_HMAC, NULL);
396 }
397 return json;
398}
399
400typedef struct {
401 const char *name;
402 const char *url;
403} md_ca_t;
404
405#define LE_ACMEv2_PROD "https://acme-v02.api.letsencrypt.org/directory"
406#define LE_ACMEv2_STAGING "https://acme-staging-v02.api.letsencrypt.org/directory"
407#define BUYPASS_ACME "https://api.buypass.com/acme/directory"
408#define BUYPASS_ACME_TEST "https://api.test4.buypass.no/acme/directory"
409
410static md_ca_t KNOWN_CAs[] = {
411 { "LetsEncrypt", LE_ACMEv2_PROD },
412 { "LetsEncrypt-Test", LE_ACMEv2_STAGING },
413 { "Buypass", BUYPASS_ACME },
414 { "Buypass-Test", BUYPASS_ACME_TEST },
415};
416
417const char *md_get_ca_name_from_url(apr_pool_t *p, const char *url)
418{
420 unsigned int i;
421
422 for (i = 0; i < sizeof(KNOWN_CAs)/sizeof(KNOWN_CAs[0]); ++i) {
424 return KNOWN_CAs[i].name;
425 }
426 }
428 return uri_parsed.hostname;
429 }
430 return apr_pstrdup(p, url);
431}
432
434{
435 const char *err;
436 unsigned int i;
438
439 *purl = NULL;
440 for (i = 0; i < sizeof(KNOWN_CAs)/sizeof(KNOWN_CAs[0]); ++i) {
442 *purl = KNOWN_CAs[i].url;
443 goto leave;
444 }
445 }
446 *purl = name;
448 if (APR_SUCCESS != rv) {
450
451 names = apr_array_make(p, 10, sizeof(const char*));
452 for (i = 0; i < sizeof(KNOWN_CAs)/sizeof(KNOWN_CAs[0]); ++i) {
453 APR_ARRAY_PUSH(names, const char *) = KNOWN_CAs[i].name;
454 }
456 "The CA name '%s' is not known and it is not a URL either (%s). "
457 "Known CA names are: %s.",
458 name, err, apr_array_pstrcat(p, names, ' '));
459 }
460leave:
461 return rv;
462}
APR-UTIL date routines.
APR general purpose library routines.
APR Strings library.
APR Table library.
APR Time Library.
APR-UTIL URI Routines.
const char * src
Definition apr_encode.h:167
const char * url
Definition apr_escape.h:120
const char int case_sensitive
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
#define APR_ARRAY_PUSH(ary, type)
Definition apr_tables.h:150
#define APR_ARRAY_IDX(ary, i, type)
Definition apr_tables.h:141
apr_int32_t apr_int32_t apr_int32_t err
#define MD_KEY_HMAC
Definition md.h:152
#define MD_KEY_WARN_WINDOW
Definition md.h:216
#define MD_KEY_STATE_DESCR
Definition md.h:195
#define MD_KEY_ACME_TLS_1
Definition md.h:116
#define MD_KEY_RENEW_MODE
Definition md.h:183
md_state_t
Definition md.h:52
@ MD_S_COMPLETE
Definition md.h:55
@ MD_S_EXPIRED_DEPRECATED
Definition md.h:56
#define MD_KEY_PKEY
Definition md.h:175
#define MD_KEY_NAME
Definition md.h:167
#define MD_KEY_URL
Definition md.h:207
#define MD_KEY_ACCOUNT
Definition md.h:115
#define MD_TIME_LIFE_NORM
Definition md.h:45
#define MD_KEY_TRANSITIVE
Definition md.h:203
#define MD_KEY_STAPLING
Definition md.h:193
#define MD_KEY_PROTO
Definition md.h:178
#define MD_KEY_TEMPORARY
Definition md.h:199
#define MD_KEY_CMD_DNS01
Definition md.h:129
#define MD_KEY_KID
Definition md.h:158
#define MD_KEY_CERT_FILES
Definition md.h:125
#define MD_KEY_PKEY_FILES
Definition md.h:176
#define MD_KEY_EAB
Definition md.h:141
#define MD_KEY_AGREEMENT
Definition md.h:119
#define MD_KEY_STATE
Definition md.h:194
#define MD_KEY_CA
Definition md.h:122
#define MD_KEY_CHALLENGES
Definition md.h:128
#define MD_KEY_CONTACTS
Definition md.h:133
#define MD_KEY_URLS
Definition md.h:208
#define MD_KEY_PERMANENT
Definition md.h:174
@ MD_RENEW_DEFAULT
Definition md.h:69
#define MD_KEY_REQUIRE_HTTPS
Definition md.h:187
#define MD_KEY_RENEW_WINDOW
Definition md.h:186
#define MD_KEY_MUST_STAPLE
Definition md.h:166
@ MD_REQUIRE_UNSET
Definition md.h:62
@ MD_REQUIRE_OFF
Definition md.h:63
@ MD_REQUIRE_TEMPORARY
Definition md.h:64
@ MD_REQUIRE_PERMANENT
Definition md.h:65
#define MD_KEY_DOMAINS
Definition md.h:140
int md_equal_domains(const md_t *md1, const md_t *md2, int case_sensitive)
Definition md_core.c:121
int md_cert_count(const md_t *md)
Definition md_core.c:187
int md_is_covered_by_alt_names(const md_t *md, const struct apr_array_header_t *alt_names)
Definition md_core.c:86
#define BUYPASS_ACME
Definition md_core.c:407
#define LE_ACMEv2_STAGING
Definition md_core.c:406
md_t * md_clone(apr_pool_t *p, const md_t *src)
Definition md_core.c:228
md_t * md_from_json(md_json_t *json, apr_pool_t *p)
Definition md_core.c:325
md_t * md_get_by_name(struct apr_array_header_t *mds, const char *name)
Definition md_core.c:151
static md_ca_t KNOWN_CAs[]
Definition md_core.c:410
const char * md_common_name(const md_t *md1, const md_t *md2)
Definition md_core.c:43
md_t * md_get_by_domain(struct apr_array_header_t *mds, const char *domain)
Definition md_core.c:163
int md_domains_overlap(const md_t *md1, const md_t *md2)
Definition md_core.c:61
md_t * md_copy(apr_pool_t *p, const md_t *src)
Definition md_core.c:210
apr_size_t md_common_name_count(const md_t *md1, const md_t *md2)
Definition md_core.c:66
md_json_t * md_to_json(const md_t *md, apr_pool_t *p)
Definition md_core.c:268
md_t * md_create(apr_pool_t *p, apr_array_header_t *domains)
Definition md_core.c:196
#define BUYPASS_ACME_TEST
Definition md_core.c:408
md_t * md_get_by_dns_overlap(struct apr_array_header_t *mds, const md_t *md)
Definition md_core.c:175
const char * md_get_ca_name_from_url(apr_pool_t *p, const char *url)
Definition md_core.c:417
apr_status_t md_get_ca_url_from_name(const char **purl, apr_pool_t *p, const char *name)
Definition md_core.c:433
int md_contains_domains(const md_t *md1, const md_t *md2)
Definition md_core.c:136
#define LE_ACMEv2_PROD
Definition md_core.c:405
int md_contains(const md_t *md, const char *domain, int case_sensitive)
Definition md_core.c:35
md_t * md_create_empty(apr_pool_t *p)
Definition md_core.c:103
md_json_t * md_to_public_json(const md_t *md, apr_pool_t *p)
Definition md_core.c:391
int md_pkeys_spec_count(const md_pkeys_spec_t *pks)
Definition md_crypt.c:555
md_json_t * md_pkeys_spec_to_json(const md_pkeys_spec_t *pks, apr_pool_t *p)
Definition md_crypt.c:385
static const char * alt_names(apr_array_header_t *domains, apr_pool_t *p)
Definition md_crypt.c:1692
md_pkeys_spec_t * md_pkeys_spec_clone(apr_pool_t *p, const md_pkeys_spec_t *pks)
Definition md_crypt.c:538
md_pkeys_spec_t * md_pkeys_spec_from_json(struct md_json_t *json, apr_pool_t *p)
Definition md_crypt.c:439
int md_pkeys_spec_is_empty(const md_pkeys_spec_t *pks)
Definition md_crypt.c:533
apr_pool_t * p
Definition md_event.c:32
md_json_t * md_json_create(apr_pool_t *pool)
Definition md_json.c:92
int md_json_getb(const md_json_t *json,...)
Definition md_json.c:330
apr_status_t md_json_sets(const char *value, md_json_t *json,...)
Definition md_json.c:430
const char * md_json_gets(const md_json_t *json,...)
Definition md_json.c:406
long md_json_getl(const md_json_t *json,...)
Definition md_json.c:381
md_json_t * md_json_getj(md_json_t *json,...)
Definition md_json.c:473
apr_status_t md_json_dupsa(apr_array_header_t *a, apr_pool_t *p, md_json_t *json,...)
Definition md_json.c:887
apr_status_t md_json_setj(const md_json_t *value, md_json_t *json,...)
Definition md_json.c:527
int md_json_has_key(const md_json_t *json,...)
Definition md_json.c:279
apr_status_t md_json_setb(int value, md_json_t *json,...)
Definition md_json.c:342
const char * md_json_dups(apr_pool_t *p, const md_json_t *json,...)
Definition md_json.c:418
apr_status_t md_json_setl(long value, md_json_t *json,...)
Definition md_json.c:392
apr_status_t md_json_setsa(apr_array_header_t *a, md_json_t *json,...)
Definition md_json.c:911
const char * md_timeslice_format(const md_timeslice_t *ts, apr_pool_t *p)
Definition md_time.c:277
const char * md_timeslice_parse(md_timeslice_t **pts, apr_pool_t *p, const char *val, apr_interval_time_t norm)
Definition md_time.c:247
apr_array_header_t * md_array_str_clone(apr_pool_t *p, apr_array_header_t *src)
Definition md_util.c:288
int md_dns_domains_match(const apr_array_header_t *domains, const char *name)
Definition md_util.c:907
apr_status_t md_util_abs_uri_check(apr_pool_t *p, const char *uri, const char **perr)
Definition md_util.c:1005
struct apr_array_header_t * md_array_str_compact(apr_pool_t *p, struct apr_array_header_t *src, int case_sensitive)
Definition md_util.c:301
int md_array_str_index(const apr_array_header_t *array, const char *s, int start, int case_sensitive)
Definition md_util.c:250
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
const char * url
Definition md_core.c:402
const char * name
Definition md_core.c:401
Definition md.h:76
const char * name
Definition md.h:77
md_timeslice_t * renew_window
Definition md.h:82
int transitive
Definition md.h:109
struct apr_array_header_t * domains
Definition md.h:78
const char * ca_eab_hmac
Definition md.h:94
md_timeslice_t * warn_window
Definition md.h:83
struct apr_array_header_t * acme_tls_1_domains
Definition md.h:98
md_require_t require_https
Definition md.h:107
struct apr_array_header_t * pkey_files
Definition md.h:92
const char * defn_name
Definition md.h:102
unsigned defn_line_number
Definition md.h:103
const char * ca_effective
Definition md.h:87
md_state_t state
Definition md.h:108
int must_staple
Definition md.h:110
const char * ca_proto
Definition md.h:85
struct apr_array_header_t * ca_urls
Definition md.h:86
struct md_pkeys_spec_t * pks
Definition md.h:81
const char * ca_eab_kid
Definition md.h:93
const char * ca_account
Definition md.h:88
const char * ca_agreement
Definition md.h:89
struct apr_array_header_t * contacts
Definition md.h:79
int renew_mode
Definition md.h:106
int stapling
Definition md.h:111
struct apr_array_header_t * cert_files
Definition md.h:91
const char * state_descr
Definition md.h:96
struct apr_array_header_t * ca_challenges
Definition md.h:90
const char * dns01_cmd
Definition md.h:99
typedef int(WSAAPI *apr_winapi_fpt_WSAPoll)(IN OUT LPWSAPOLLFD fdArray