mirror of
https://github.com/apache/httpd.git
synced 2025-08-08 15:02:10 +03:00
On the trunk:
mod_md: v0.8.1 from github, new feats in CHANGES git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1806939 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
24
CHANGES
24
CHANGES
@@ -1,7 +1,29 @@
|
|||||||
-*- coding: utf-8 -*-
|
-*- coding: utf-8 -*-
|
||||||
Changes with Apache 2.5.0
|
Changes with Apache 2.5.0
|
||||||
|
|
||||||
*) mod_md: v0.7.0:
|
*) mod_md: v0.8.1:
|
||||||
|
- New directive ```MDPrivateKeys``` to specify the type and parameter to private key generation.
|
||||||
|
Currently only 'RSA' is supported as type with an option number of bits >= 2048 as parameter.
|
||||||
|
Simple test cases for config handling added.
|
||||||
|
- Private RSA keys are now generated with 2048 bits by default. Use ```MDPrivateKeys``` for
|
||||||
|
higher security.
|
||||||
|
- IMPORTANT: store format change. The following changes will be made to an existing md store on
|
||||||
|
first start with a new version (be it by mod_md in the server or a run by a new 'a2md'):
|
||||||
|
- pkey.pem will be renamed to privkey.pem
|
||||||
|
- cert.pem and chain.pem will be concatenated to pubcert.pem. The former files will remain,
|
||||||
|
but no longer be used. They will disappear on next renewal.
|
||||||
|
ADVICE: If the current store data is vital to you, please make a backup first!
|
||||||
|
- Fixed test case clearing of store to keep key alive, enabling true random store key again.
|
||||||
|
- Removed pun "Something, like certbot" from the User-Agent request header. Refs issue #34
|
||||||
|
- Cleaned up reporting of missing/mismatched MDCertificateAgreement in the logs. This will
|
||||||
|
no longer trigger early retries.
|
||||||
|
- badNonce encounters are no longer reported as errors. Retries are attempted now silently.
|
||||||
|
Refs github issue #35
|
||||||
|
- new default MDRenewWindow. Instead of 14 days, the default is now a third before the end of
|
||||||
|
the certificates lifetime. For the usual 90 days of Let's Encrypt certificates, this makes
|
||||||
|
an effective renewal window of 30 days - as recommended by LE. Refs issue #30
|
||||||
|
- Enabled conversion warnings if supported by compiler, eliminated several signed/unsigned
|
||||||
|
warnings.
|
||||||
- LIVE: the real Let's Encrypt CA is now live by default! If you need to experiment, configure
|
- LIVE: the real Let's Encrypt CA is now live by default! If you need to experiment, configure
|
||||||
MDCertificateAuthority https://acme-staging.api.letsencrypt.org/directory
|
MDCertificateAuthority https://acme-staging.api.letsencrypt.org/directory
|
||||||
- When existing, complete certificates are renewed, the activation of the new ones is
|
- When existing, complete certificates are renewed, the activation of the new ones is
|
||||||
|
@@ -341,6 +341,40 @@ MDPortMap 80:- 443:5002
|
|||||||
</usage>
|
</usage>
|
||||||
</directivesynopsis>
|
</directivesynopsis>
|
||||||
|
|
||||||
|
<directivesynopsis>
|
||||||
|
<name>MDPrivateKeys</name>
|
||||||
|
<description></description>
|
||||||
|
<syntax>MDPrivateKeys type [ params... ]</syntax>
|
||||||
|
<default>MDPrivateKeys RSA 2048</default>
|
||||||
|
<contextlist>
|
||||||
|
<context>server config</context>
|
||||||
|
</contextlist>
|
||||||
|
<usage>
|
||||||
|
<p>
|
||||||
|
Defines what kind of private keys are generated for a managed domain and with
|
||||||
|
what parameters. The only supported type right now is 'RSA' and the only parameter
|
||||||
|
it takes is the number of bits used for the key.
|
||||||
|
</p><p>
|
||||||
|
The current (2017) recommendation is at least 2048 bits and a smaller number is
|
||||||
|
not accepted here. Higher numbers offer longer security, but are computationally more
|
||||||
|
expensive, e.g. increase the load on your server. That might or might not be an
|
||||||
|
issue for you.
|
||||||
|
</p><p>
|
||||||
|
Other key types will be defined in the future.
|
||||||
|
</p>
|
||||||
|
<example><title>Example</title>
|
||||||
|
<highlight language="config">
|
||||||
|
MDPrivateKeys RSA 3072
|
||||||
|
</highlight>
|
||||||
|
</example>
|
||||||
|
<p>
|
||||||
|
Please note that this setting only has an effect on new keys. Any existing
|
||||||
|
private key you have remains unaffected. Also, this only affects private keys
|
||||||
|
generated for certificates. ACME account keys are unaffected by this.
|
||||||
|
</p>
|
||||||
|
</usage>
|
||||||
|
</directivesynopsis>
|
||||||
|
|
||||||
<directivesynopsis>
|
<directivesynopsis>
|
||||||
<name>MDRenewWindow</name>
|
<name>MDRenewWindow</name>
|
||||||
<description></description>
|
<description></description>
|
||||||
|
@@ -25,8 +25,10 @@ struct md_cert_t;
|
|||||||
struct md_pkey_t;
|
struct md_pkey_t;
|
||||||
struct md_store_t;
|
struct md_store_t;
|
||||||
struct md_srv_conf_t;
|
struct md_srv_conf_t;
|
||||||
|
struct md_pkey_spec_t;
|
||||||
|
|
||||||
#define MD_TLSSNI01_DNS_SUFFIX ".acme.invalid"
|
#define MD_TLSSNI01_DNS_SUFFIX ".acme.invalid"
|
||||||
|
#define MD_PKEY_RSA_BITS_DEF 2048U
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MD_S_UNKNOWN, /* MD has not been analysed yet */
|
MD_S_UNKNOWN, /* MD has not been analysed yet */
|
||||||
@@ -34,6 +36,7 @@ typedef enum {
|
|||||||
MD_S_COMPLETE, /* MD has all necessary information, can go live */
|
MD_S_COMPLETE, /* MD has all necessary information, can go live */
|
||||||
MD_S_EXPIRED, /* MD is complete, but credentials have expired */
|
MD_S_EXPIRED, /* MD is complete, but credentials have expired */
|
||||||
MD_S_ERROR, /* MD data is flawed, unable to be processed as is */
|
MD_S_ERROR, /* MD data is flawed, unable to be processed as is */
|
||||||
|
MD_S_MISSING, /* MD is missing config information, cannot proceed */
|
||||||
} md_state_t;
|
} md_state_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -70,7 +73,9 @@ struct md_t {
|
|||||||
|
|
||||||
int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */
|
int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */
|
||||||
int drive_mode; /* mode of obtaining credentials */
|
int drive_mode; /* mode of obtaining credentials */
|
||||||
|
struct md_pkey_spec_t *pkey_spec;/* specification for generating new private keys */
|
||||||
int must_staple; /* certificates should set the OCSP Must Staple extension */
|
int must_staple; /* certificates should set the OCSP Must Staple extension */
|
||||||
|
apr_interval_time_t renew_norm; /* if > 0, normalized cert lifetime */
|
||||||
apr_interval_time_t renew_window;/* time before expiration that starts renewal */
|
apr_interval_time_t renew_window;/* time before expiration that starts renewal */
|
||||||
|
|
||||||
const char *ca_url; /* url of CA certificate service */
|
const char *ca_url; /* url of CA certificate service */
|
||||||
@@ -91,6 +96,7 @@ struct md_t {
|
|||||||
|
|
||||||
#define MD_KEY_ACCOUNT "account"
|
#define MD_KEY_ACCOUNT "account"
|
||||||
#define MD_KEY_AGREEMENT "agreement"
|
#define MD_KEY_AGREEMENT "agreement"
|
||||||
|
#define MD_KEY_BITS "bits"
|
||||||
#define MD_KEY_CA "ca"
|
#define MD_KEY_CA "ca"
|
||||||
#define MD_KEY_CA_URL "ca-url"
|
#define MD_KEY_CA_URL "ca-url"
|
||||||
#define MD_KEY_CERT "cert"
|
#define MD_KEY_CERT "cert"
|
||||||
@@ -112,8 +118,10 @@ struct md_t {
|
|||||||
#define MD_KEY_KEYAUTHZ "keyAuthorization"
|
#define MD_KEY_KEYAUTHZ "keyAuthorization"
|
||||||
#define MD_KEY_LOCATION "location"
|
#define MD_KEY_LOCATION "location"
|
||||||
#define MD_KEY_NAME "name"
|
#define MD_KEY_NAME "name"
|
||||||
|
#define MD_KEY_PKEY "privkey"
|
||||||
#define MD_KEY_PROTO "proto"
|
#define MD_KEY_PROTO "proto"
|
||||||
#define MD_KEY_REGISTRATION "registration"
|
#define MD_KEY_REGISTRATION "registration"
|
||||||
|
#define MD_KEY_RENEW_NORM "renew-norm"
|
||||||
#define MD_KEY_RENEW_WINDOW "renew-window"
|
#define MD_KEY_RENEW_WINDOW "renew-window"
|
||||||
#define MD_KEY_RESOURCE "resource"
|
#define MD_KEY_RESOURCE "resource"
|
||||||
#define MD_KEY_STATE "state"
|
#define MD_KEY_STATE "state"
|
||||||
@@ -129,7 +137,8 @@ struct md_t {
|
|||||||
#define MD_KEY_VERSION "version"
|
#define MD_KEY_VERSION "version"
|
||||||
|
|
||||||
#define MD_FN_MD "md.json"
|
#define MD_FN_MD "md.json"
|
||||||
#define MD_FN_PKEY "pkey.pem"
|
#define MD_FN_PRIVKEY "privkey.pem"
|
||||||
|
#define MD_FN_PUBCERT "pubcert.pem"
|
||||||
#define MD_FN_CERT "cert.pem"
|
#define MD_FN_CERT "cert.pem"
|
||||||
#define MD_FN_CHAIN "chain.pem"
|
#define MD_FN_CHAIN "chain.pem"
|
||||||
#define MD_FN_HTTPD_JSON "httpd.json"
|
#define MD_FN_HTTPD_JSON "httpd.json"
|
||||||
@@ -230,9 +239,9 @@ md_t *md_from_json(struct md_json_t *json, apr_pool_t *p);
|
|||||||
|
|
||||||
typedef struct md_creds_t md_creds_t;
|
typedef struct md_creds_t md_creds_t;
|
||||||
struct md_creds_t {
|
struct md_creds_t {
|
||||||
|
struct md_pkey_t *privkey;
|
||||||
|
struct apr_array_header_t *pubcert; /* complete md_cert* chain */
|
||||||
struct md_cert_t *cert;
|
struct md_cert_t *cert;
|
||||||
struct md_pkey_t *pkey;
|
|
||||||
struct apr_array_header_t *chain; /* list of md_cert* */
|
|
||||||
int expired;
|
int expired;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -111,9 +111,8 @@ apr_status_t md_acme_create(md_acme_t **pacme, apr_pool_t *p, const char *url)
|
|||||||
acme = apr_pcalloc(p, sizeof(*acme));
|
acme = apr_pcalloc(p, sizeof(*acme));
|
||||||
acme->url = url;
|
acme->url = url;
|
||||||
acme->p = p;
|
acme->p = p;
|
||||||
acme->user_agent = apr_psprintf(p, "%s mod_md/%s (Something, like certbot)",
|
acme->user_agent = apr_psprintf(p, "%s mod_md/%s",
|
||||||
base_product, MOD_MD_VERSION);
|
base_product, MOD_MD_VERSION);
|
||||||
acme->pkey_bits = 4096;
|
|
||||||
acme->max_retries = 3;
|
acme->max_retries = 3;
|
||||||
|
|
||||||
if (APR_SUCCESS != (rv = apr_uri_parse(p, url, &uri_parsed))) {
|
if (APR_SUCCESS != (rv = apr_uri_parse(p, url, &uri_parsed))) {
|
||||||
@@ -261,8 +260,14 @@ static apr_status_t inspect_problem(md_acme_req_t *req, const md_http_response_t
|
|||||||
pdetail = md_json_gets(problem, "detail", NULL);
|
pdetail = md_json_gets(problem, "detail", NULL);
|
||||||
req->rv = problem_status_get(ptype);
|
req->rv = problem_status_get(ptype);
|
||||||
|
|
||||||
|
if (APR_STATUS_IS_EAGAIN(req->rv)) {
|
||||||
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, req->rv, req->p,
|
||||||
|
"acme reports %s: %s", ptype, pdetail);
|
||||||
|
}
|
||||||
|
else {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, req->rv, req->p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, req->rv, req->p,
|
||||||
"acme problem %s: %s", ptype, pdetail);
|
"acme problem %s: %s", ptype, pdetail);
|
||||||
|
}
|
||||||
return req->rv;
|
return req->rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,7 +62,6 @@ struct md_acme_t {
|
|||||||
|
|
||||||
const char *nonce;
|
const char *nonce;
|
||||||
int max_retries;
|
int max_retries;
|
||||||
unsigned int pkey_bits;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,8 +125,12 @@ apr_status_t md_acme_agree(md_acme_t *acme, apr_pool_t *p, const char *tos);
|
|||||||
* accounces the Tos URL it wants. If this is equal to the agreement specified,
|
* accounces the Tos URL it wants. If this is equal to the agreement specified,
|
||||||
* the server is notified of this. If the server requires a ToS that the account
|
* the server is notified of this. If the server requires a ToS that the account
|
||||||
* thinks it has already given, it is resend.
|
* thinks it has already given, it is resend.
|
||||||
|
*
|
||||||
|
* If an agreement is required, different from the current one, APR_INCOMPLETE is
|
||||||
|
* returned and the agreement url is returned in the parameter.
|
||||||
*/
|
*/
|
||||||
apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, const char *agreement);
|
apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p,
|
||||||
|
const char *agreement, const char **prequired);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ToS agreement for current account.
|
* Get the ToS agreement for current account.
|
||||||
|
@@ -327,6 +327,7 @@ static apr_status_t acct_register(md_acme_t *acme, apr_pool_t *p,
|
|||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
md_pkey_t *pkey;
|
md_pkey_t *pkey;
|
||||||
const char *err = NULL, *uri;
|
const char *err = NULL, *uri;
|
||||||
|
md_pkey_spec_t spec;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "create new account");
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "create new account");
|
||||||
@@ -347,7 +348,10 @@ static apr_status_t acct_register(md_acme_t *acme, apr_pool_t *p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (APR_SUCCESS == (rv = md_pkey_gen_rsa(&pkey, acme->p, acme->pkey_bits))
|
spec.type = MD_PKEY_TYPE_RSA;
|
||||||
|
spec.params.rsa.bits = MD_ACME_ACCT_PKEY_BITS;
|
||||||
|
|
||||||
|
if (APR_SUCCESS == (rv = md_pkey_gen(&pkey, acme->p, &spec))
|
||||||
&& APR_SUCCESS == (rv = acct_make(&acme->acct, p, acme->url, NULL, contacts))) {
|
&& APR_SUCCESS == (rv = acct_make(&acme->acct, p, acme->url, NULL, contacts))) {
|
||||||
acct_ctx_t ctx;
|
acct_ctx_t ctx;
|
||||||
|
|
||||||
@@ -614,11 +618,13 @@ static int agreement_required(md_acme_acct_t *acct)
|
|||||||
|| (acct->tos_required && strcmp(acct->tos_required, acct->agreement)));
|
|| (acct->tos_required && strcmp(acct->tos_required, acct->agreement)));
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, const char *agreement)
|
apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p,
|
||||||
|
const char *agreement, const char **prequired)
|
||||||
{
|
{
|
||||||
apr_status_t rv = APR_SUCCESS;
|
apr_status_t rv = APR_SUCCESS;
|
||||||
|
|
||||||
/* Check if (correct) Terms-of-Service for account were accepted */
|
/* Check if (correct) Terms-of-Service for account were accepted */
|
||||||
|
*prequired = NULL;
|
||||||
if (agreement_required(acme->acct)) {
|
if (agreement_required(acme->acct)) {
|
||||||
const char *tos = acme->acct->tos_required;
|
const char *tos = acme->acct->tos_required;
|
||||||
if (!tos) {
|
if (!tos) {
|
||||||
@@ -642,10 +648,8 @@ apr_status_t md_acme_check_agreement(md_acme_t *acme, apr_pool_t *p, const char
|
|||||||
rv = md_acme_agree(acme, p, tos);
|
rv = md_acme_agree(acme, p, tos);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, acme->p,
|
*prequired = apr_pstrdup(p, tos);
|
||||||
"need to accept terms-of-service <%s> for account %s",
|
rv = APR_INCOMPLETE;
|
||||||
tos, acme->acct->id);
|
|
||||||
rv = APR_EACCES;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
|
@@ -41,4 +41,8 @@ struct md_acme_acct_t {
|
|||||||
#define MD_FN_ACCOUNT "account.json"
|
#define MD_FN_ACCOUNT "account.json"
|
||||||
#define MD_FN_ACCT_KEY "account.pem"
|
#define MD_FN_ACCT_KEY "account.pem"
|
||||||
|
|
||||||
|
/* ACME account private keys are always RSA and have that many bits. Since accounts
|
||||||
|
* are expected to live long, better err on the safe side. */
|
||||||
|
#define MD_ACME_ACCT_PKEY_BITS 3072
|
||||||
|
|
||||||
#endif /* md_acme_acct_h */
|
#endif /* md_acme_acct_h */
|
||||||
|
@@ -94,7 +94,7 @@ apr_status_t md_acme_authz_set_remove(md_acme_authz_set_t *set, const char *doma
|
|||||||
int n = i + 1;
|
int n = i + 1;
|
||||||
if (n < set->authzs->nelts) {
|
if (n < set->authzs->nelts) {
|
||||||
void **elems = (void **)set->authzs->elts;
|
void **elems = (void **)set->authzs->elts;
|
||||||
memmove(elems + i, elems + n, set->authzs->nelts - n);
|
memmove(elems + i, elems + n, (size_t)(set->authzs->nelts - n));
|
||||||
}
|
}
|
||||||
--set->authzs->nelts;
|
--set->authzs->nelts;
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
@@ -292,7 +292,8 @@ static apr_status_t setup_key_authz(md_acme_authz_cha_t *cha, md_acme_authz_t *a
|
|||||||
}
|
}
|
||||||
|
|
||||||
static apr_status_t cha_http_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *authz,
|
static apr_status_t cha_http_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *authz,
|
||||||
md_acme_t *acme, md_store_t *store, apr_pool_t *p)
|
md_acme_t *acme, md_store_t *store,
|
||||||
|
md_pkey_spec_t *key_spec, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
const char *data;
|
const char *data;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
@@ -347,7 +348,8 @@ static apr_status_t setup_cha_dns(const char **pdns, md_acme_authz_cha_t *cha, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
static apr_status_t cha_tls_sni_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *authz,
|
static apr_status_t cha_tls_sni_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t *authz,
|
||||||
md_acme_t *acme, md_store_t *store, apr_pool_t *p)
|
md_acme_t *acme, md_store_t *store,
|
||||||
|
md_pkey_spec_t *key_spec, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
md_cert_t *cha_cert;
|
md_cert_t *cha_cert;
|
||||||
md_pkey_t *cha_key;
|
md_pkey_t *cha_key;
|
||||||
@@ -365,7 +367,7 @@ static apr_status_t cha_tls_sni_01_setup(md_acme_authz_cha_t *cha, md_acme_authz
|
|||||||
if ((APR_SUCCESS == rv && !md_cert_covers_domain(cha_cert, cha_dns))
|
if ((APR_SUCCESS == rv && !md_cert_covers_domain(cha_cert, cha_dns))
|
||||||
|| APR_STATUS_IS_ENOENT(rv)) {
|
|| APR_STATUS_IS_ENOENT(rv)) {
|
||||||
|
|
||||||
if (APR_SUCCESS != (rv = md_pkey_gen_rsa(&cha_key, p, acme->pkey_bits))) {
|
if (APR_SUCCESS != (rv = md_pkey_gen(&cha_key, p, key_spec))) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: create tls-sni-01 challgenge key",
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: create tls-sni-01 challgenge key",
|
||||||
authz->domain);
|
authz->domain);
|
||||||
goto out;
|
goto out;
|
||||||
@@ -405,7 +407,8 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef apr_status_t cha_starter(md_acme_authz_cha_t *cha, md_acme_authz_t *authz,
|
typedef apr_status_t cha_starter(md_acme_authz_cha_t *cha, md_acme_authz_t *authz,
|
||||||
md_acme_t *acme, md_store_t *store, apr_pool_t *p);
|
md_acme_t *acme, md_store_t *store,
|
||||||
|
md_pkey_spec_t *key_spec, apr_pool_t *p);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -449,7 +452,8 @@ static apr_status_t find_type(void *baton, size_t index, md_json_t *json)
|
|||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_store_t *store,
|
apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_store_t *store,
|
||||||
apr_array_header_t *challenges, apr_pool_t *p)
|
apr_array_header_t *challenges,
|
||||||
|
md_pkey_spec_t *key_spec, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
int i;
|
int i;
|
||||||
@@ -485,7 +489,7 @@ apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, md_acme_t *acme, md_s
|
|||||||
|
|
||||||
for (i = 0; i < CHA_TYPES_LEN; ++i) {
|
for (i = 0; i < CHA_TYPES_LEN; ++i) {
|
||||||
if (!apr_strnatcasecmp(CHA_TYPES[i].name, fctx.accepted->type)) {
|
if (!apr_strnatcasecmp(CHA_TYPES[i].name, fctx.accepted->type)) {
|
||||||
return CHA_TYPES[i].start(fctx.accepted, authz, acme, store, p);
|
return CHA_TYPES[i].start(fctx.accepted, authz, acme, store, key_spec, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +564,7 @@ md_acme_authz_t *md_acme_authz_from_json(struct md_json_t *json, apr_pool_t *p)
|
|||||||
authz->domain = md_json_dups(p, json, MD_KEY_DOMAIN, NULL);
|
authz->domain = md_json_dups(p, json, MD_KEY_DOMAIN, NULL);
|
||||||
authz->location = md_json_dups(p, json, MD_KEY_LOCATION, NULL);
|
authz->location = md_json_dups(p, json, MD_KEY_LOCATION, NULL);
|
||||||
authz->dir = md_json_dups(p, json, MD_KEY_DIR, NULL);
|
authz->dir = md_json_dups(p, json, MD_KEY_DIR, NULL);
|
||||||
authz->state = (int)md_json_getl(json, MD_KEY_STATE, NULL);
|
authz->state = (md_acme_authz_state_t)md_json_getl(json, MD_KEY_STATE, NULL);
|
||||||
return authz;
|
return authz;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -631,7 +635,7 @@ static apr_status_t p_save(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_lis
|
|||||||
const char *md_name;
|
const char *md_name;
|
||||||
int create;
|
int create;
|
||||||
|
|
||||||
group = va_arg(ap, int);
|
group = (md_store_group_t)va_arg(ap, int);
|
||||||
md_name = va_arg(ap, const char *);
|
md_name = va_arg(ap, const char *);
|
||||||
set = va_arg(ap, md_acme_authz_set_t *);
|
set = va_arg(ap, md_acme_authz_set_t *);
|
||||||
create = va_arg(ap, int);
|
create = va_arg(ap, int);
|
||||||
@@ -657,7 +661,7 @@ static apr_status_t p_purge(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_li
|
|||||||
const char *md_name;
|
const char *md_name;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
group = va_arg(ap, int);
|
group = (md_store_group_t)va_arg(ap, int);
|
||||||
md_name = va_arg(ap, const char *);
|
md_name = va_arg(ap, const char *);
|
||||||
|
|
||||||
if (APR_SUCCESS == md_acme_authz_set_load(store, group, md_name, &authz_set, p)) {
|
if (APR_SUCCESS == md_acme_authz_set_load(store, group, md_name, &authz_set, p)) {
|
||||||
|
@@ -21,6 +21,7 @@ struct md_acme_t;
|
|||||||
struct md_acme_acct_t;
|
struct md_acme_acct_t;
|
||||||
struct md_json_t;
|
struct md_json_t;
|
||||||
struct md_store_t;
|
struct md_store_t;
|
||||||
|
struct md_pkey_spec_t;
|
||||||
|
|
||||||
typedef struct md_acme_challenge_t md_acme_challenge_t;
|
typedef struct md_acme_challenge_t md_acme_challenge_t;
|
||||||
|
|
||||||
@@ -67,8 +68,8 @@ apr_status_t md_acme_authz_update(md_acme_authz_t *authz, struct md_acme_t *acme
|
|||||||
struct md_store_t *store, apr_pool_t *p);
|
struct md_store_t *store, apr_pool_t *p);
|
||||||
|
|
||||||
apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, struct md_acme_t *acme,
|
apr_status_t md_acme_authz_respond(md_acme_authz_t *authz, struct md_acme_t *acme,
|
||||||
struct md_store_t *store,
|
struct md_store_t *store, apr_array_header_t *challenges,
|
||||||
apr_array_header_t *challenges, apr_pool_t *p);
|
struct md_pkey_spec_t *key_spec, apr_pool_t *p);
|
||||||
apr_status_t md_acme_authz_del(md_acme_authz_t *authz, struct md_acme_t *acme,
|
apr_status_t md_acme_authz_del(md_acme_authz_t *authz, struct md_acme_t *acme,
|
||||||
struct md_store_t *store, apr_pool_t *p);
|
struct md_store_t *store, apr_pool_t *p);
|
||||||
|
|
||||||
|
@@ -42,9 +42,11 @@ typedef struct {
|
|||||||
const char *phase;
|
const char *phase;
|
||||||
int complete;
|
int complete;
|
||||||
|
|
||||||
md_pkey_t *pkey;
|
md_pkey_t *privkey; /* the new private key */
|
||||||
md_cert_t *cert;
|
apr_array_header_t *pubcert; /* the new certificate + chain certs */
|
||||||
apr_array_header_t *chain;
|
|
||||||
|
md_cert_t *cert; /* the new certificate */
|
||||||
|
apr_array_header_t *chain; /* the chain certificates */
|
||||||
|
|
||||||
md_acme_t *acme;
|
md_acme_t *acme;
|
||||||
md_t *md;
|
md_t *md;
|
||||||
@@ -122,8 +124,8 @@ static apr_status_t ad_set_acct(md_proto_driver_t *d)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (APR_SUCCESS == (rv = md_acme_create_acct(ad->acme, d->p,
|
if (APR_SUCCESS == (rv = md_acme_create_acct(ad->acme, d->p, md->contacts,
|
||||||
md->contacts, md->ca_agreement))
|
md->ca_agreement))
|
||||||
&& APR_SUCCESS == (rv = md_acme_acct_save_staged(ad->acme, d->store, md, d->p))) {
|
&& APR_SUCCESS == (rv = md_acme_acct_save_staged(ad->acme, d->store, md, d->p))) {
|
||||||
md->ca_account = MD_ACME_ACCT_STAGED;
|
md->ca_account = MD_ACME_ACCT_STAGED;
|
||||||
update = 1;
|
update = 1;
|
||||||
@@ -267,11 +269,13 @@ static apr_status_t ad_start_challenges(md_proto_driver_t *d)
|
|||||||
switch (authz->state) {
|
switch (authz->state) {
|
||||||
case MD_ACME_AUTHZ_S_VALID:
|
case MD_ACME_AUTHZ_S_VALID:
|
||||||
break;
|
break;
|
||||||
case MD_ACME_AUTHZ_S_PENDING:
|
|
||||||
|
|
||||||
rv = md_acme_authz_respond(authz, ad->acme, d->store, ad->ca_challenges, d->p);
|
case MD_ACME_AUTHZ_S_PENDING:
|
||||||
|
rv = md_acme_authz_respond(authz, ad->acme, d->store, ad->ca_challenges,
|
||||||
|
d->md->pkey_spec, d->p);
|
||||||
changed = 1;
|
changed = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
rv = APR_EINVAL;
|
rv = APR_EINVAL;
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p,
|
||||||
@@ -464,22 +468,22 @@ static apr_status_t csr_req(md_acme_t *acme, const md_http_response_t *res, void
|
|||||||
static apr_status_t ad_setup_certificate(md_proto_driver_t *d)
|
static apr_status_t ad_setup_certificate(md_proto_driver_t *d)
|
||||||
{
|
{
|
||||||
md_acme_driver_t *ad = d->baton;
|
md_acme_driver_t *ad = d->baton;
|
||||||
md_pkey_t *pkey;
|
md_pkey_t *privkey;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
|
|
||||||
ad->phase = "setup cert pkey";
|
ad->phase = "setup cert privkey";
|
||||||
|
|
||||||
rv = md_pkey_load(d->store, MD_SG_STAGING, ad->md->name, &pkey, d->p);
|
rv = md_pkey_load(d->store, MD_SG_STAGING, ad->md->name, &privkey, d->p);
|
||||||
if (APR_STATUS_IS_ENOENT(rv)) {
|
if (APR_STATUS_IS_ENOENT(rv)) {
|
||||||
if (APR_SUCCESS == (rv = md_pkey_gen_rsa(&pkey, d->p, ad->acme->pkey_bits))) {
|
if (APR_SUCCESS == (rv = md_pkey_gen(&privkey, d->p, d->md->pkey_spec))) {
|
||||||
rv = md_pkey_save(d->store, d->p, MD_SG_STAGING, ad->md->name, pkey, 1);
|
rv = md_pkey_save(d->store, d->p, MD_SG_STAGING, ad->md->name, privkey, 1);
|
||||||
}
|
}
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: generate pkey", ad->md->name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: generate privkey", ad->md->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (APR_SUCCESS == rv) {
|
if (APR_SUCCESS == rv) {
|
||||||
ad->phase = "setup csr";
|
ad->phase = "setup csr";
|
||||||
rv = md_cert_req_create(&ad->csr_der_64, ad->md, pkey, d->p);
|
rv = md_cert_req_create(&ad->csr_der_64, ad->md, privkey, d->p);
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: create CSR", ad->md->name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, d->p, "%s: create CSR", ad->md->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,6 +678,12 @@ static apr_status_t acme_stage(md_proto_driver_t *d)
|
|||||||
ad->md = NULL;
|
ad->md = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ad->md && ad->md->state == MD_S_MISSING) {
|
||||||
|
/* There is config information missing. It makes no sense to drive this MD further */
|
||||||
|
rv = APR_INCOMPLETE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (ad->md) {
|
if (ad->md) {
|
||||||
/* staging in progress. look for new ACME account information collected there */
|
/* staging in progress. look for new ACME account information collected there */
|
||||||
rv = md_reg_creds_get(&ad->ncreds, d->reg, MD_SG_STAGING, d->md, d->p);
|
rv = md_reg_creds_get(&ad->ncreds, d->reg, MD_SG_STAGING, d->md, d->p);
|
||||||
@@ -684,7 +694,7 @@ static apr_status_t acme_stage(md_proto_driver_t *d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Find out where we're at with this managed domain */
|
/* Find out where we're at with this managed domain */
|
||||||
if (ad->ncreds && ad->ncreds->pkey && ad->ncreds->cert && ad->ncreds->chain) {
|
if (ad->ncreds && ad->ncreds->privkey && ad->ncreds->pubcert) {
|
||||||
/* There is a full set staged, to be loaded */
|
/* There is a full set staged, to be loaded */
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p, "%s: all data staged", d->md->name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p, "%s: all data staged", d->md->name);
|
||||||
renew = 0;
|
renew = 0;
|
||||||
@@ -724,11 +734,32 @@ static apr_status_t acme_stage(md_proto_driver_t *d)
|
|||||||
* requests for new authorizations are denied. ToS may change during the
|
* requests for new authorizations are denied. ToS may change during the
|
||||||
* lifetime of an account */
|
* lifetime of an account */
|
||||||
if (APR_SUCCESS == rv) {
|
if (APR_SUCCESS == rv) {
|
||||||
|
const char *required;
|
||||||
|
|
||||||
ad->phase = "check agreement";
|
ad->phase = "check agreement";
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p,
|
||||||
"%s: check Terms-of-Service agreement", d->md->name);
|
"%s: check Terms-of-Service agreement", d->md->name);
|
||||||
|
|
||||||
rv = md_acme_check_agreement(ad->acme, d->p, ad->md->ca_agreement);
|
rv = md_acme_check_agreement(ad->acme, d->p, ad->md->ca_agreement, &required);
|
||||||
|
|
||||||
|
if (APR_STATUS_IS_INCOMPLETE(rv) && required) {
|
||||||
|
/* The CA wants the user to agree to Terms-of-Services. Until the user
|
||||||
|
* has reconfigured and restarted the server, this MD cannot be
|
||||||
|
* driven further */
|
||||||
|
ad->md->state = MD_S_MISSING;
|
||||||
|
md_save(d->store, d->p, MD_SG_STAGING, ad->md, 0);
|
||||||
|
|
||||||
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, d->p,
|
||||||
|
"%s: the CA requires you to accept the terms-of-service "
|
||||||
|
"as specified in <%s>. "
|
||||||
|
"Please read the document that you find at that URL and, "
|
||||||
|
"if you agree to the conditions, configure "
|
||||||
|
"\"MDCertificateAgreement url\" "
|
||||||
|
"with exactly that URL in your Apache. "
|
||||||
|
"Then (graceful) restart the server to activate.",
|
||||||
|
ad->md->name, required);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we know a cert's location, try to get it. Previous download might
|
/* If we know a cert's location, try to get it. Previous download might
|
||||||
@@ -779,6 +810,10 @@ static apr_status_t acme_stage(md_proto_driver_t *d)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (APR_SUCCESS == rv && !ad->chain) {
|
||||||
|
/* have we created this already? */
|
||||||
|
md_chain_load(d->store, MD_SG_STAGING, ad->md->name, &ad->chain, d->p);
|
||||||
|
}
|
||||||
if (APR_SUCCESS == rv && !ad->chain) {
|
if (APR_SUCCESS == rv && !ad->chain) {
|
||||||
ad->phase = "install chain";
|
ad->phase = "install chain";
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, 0, d->p,
|
||||||
@@ -786,6 +821,18 @@ static apr_status_t acme_stage(md_proto_driver_t *d)
|
|||||||
rv = ad_chain_install(d);
|
rv = ad_chain_install(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (APR_SUCCESS == rv && !ad->pubcert) {
|
||||||
|
/* have we created this already? */
|
||||||
|
md_pubcert_load(d->store, MD_SG_STAGING, ad->md->name, &ad->pubcert, d->p);
|
||||||
|
}
|
||||||
|
if (APR_SUCCESS == rv && !ad->pubcert) {
|
||||||
|
/* combine cert + chain into the pubcert */
|
||||||
|
ad->pubcert = apr_array_make(d->p, ad->chain->nelts + 1, sizeof(md_cert_t*));
|
||||||
|
APR_ARRAY_PUSH(ad->pubcert, md_cert_t *) = ad->cert;
|
||||||
|
apr_array_cat(ad->pubcert, ad->chain);
|
||||||
|
rv = md_pubcert_save(d->store, d->p, MD_SG_STAGING, ad->md->name, ad->pubcert, 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (APR_SUCCESS == rv && ad->cert) {
|
if (APR_SUCCESS == rv && ad->cert) {
|
||||||
apr_time_t now = apr_time_now();
|
apr_time_t now = apr_time_now();
|
||||||
apr_interval_time_t max_delay, delay_activation;
|
apr_interval_time_t max_delay, delay_activation;
|
||||||
@@ -832,10 +879,9 @@ static apr_status_t acme_preload(md_store_t *store, md_store_group_t load_group,
|
|||||||
const char *name, apr_pool_t *p)
|
const char *name, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
md_pkey_t *pkey, *acct_key;
|
md_pkey_t *privkey, *acct_key;
|
||||||
md_t *md;
|
md_t *md;
|
||||||
md_cert_t *cert;
|
apr_array_header_t *pubcert;
|
||||||
apr_array_header_t *chain;
|
|
||||||
struct md_acme_acct_t *acct;
|
struct md_acme_acct_t *acct;
|
||||||
|
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "%s: preload start", name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "%s: preload start", name);
|
||||||
@@ -852,18 +898,14 @@ static apr_status_t acme_preload(md_store_t *store, md_store_group_t load_group,
|
|||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading md json", name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading md json", name);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
if (APR_SUCCESS != (rv = md_cert_load(store, MD_SG_STAGING, name, &cert, p))) {
|
if (APR_SUCCESS != (rv = md_pkey_load(store, MD_SG_STAGING, name, &privkey, p))) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading certificate", name);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (APR_SUCCESS != (rv = md_chain_load(store, MD_SG_STAGING, name, &chain, p))) {
|
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading cert chain", name);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (APR_SUCCESS != (rv = md_pkey_load(store, MD_SG_STAGING, name, &pkey, p))) {
|
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading staging private key", name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading staging private key", name);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
if (APR_SUCCESS != (rv = md_pubcert_load(store, MD_SG_STAGING, name, &pubcert, p))) {
|
||||||
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p, "%s: loading pubcert", name);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
/* See if staging holds a new or modified account data */
|
/* See if staging holds a new or modified account data */
|
||||||
rv = md_acme_acct_load(&acct, &acct_key, store, MD_SG_STAGING, name, p);
|
rv = md_acme_acct_load(&acct, &acct_key, store, MD_SG_STAGING, name, p);
|
||||||
@@ -904,16 +946,12 @@ static apr_status_t acme_preload(md_store_t *store, md_store_group_t load_group,
|
|||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving md json", name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving md json", name);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
if (APR_SUCCESS != (rv = md_cert_save(store, p, load_group, name, cert, 1))) {
|
if (APR_SUCCESS != (rv = md_pubcert_save(store, p, load_group, name, pubcert, 1))) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving certificate", name);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (APR_SUCCESS != (rv = md_chain_save(store, p, load_group, name, chain, 1))) {
|
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving cert chain", name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving cert chain", name);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
if (APR_SUCCESS != (rv = md_pkey_save(store, p, load_group, name, pkey, 1))) {
|
if (APR_SUCCESS != (rv = md_pkey_save(store, p, load_group, name, privkey, 1))) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving domain private key", name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: saving private key", name);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -103,7 +103,7 @@ static apr_status_t cmd_reg_list(md_cmd_ctx *ctx, const md_cmd_t *cmd)
|
|||||||
else {
|
else {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE4, 0, ctx->p, "list do");
|
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE4, 0, ctx->p, "list do");
|
||||||
md_reg_do(list_add_md, mdlist, ctx->reg, ctx->p);
|
md_reg_do(list_add_md, mdlist, ctx->reg, ctx->p);
|
||||||
qsort(mdlist->elts, mdlist->nelts, sizeof(md_t *), md_name_cmp);
|
qsort(mdlist->elts, (size_t)mdlist->nelts, sizeof(md_t *), md_name_cmp);
|
||||||
|
|
||||||
for (i = 0; i < mdlist->nelts; ++i) {
|
for (i = 0; i < mdlist->nelts; ++i) {
|
||||||
md = APR_ARRAY_IDX(mdlist, i, const md_t*);
|
md = APR_ARRAY_IDX(mdlist, i, const md_t*);
|
||||||
@@ -317,7 +317,7 @@ static apr_status_t cmd_reg_drive(md_cmd_ctx *ctx, const md_cmd_t *cmd)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
md_reg_do(list_add_md, mdlist, ctx->reg, ctx->p);
|
md_reg_do(list_add_md, mdlist, ctx->reg, ctx->p);
|
||||||
qsort(mdlist->elts, mdlist->nelts, sizeof(md_t *), md_name_cmp);
|
qsort(mdlist->elts, (size_t)mdlist->nelts, sizeof(md_t *), md_name_cmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = APR_SUCCESS;
|
rv = APR_SUCCESS;
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include "md_json.h"
|
#include "md_json.h"
|
||||||
#include "md.h"
|
#include "md.h"
|
||||||
|
#include "md_crypt.h"
|
||||||
#include "md_log.h"
|
#include "md_log.h"
|
||||||
#include "md_store.h"
|
#include "md_store.h"
|
||||||
#include "md_util.h"
|
#include "md_util.h"
|
||||||
@@ -229,6 +230,8 @@ md_t *md_clone(apr_pool_t *p, const md_t *src)
|
|||||||
md->name = apr_pstrdup(p, src->name);
|
md->name = apr_pstrdup(p, src->name);
|
||||||
md->drive_mode = src->drive_mode;
|
md->drive_mode = src->drive_mode;
|
||||||
md->domains = md_array_str_compact(p, src->domains, 0);
|
md->domains = md_array_str_compact(p, src->domains, 0);
|
||||||
|
md->pkey_spec = src->pkey_spec;
|
||||||
|
md->renew_norm = src->renew_norm;
|
||||||
md->renew_window = src->renew_window;
|
md->renew_window = src->renew_window;
|
||||||
md->contacts = md_array_str_clone(p, src->contacts);
|
md->contacts = md_array_str_clone(p, src->contacts);
|
||||||
if (src->ca_url) md->ca_url = apr_pstrdup(p, src->ca_url);
|
if (src->ca_url) md->ca_url = apr_pstrdup(p, src->ca_url);
|
||||||
@@ -253,8 +256,10 @@ md_t *md_merge(apr_pool_t *p, const md_t *add, const md_t *base)
|
|||||||
n->ca_proto = add->ca_proto? add->ca_proto : base->ca_proto;
|
n->ca_proto = add->ca_proto? add->ca_proto : base->ca_proto;
|
||||||
n->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement;
|
n->ca_agreement = add->ca_agreement? add->ca_agreement : base->ca_agreement;
|
||||||
n->drive_mode = (add->drive_mode != MD_DRIVE_DEFAULT)? add->drive_mode : base->drive_mode;
|
n->drive_mode = (add->drive_mode != MD_DRIVE_DEFAULT)? add->drive_mode : base->drive_mode;
|
||||||
n->renew_window = (add->renew_window <= 0)? add->renew_window : base->renew_window;
|
n->pkey_spec = add->pkey_spec? add->pkey_spec : base->pkey_spec;
|
||||||
n->transitive = (add->transitive < 0)? add->transitive : base->transitive;
|
n->renew_norm = (add->renew_norm > 0)? add->renew_norm : base->renew_norm;
|
||||||
|
n->renew_window = (add->renew_window > 0)? add->renew_window : base->renew_window;
|
||||||
|
n->transitive = (add->transitive >= 0)? add->transitive : base->transitive;
|
||||||
if (add->ca_challenges) {
|
if (add->ca_challenges) {
|
||||||
n->ca_challenges = apr_array_copy(p, add->ca_challenges);
|
n->ca_challenges = apr_array_copy(p, add->ca_challenges);
|
||||||
}
|
}
|
||||||
@@ -264,7 +269,6 @@ md_t *md_merge(apr_pool_t *p, const md_t *add, const md_t *base)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************************************/
|
/**************************************************************************************************/
|
||||||
/* format conversion */
|
/* format conversion */
|
||||||
|
|
||||||
@@ -284,6 +288,9 @@ md_json_t *md_to_json(const md_t *md, apr_pool_t *p)
|
|||||||
if (md->cert_url) {
|
if (md->cert_url) {
|
||||||
md_json_sets(md->cert_url, json, MD_KEY_CERT, MD_KEY_URL, NULL);
|
md_json_sets(md->cert_url, json, MD_KEY_CERT, MD_KEY_URL, NULL);
|
||||||
}
|
}
|
||||||
|
if (md->pkey_spec) {
|
||||||
|
md_json_setj(md_pkey_spec_to_json(md->pkey_spec, p), json, MD_KEY_PKEY, NULL);
|
||||||
|
}
|
||||||
md_json_setl(md->state, json, MD_KEY_STATE, NULL);
|
md_json_setl(md->state, json, MD_KEY_STATE, NULL);
|
||||||
md_json_setl(md->drive_mode, json, MD_KEY_DRIVE_MODE, NULL);
|
md_json_setl(md->drive_mode, json, MD_KEY_DRIVE_MODE, NULL);
|
||||||
if (md->expires > 0) {
|
if (md->expires > 0) {
|
||||||
@@ -296,7 +303,13 @@ md_json_t *md_to_json(const md_t *md, apr_pool_t *p)
|
|||||||
apr_rfc822_date(ts, md->valid_from);
|
apr_rfc822_date(ts, md->valid_from);
|
||||||
md_json_sets(ts, json, MD_KEY_CERT, MD_KEY_VALID_FROM, NULL);
|
md_json_sets(ts, json, MD_KEY_CERT, MD_KEY_VALID_FROM, NULL);
|
||||||
}
|
}
|
||||||
md_json_setl(apr_time_sec(md->renew_window), json, MD_KEY_RENEW_WINDOW, NULL);
|
if (md->renew_norm > 0) {
|
||||||
|
md_json_setl((long)apr_time_sec(md->renew_norm), json, MD_KEY_RENEW_NORM, NULL);
|
||||||
|
md_json_setl((long)apr_time_sec(md->renew_window), json, MD_KEY_RENEW_WINDOW, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
md_json_setl((long)apr_time_sec(md->renew_window), json, MD_KEY_RENEW_WINDOW, NULL);
|
||||||
|
}
|
||||||
if (md->ca_challenges && md->ca_challenges->nelts > 0) {
|
if (md->ca_challenges && md->ca_challenges->nelts > 0) {
|
||||||
apr_array_header_t *na;
|
apr_array_header_t *na;
|
||||||
na = md_array_str_compact(p, md->ca_challenges, 0);
|
na = md_array_str_compact(p, md->ca_challenges, 0);
|
||||||
@@ -320,7 +333,10 @@ md_t *md_from_json(md_json_t *json, apr_pool_t *p)
|
|||||||
md->ca_url = md_json_dups(p, json, MD_KEY_CA, MD_KEY_URL, NULL);
|
md->ca_url = md_json_dups(p, json, MD_KEY_CA, MD_KEY_URL, NULL);
|
||||||
md->ca_agreement = md_json_dups(p, json, MD_KEY_CA, MD_KEY_AGREEMENT, NULL);
|
md->ca_agreement = md_json_dups(p, json, MD_KEY_CA, MD_KEY_AGREEMENT, NULL);
|
||||||
md->cert_url = md_json_dups(p, json, MD_KEY_CERT, MD_KEY_URL, NULL);
|
md->cert_url = md_json_dups(p, json, MD_KEY_CERT, MD_KEY_URL, NULL);
|
||||||
md->state = (int)md_json_getl(json, MD_KEY_STATE, NULL);
|
if (md_json_has_key(json, MD_KEY_PKEY, MD_KEY_TYPE, NULL)) {
|
||||||
|
md->pkey_spec = md_pkey_spec_from_json(md_json_getj(json, MD_KEY_PKEY, NULL), p);
|
||||||
|
}
|
||||||
|
md->state = (md_state_t)md_json_getl(json, MD_KEY_STATE, NULL);
|
||||||
md->drive_mode = (int)md_json_getl(json, MD_KEY_DRIVE_MODE, NULL);
|
md->drive_mode = (int)md_json_getl(json, MD_KEY_DRIVE_MODE, NULL);
|
||||||
md->domains = md_array_str_compact(p, md->domains, 0);
|
md->domains = md_array_str_compact(p, md->domains, 0);
|
||||||
md->transitive = (int)md_json_getl(json, MD_KEY_TRANSITIVE, NULL);
|
md->transitive = (int)md_json_getl(json, MD_KEY_TRANSITIVE, NULL);
|
||||||
@@ -332,6 +348,7 @@ md_t *md_from_json(md_json_t *json, apr_pool_t *p)
|
|||||||
if (s && *s) {
|
if (s && *s) {
|
||||||
md->valid_from = apr_date_parse_rfc(s);
|
md->valid_from = apr_date_parse_rfc(s);
|
||||||
}
|
}
|
||||||
|
md->renew_norm = apr_time_from_sec(md_json_getl(json, MD_KEY_RENEW_NORM, NULL));
|
||||||
md->renew_window = apr_time_from_sec(md_json_getl(json, MD_KEY_RENEW_WINDOW, NULL));
|
md->renew_window = apr_time_from_sec(md_json_getl(json, MD_KEY_RENEW_WINDOW, NULL));
|
||||||
if (md_json_has_key(json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL)) {
|
if (md_json_has_key(json, MD_KEY_CA, MD_KEY_CHALLENGES, NULL)) {
|
||||||
md->ca_challenges = apr_array_make(p, 5, sizeof(const char*));
|
md->ca_challenges = apr_array_make(p, 5, sizeof(const char*));
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "md.h"
|
#include "md.h"
|
||||||
#include "md_crypt.h"
|
#include "md_crypt.h"
|
||||||
|
#include "md_json.h"
|
||||||
#include "md_log.h"
|
#include "md_log.h"
|
||||||
#include "md_http.h"
|
#include "md_http.h"
|
||||||
#include "md_util.h"
|
#include "md_util.h"
|
||||||
@@ -83,7 +84,7 @@ static void seed_RAND(int pid)
|
|||||||
{
|
{
|
||||||
unsigned char stackdata[256];
|
unsigned char stackdata[256];
|
||||||
/* stolen from mod_ssl/ssl_engine_rand.c */
|
/* stolen from mod_ssl/ssl_engine_rand.c */
|
||||||
apr_size_t n, l;
|
int n;
|
||||||
struct {
|
struct {
|
||||||
time_t t;
|
time_t t;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@@ -99,8 +100,7 @@ static void seed_RAND(int pid)
|
|||||||
*/
|
*/
|
||||||
my_seed.pid = pid;
|
my_seed.pid = pid;
|
||||||
|
|
||||||
l = sizeof(my_seed);
|
RAND_seed((unsigned char *)&my_seed, sizeof(my_seed));
|
||||||
RAND_seed((unsigned char *)&my_seed, l);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* seed in some current state of the run-time stack (128 bytes)
|
* seed in some current state of the run-time stack (128 bytes)
|
||||||
@@ -173,7 +173,7 @@ static int pem_passwd(char *buf, int size, int rwflag, void *baton)
|
|||||||
if (ctx->pass_len < size) {
|
if (ctx->pass_len < size) {
|
||||||
size = (int)ctx->pass_len;
|
size = (int)ctx->pass_len;
|
||||||
}
|
}
|
||||||
memcpy(buf, ctx->pass_phrase, size);
|
memcpy(buf, ctx->pass_phrase, (size_t)size);
|
||||||
}
|
}
|
||||||
return ctx->pass_len;
|
return ctx->pass_len;
|
||||||
}
|
}
|
||||||
@@ -181,6 +181,50 @@ static int pem_passwd(char *buf, int size, int rwflag, void *baton)
|
|||||||
/**************************************************************************************************/
|
/**************************************************************************************************/
|
||||||
/* private keys */
|
/* private keys */
|
||||||
|
|
||||||
|
md_json_t *md_pkey_spec_to_json(const md_pkey_spec_t *spec, apr_pool_t *p)
|
||||||
|
{
|
||||||
|
md_json_t *json = md_json_create(p);
|
||||||
|
if (json) {
|
||||||
|
switch (spec->type) {
|
||||||
|
case MD_PKEY_TYPE_DEFAULT:
|
||||||
|
md_json_sets("Default", json, MD_KEY_TYPE, NULL);
|
||||||
|
break;
|
||||||
|
case MD_PKEY_TYPE_RSA:
|
||||||
|
md_json_sets("RSA", json, MD_KEY_TYPE, NULL);
|
||||||
|
if (spec->params.rsa.bits > 2048) {
|
||||||
|
md_json_setl(spec->params.rsa.bits, json, MD_KEY_BITS, NULL);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
md_json_sets("Unsupported", json, MD_KEY_TYPE, NULL);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
md_pkey_spec_t *md_pkey_spec_from_json(struct md_json_t *json, apr_pool_t *p)
|
||||||
|
{
|
||||||
|
md_pkey_spec_t *spec = apr_pcalloc(p, sizeof(*spec));
|
||||||
|
const char *s;
|
||||||
|
long l;
|
||||||
|
|
||||||
|
if (spec) {
|
||||||
|
s = md_json_gets(json, MD_KEY_TYPE, NULL);
|
||||||
|
if (!s || !apr_strnatcasecmp("Default", s)) {
|
||||||
|
spec->type = MD_PKEY_TYPE_DEFAULT;
|
||||||
|
}
|
||||||
|
else if (!apr_strnatcasecmp("RSA", s)) {
|
||||||
|
spec->type = MD_PKEY_TYPE_RSA;
|
||||||
|
l = md_json_getl(json, MD_KEY_BITS, NULL);
|
||||||
|
if (l > 2048) {
|
||||||
|
spec->params.rsa.bits = (unsigned int)l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
|
||||||
static md_pkey_t *make_pkey(apr_pool_t *p)
|
static md_pkey_t *make_pkey(apr_pool_t *p)
|
||||||
{
|
{
|
||||||
md_pkey_t *pkey = apr_pcalloc(p, sizeof(*pkey));
|
md_pkey_t *pkey = apr_pcalloc(p, sizeof(*pkey));
|
||||||
@@ -231,7 +275,7 @@ apr_status_t md_pkey_fload(md_pkey_t **ppkey, apr_pool_t *p,
|
|||||||
apr_pool_cleanup_register(p, pkey, pkey_cleanup, apr_pool_cleanup_null);
|
apr_pool_cleanup_register(p, pkey, pkey_cleanup, apr_pool_cleanup_null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
long err = ERR_get_error();
|
unsigned long err = ERR_get_error();
|
||||||
rv = APR_EINVAL;
|
rv = APR_EINVAL;
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, rv, p,
|
||||||
"error loading pkey %s: %s (pass phrase was %snull)", fname,
|
"error loading pkey %s: %s (pass phrase was %snull)", fname,
|
||||||
@@ -251,6 +295,7 @@ static apr_status_t pkey_to_buffer(buffer *buffer, md_pkey_t *pkey, apr_pool_t *
|
|||||||
void *cb_baton = NULL;
|
void *cb_baton = NULL;
|
||||||
passwd_ctx ctx;
|
passwd_ctx ctx;
|
||||||
unsigned long err;
|
unsigned long err;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
return APR_ENOMEM;
|
return APR_ENOMEM;
|
||||||
@@ -278,11 +323,12 @@ static apr_status_t pkey_to_buffer(buffer *buffer, md_pkey_t *pkey, apr_pool_t *
|
|||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->len = BIO_pending(bio);
|
i = BIO_pending(bio);
|
||||||
if (buffer->len > 0) {
|
if (i > 0) {
|
||||||
buffer->data = apr_palloc(p, buffer->len+1);
|
buffer->data = apr_palloc(p, (apr_size_t)i + 1);
|
||||||
buffer->len = BIO_read(bio, buffer->data, (int)buffer->len);
|
i = BIO_read(bio, buffer->data, i);
|
||||||
buffer->data[buffer->len] = '\0';
|
buffer->data[i] = '\0';
|
||||||
|
buffer->len = (apr_size_t)i;
|
||||||
}
|
}
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
@@ -303,7 +349,7 @@ apr_status_t md_pkey_fsave(md_pkey_t *pkey, apr_pool_t *p,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t md_pkey_gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, int bits)
|
static apr_status_t gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, unsigned int bits)
|
||||||
{
|
{
|
||||||
EVP_PKEY_CTX *ctx = NULL;
|
EVP_PKEY_CTX *ctx = NULL;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
@@ -312,7 +358,7 @@ apr_status_t md_pkey_gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, int bits)
|
|||||||
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
||||||
if (ctx
|
if (ctx
|
||||||
&& EVP_PKEY_keygen_init(ctx) >= 0
|
&& EVP_PKEY_keygen_init(ctx) >= 0
|
||||||
&& EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) >= 0
|
&& EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int)bits) >= 0
|
||||||
&& EVP_PKEY_keygen(ctx, &(*ppkey)->pkey) >= 0) {
|
&& EVP_PKEY_keygen(ctx, &(*ppkey)->pkey) >= 0) {
|
||||||
rv = APR_SUCCESS;
|
rv = APR_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -328,6 +374,19 @@ apr_status_t md_pkey_gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, int bits)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec)
|
||||||
|
{
|
||||||
|
md_pkey_type_t ptype = spec? spec->type : MD_PKEY_TYPE_DEFAULT;
|
||||||
|
switch (ptype) {
|
||||||
|
case MD_PKEY_TYPE_DEFAULT:
|
||||||
|
return gen_rsa(ppkey, p, MD_PKEY_RSA_BITS_DEF);
|
||||||
|
case MD_PKEY_TYPE_RSA:
|
||||||
|
return gen_rsa(ppkey, p, spec->params.rsa.bits);
|
||||||
|
default:
|
||||||
|
return APR_ENOTIMPL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
|
|
||||||
#ifndef NID_tlsfeature
|
#ifndef NID_tlsfeature
|
||||||
@@ -350,7 +409,7 @@ static void RSA_get0_key(const RSA *r,
|
|||||||
static const char *bn64(const BIGNUM *b, apr_pool_t *p)
|
static const char *bn64(const BIGNUM *b, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
if (b) {
|
if (b) {
|
||||||
int len = BN_num_bytes(b);
|
apr_size_t len = (apr_size_t)BN_num_bytes(b);
|
||||||
char *buffer = apr_pcalloc(p, len);
|
char *buffer = apr_pcalloc(p, len);
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
BN_bn2bin(b, (unsigned char *)buffer);
|
BN_bn2bin(b, (unsigned char *)buffer);
|
||||||
@@ -393,7 +452,7 @@ apr_status_t md_crypt_sign64(const char **psign64, md_pkey_t *pkey, apr_pool_t *
|
|||||||
const char *sign64 = NULL;
|
const char *sign64 = NULL;
|
||||||
apr_status_t rv = APR_ENOMEM;
|
apr_status_t rv = APR_ENOMEM;
|
||||||
|
|
||||||
buffer = apr_pcalloc(p, EVP_PKEY_size(pkey->pkey));
|
buffer = apr_pcalloc(p, (apr_size_t)EVP_PKEY_size(pkey->pkey));
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
ctx = EVP_MD_CTX_create();
|
ctx = EVP_MD_CTX_create();
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
@@ -728,6 +787,7 @@ apr_status_t md_cert_fload(md_cert_t **pcert, apr_pool_t *p, const char *fname)
|
|||||||
static apr_status_t cert_to_buffer(buffer *buffer, md_cert_t *cert, apr_pool_t *p)
|
static apr_status_t cert_to_buffer(buffer *buffer, md_cert_t *cert, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
BIO *bio = BIO_new(BIO_s_mem());
|
BIO *bio = BIO_new(BIO_s_mem());
|
||||||
|
int i;
|
||||||
|
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
return APR_ENOMEM;
|
return APR_ENOMEM;
|
||||||
@@ -740,11 +800,12 @@ static apr_status_t cert_to_buffer(buffer *buffer, md_cert_t *cert, apr_pool_t *
|
|||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer->len = BIO_pending(bio);
|
i = BIO_pending(bio);
|
||||||
if (buffer->len > 0) {
|
if (i > 0) {
|
||||||
buffer->data = apr_palloc(p, buffer->len+1);
|
buffer->data = apr_palloc(p, (apr_size_t)i + 1);
|
||||||
buffer->len = BIO_read(bio, buffer->data, (int)buffer->len);
|
i = BIO_read(bio, buffer->data, i);
|
||||||
buffer->data[buffer->len] = '\0';
|
buffer->data[i] = '\0';
|
||||||
|
buffer->len = (apr_size_t)i;
|
||||||
}
|
}
|
||||||
BIO_free(bio);
|
BIO_free(bio);
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
@@ -797,7 +858,7 @@ apr_status_t md_cert_read_http(md_cert_t **pcert, apr_pool_t *p,
|
|||||||
const unsigned char *bf = (const unsigned char*)der;
|
const unsigned char *bf = (const unsigned char*)der;
|
||||||
X509 *x509;
|
X509 *x509;
|
||||||
|
|
||||||
if (NULL == (x509 = d2i_X509(NULL, &bf, der_len))) {
|
if (NULL == (x509 = d2i_X509(NULL, &bf, (long)der_len))) {
|
||||||
rv = APR_EINVAL;
|
rv = APR_EINVAL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -818,19 +879,16 @@ md_cert_state_t md_cert_state_get(md_cert_t *cert)
|
|||||||
return MD_CERT_UNKNOWN;
|
return MD_CERT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const char *fname)
|
apr_status_t md_chain_fappend(struct apr_array_header_t *certs, apr_pool_t *p, const char *fname)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
apr_array_header_t *certs = NULL;
|
|
||||||
X509 *x509;
|
X509 *x509;
|
||||||
md_cert_t *cert;
|
md_cert_t *cert;
|
||||||
unsigned long err;
|
unsigned long err;
|
||||||
|
|
||||||
rv = md_util_fopen(&f, fname, "r");
|
rv = md_util_fopen(&f, fname, "r");
|
||||||
if (rv == APR_SUCCESS) {
|
if (rv == APR_SUCCESS) {
|
||||||
certs = apr_array_make(p, 5, sizeof(md_cert_t *));
|
|
||||||
|
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
while (NULL != (x509 = PEM_read_X509(f, NULL, NULL, NULL))) {
|
while (NULL != (x509 = PEM_read_X509(f, NULL, NULL, NULL))) {
|
||||||
cert = make_cert(p, x509);
|
cert = make_cert(p, x509);
|
||||||
@@ -862,6 +920,16 @@ apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const ch
|
|||||||
out:
|
out:
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, rv, p, "read chain file %s, found %d certs",
|
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE3, rv, p, "read chain file %s, found %d certs",
|
||||||
fname, certs? certs->nelts : 0);
|
fname, certs? certs->nelts : 0);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_status_t md_chain_fload(apr_array_header_t **pcerts, apr_pool_t *p, const char *fname)
|
||||||
|
{
|
||||||
|
apr_array_header_t *certs;
|
||||||
|
apr_status_t rv;
|
||||||
|
|
||||||
|
certs = apr_array_make(p, 5, sizeof(md_cert_t *));
|
||||||
|
rv = md_chain_fappend(certs, p, fname);
|
||||||
*pcerts = (APR_SUCCESS == rv)? certs : NULL;
|
*pcerts = (APR_SUCCESS == rv)? certs : NULL;
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -1027,12 +1095,12 @@ apr_status_t md_cert_req_create(const char **pcsr_der_64, const md_t *md,
|
|||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: der length", md->name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: der length", md->name);
|
||||||
rv = APR_EGENERAL; goto out;
|
rv = APR_EGENERAL; goto out;
|
||||||
}
|
}
|
||||||
s = csr_der = apr_pcalloc(p, csr_der_len + 1);
|
s = csr_der = apr_pcalloc(p, (apr_size_t)csr_der_len + 1);
|
||||||
if (i2d_X509_REQ(csr, (unsigned char**)&s) != csr_der_len) {
|
if (i2d_X509_REQ(csr, (unsigned char**)&s) != csr_der_len) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: csr der enc", md->name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, "%s: csr der enc", md->name);
|
||||||
rv = APR_EGENERAL; goto out;
|
rv = APR_EGENERAL; goto out;
|
||||||
}
|
}
|
||||||
csr_der_64 = md_util_base64url_encode(csr_der, csr_der_len, p);
|
csr_der_64 = md_util_base64url_encode(csr_der, (apr_size_t)csr_der_len, p);
|
||||||
rv = APR_SUCCESS;
|
rv = APR_SUCCESS;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@@ -1104,7 +1172,7 @@ apr_status_t md_cert_self_sign(md_cert_t **pcert, const char *cn,
|
|||||||
rv = APR_EGENERAL; goto out;
|
rv = APR_EGENERAL; goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
days = ((apr_time_sec(valid_for) + MD_SECS_PER_DAY - 1)/ MD_SECS_PER_DAY);
|
days = (int)((apr_time_sec(valid_for) + MD_SECS_PER_DAY - 1)/ MD_SECS_PER_DAY);
|
||||||
if (!X509_set_notBefore(x, ASN1_TIME_set(NULL, time(NULL)))) {
|
if (!X509_set_notBefore(x, ASN1_TIME_set(NULL, time(NULL)))) {
|
||||||
rv = APR_EGENERAL; goto out;
|
rv = APR_EGENERAL; goto out;
|
||||||
}
|
}
|
||||||
|
@@ -41,9 +41,25 @@ apr_status_t md_crypt_sha256_digest_hex(const char **pdigesthex, apr_pool_t *p,
|
|||||||
|
|
||||||
typedef struct md_pkey_t md_pkey_t;
|
typedef struct md_pkey_t md_pkey_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MD_PKEY_TYPE_DEFAULT,
|
||||||
|
MD_PKEY_TYPE_RSA,
|
||||||
|
} md_pkey_type_t;
|
||||||
|
|
||||||
|
typedef struct md_pkey_rsa_spec_t {
|
||||||
|
apr_uint32_t bits;
|
||||||
|
} md_pkey_rsa_spec_t;
|
||||||
|
|
||||||
|
typedef struct md_pkey_spec_t {
|
||||||
|
md_pkey_type_t type;
|
||||||
|
union {
|
||||||
|
md_pkey_rsa_spec_t rsa;
|
||||||
|
} params;
|
||||||
|
} md_pkey_spec_t;
|
||||||
|
|
||||||
apr_status_t md_crypt_init(apr_pool_t *pool);
|
apr_status_t md_crypt_init(apr_pool_t *pool);
|
||||||
|
|
||||||
apr_status_t md_pkey_gen_rsa(md_pkey_t **ppkey, apr_pool_t *p, int bits);
|
apr_status_t md_pkey_gen(md_pkey_t **ppkey, apr_pool_t *p, md_pkey_spec_t *spec);
|
||||||
void md_pkey_free(md_pkey_t *pkey);
|
void md_pkey_free(md_pkey_t *pkey);
|
||||||
|
|
||||||
const char *md_pkey_get_rsa_e64(md_pkey_t *pkey, apr_pool_t *p);
|
const char *md_pkey_get_rsa_e64(md_pkey_t *pkey, apr_pool_t *p);
|
||||||
@@ -62,6 +78,9 @@ apr_status_t md_crypt_sign64(const char **psign64, md_pkey_t *pkey, apr_pool_t *
|
|||||||
void *md_cert_get_X509(struct md_cert_t *cert);
|
void *md_cert_get_X509(struct md_cert_t *cert);
|
||||||
void *md_pkey_get_EVP_PKEY(struct md_pkey_t *pkey);
|
void *md_pkey_get_EVP_PKEY(struct md_pkey_t *pkey);
|
||||||
|
|
||||||
|
struct md_json_t *md_pkey_spec_to_json(const md_pkey_spec_t *spec, apr_pool_t *p);
|
||||||
|
md_pkey_spec_t *md_pkey_spec_from_json(struct md_json_t *json, apr_pool_t *p);
|
||||||
|
|
||||||
/**************************************************************************************************/
|
/**************************************************************************************************/
|
||||||
/* X509 certificates */
|
/* X509 certificates */
|
||||||
|
|
||||||
@@ -100,6 +119,8 @@ apr_status_t md_chain_fload(struct apr_array_header_t **pcerts,
|
|||||||
apr_pool_t *p, const char *fname);
|
apr_pool_t *p, const char *fname);
|
||||||
apr_status_t md_chain_fsave(struct apr_array_header_t *certs,
|
apr_status_t md_chain_fsave(struct apr_array_header_t *certs,
|
||||||
apr_pool_t *p, const char *fname, apr_fileperms_t perms);
|
apr_pool_t *p, const char *fname, apr_fileperms_t perms);
|
||||||
|
apr_status_t md_chain_fappend(struct apr_array_header_t *certs,
|
||||||
|
apr_pool_t *p, const char *fname);
|
||||||
|
|
||||||
apr_status_t md_cert_req_create(const char **pcsr_der_64, const struct md_t *md,
|
apr_status_t md_cert_req_create(const char **pcsr_der_64, const struct md_t *md,
|
||||||
md_pkey_t *pkey, apr_pool_t *p);
|
md_pkey_t *pkey, apr_pool_t *p);
|
||||||
|
@@ -99,7 +99,7 @@ static size_t resp_data_cb(void *data, size_t len, size_t nmemb, void *baton)
|
|||||||
if (res->req->resp_limit) {
|
if (res->req->resp_limit) {
|
||||||
apr_off_t body_len = 0;
|
apr_off_t body_len = 0;
|
||||||
apr_brigade_length(res->body, 0, &body_len);
|
apr_brigade_length(res->body, 0, &body_len);
|
||||||
if (body_len + len > res->req->resp_limit) {
|
if (body_len + (apr_off_t)len > res->req->resp_limit) {
|
||||||
return 0; /* signal curl failure */
|
return 0; /* signal curl failure */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ static size_t header_cb(void *buffer, size_t elen, size_t nmemb, void *baton)
|
|||||||
md_http_response_t *res = baton;
|
md_http_response_t *res = baton;
|
||||||
size_t len, clen = elen * nmemb;
|
size_t len, clen = elen * nmemb;
|
||||||
const char *name = NULL, *value = "", *b = buffer;
|
const char *name = NULL, *value = "", *b = buffer;
|
||||||
int i;
|
apr_size_t i;
|
||||||
|
|
||||||
len = (clen && b[clen-1] == '\n')? clen-1 : clen;
|
len = (clen && b[clen-1] == '\n')? clen-1 : clen;
|
||||||
len = (len && b[len-1] == '\r')? len-1 : len;
|
len = (len && b[len-1] == '\r')? len-1 : len;
|
||||||
@@ -183,7 +183,7 @@ static int curlify_headers(void *baton, const char *key, const char *value)
|
|||||||
static apr_status_t curl_perform(md_http_request_t *req)
|
static apr_status_t curl_perform(md_http_request_t *req)
|
||||||
{
|
{
|
||||||
apr_status_t rv = APR_SUCCESS;
|
apr_status_t rv = APR_SUCCESS;
|
||||||
int curle;
|
CURLcode curle;
|
||||||
md_http_response_t *res;
|
md_http_response_t *res;
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
struct curl_slist *req_hdrs = NULL;
|
struct curl_slist *req_hdrs = NULL;
|
||||||
@@ -253,7 +253,8 @@ static apr_status_t curl_perform(md_http_request_t *req)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, res->rv, req->pool,
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, res->rv, req->pool,
|
||||||
"request %ld failed(%d): %s", req->id, curle, curl_easy_strerror(curle));
|
"request %ld failed(%d): %s", req->id, curle,
|
||||||
|
curl_easy_strerror(curle));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->cb) {
|
if (req->cb) {
|
||||||
|
@@ -162,19 +162,14 @@ static apr_status_t state_init(md_reg_t *reg, apr_pool_t *p, md_t *md)
|
|||||||
|
|
||||||
if (APR_SUCCESS == (rv = md_reg_creds_get(&creds, reg, MD_SG_DOMAINS, md, p))) {
|
if (APR_SUCCESS == (rv = md_reg_creds_get(&creds, reg, MD_SG_DOMAINS, md, p))) {
|
||||||
state = MD_S_INCOMPLETE;
|
state = MD_S_INCOMPLETE;
|
||||||
if (!creds->pkey) {
|
if (!creds->privkey) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
||||||
"md{%s}: incomplete, without private key", md->name);
|
"md{%s}: incomplete, without private key", md->name);
|
||||||
}
|
}
|
||||||
else if (!creds->cert) {
|
else if (!creds->pubcert) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
||||||
"md{%s}: incomplete, has key but no certificate", md->name);
|
"md{%s}: incomplete, has key but no certificate", md->name);
|
||||||
}
|
}
|
||||||
else if (!creds->chain) {
|
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
|
||||||
"md{%s}: incomplete, has key and certificate, but no chain file.",
|
|
||||||
md->name);
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
valid_from = md_cert_get_not_before(creds->cert);
|
valid_from = md_cert_get_not_before(creds->cert);
|
||||||
expires = md_cert_get_not_after(creds->cert);
|
expires = md_cert_get_not_after(creds->cert);
|
||||||
@@ -199,8 +194,8 @@ static apr_status_t state_init(md_reg_t *reg, apr_pool_t *p, md_t *md)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < creds->chain->nelts; ++i) {
|
for (i = 1; i < creds->pubcert->nelts; ++i) {
|
||||||
cert = APR_ARRAY_IDX(creds->chain, i, const md_cert_t *);
|
cert = APR_ARRAY_IDX(creds->pubcert, i, const md_cert_t *);
|
||||||
if (!md_cert_is_valid_now(cert)) {
|
if (!md_cert_is_valid_now(cert)) {
|
||||||
state = MD_S_ERROR;
|
state = MD_S_ERROR;
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p,
|
||||||
@@ -281,17 +276,34 @@ apr_status_t md_reg_assess(md_reg_t *reg, md_t *md, int *perrored, int *prenew,
|
|||||||
md->state = MD_S_EXPIRED;
|
md->state = MD_S_EXPIRED;
|
||||||
renew = 1;
|
renew = 1;
|
||||||
}
|
}
|
||||||
else if ((md->expires - now) <= md->renew_window) {
|
else {
|
||||||
int days = (int)(apr_time_sec(md->expires - now) / MD_SECS_PER_DAY);
|
apr_interval_time_t renew_win, left, life;
|
||||||
|
|
||||||
|
renew_win = md->renew_window;
|
||||||
|
if (md->renew_norm > 0
|
||||||
|
&& md->renew_norm > renew_win
|
||||||
|
&& md->expires > md->valid_from) {
|
||||||
|
/* Calc renewal days as fraction of cert lifetime - if known */
|
||||||
|
life = md->expires - md->valid_from;
|
||||||
|
renew_win = life * md->renew_norm / renew_win;
|
||||||
|
}
|
||||||
|
|
||||||
|
left = md->expires - now;
|
||||||
|
if (left <= renew_win) {
|
||||||
|
int days_left = (int)(apr_time_sec(left) / MD_SECS_PER_DAY);
|
||||||
md_log_perror( MD_LOG_MARK, MD_LOG_DEBUG, 0, p,
|
md_log_perror( MD_LOG_MARK, MD_LOG_DEBUG, 0, p,
|
||||||
"md(%s): %d days to expiry, attempt renewal", md->name, days);
|
"md(%s): %d days to expiry, attempt renewal",
|
||||||
|
md->name, days_left);
|
||||||
renew = 1;
|
renew = 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case MD_S_INCOMPLETE:
|
case MD_S_INCOMPLETE:
|
||||||
case MD_S_EXPIRED:
|
case MD_S_EXPIRED:
|
||||||
renew = 1;
|
renew = 1;
|
||||||
break;
|
break;
|
||||||
|
case MD_S_MISSING:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
*prenew = renew;
|
*prenew = renew;
|
||||||
*perrored = errored;
|
*perrored = errored;
|
||||||
@@ -417,16 +429,10 @@ apr_status_t md_reg_get_cred_files(md_reg_t *reg, const md_t *md, apr_pool_t *p,
|
|||||||
{
|
{
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
|
|
||||||
rv = md_store_get_fname(pkeyfile, reg->store, MD_SG_DOMAINS, md->name, MD_FN_PKEY, p);
|
|
||||||
if (APR_SUCCESS == rv) {
|
|
||||||
rv = md_store_get_fname(pcertfile, reg->store, MD_SG_DOMAINS, md->name, MD_FN_CERT, p);
|
|
||||||
}
|
|
||||||
if (APR_SUCCESS == rv) {
|
|
||||||
rv = md_store_get_fname(pchainfile, reg->store, MD_SG_DOMAINS, md->name, MD_FN_CHAIN, p);
|
|
||||||
if (APR_STATUS_IS_ENOENT(rv)) {
|
|
||||||
*pchainfile = NULL;
|
*pchainfile = NULL;
|
||||||
rv = APR_SUCCESS;
|
rv = md_store_get_fname(pkeyfile, reg->store, MD_SG_DOMAINS, md->name, MD_FN_PRIVKEY, p);
|
||||||
}
|
if (APR_SUCCESS == rv) {
|
||||||
|
rv = md_store_get_fname(pcertfile, reg->store, MD_SG_DOMAINS, md->name, MD_FN_PUBCERT, p);
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -513,6 +519,7 @@ static apr_status_t p_md_update(void *baton, apr_pool_t *p, apr_pool_t *ptemp, v
|
|||||||
}
|
}
|
||||||
if (MD_UPD_RENEW_WINDOW & fields) {
|
if (MD_UPD_RENEW_WINDOW & fields) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update renew-window: %s", name);
|
md_log_perror(MD_LOG_MARK, MD_LOG_TRACE1, 0, ptemp, "update renew-window: %s", name);
|
||||||
|
nmd->renew_norm = updates->renew_norm;
|
||||||
nmd->renew_window = updates->renew_window;
|
nmd->renew_window = updates->renew_window;
|
||||||
}
|
}
|
||||||
if (MD_UPD_CA_CHALLENGES & fields) {
|
if (MD_UPD_CA_CHALLENGES & fields) {
|
||||||
@@ -544,29 +551,28 @@ static int ok_or_noent(apr_status_t rv)
|
|||||||
static apr_status_t creds_load(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
|
static apr_status_t creds_load(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_list ap)
|
||||||
{
|
{
|
||||||
md_reg_t *reg = baton;
|
md_reg_t *reg = baton;
|
||||||
apr_status_t rv;
|
md_pkey_t *privkey;
|
||||||
md_cert_t *cert;
|
apr_array_header_t *pubcert;
|
||||||
md_pkey_t *pkey;
|
|
||||||
apr_array_header_t *chain;
|
|
||||||
md_creds_t *creds, **pcreds;
|
md_creds_t *creds, **pcreds;
|
||||||
const md_t *md;
|
const md_t *md;
|
||||||
md_cert_state_t cert_state;
|
md_cert_state_t cert_state;
|
||||||
md_store_group_t group;
|
md_store_group_t group;
|
||||||
|
apr_status_t rv;
|
||||||
|
|
||||||
pcreds = va_arg(ap, md_creds_t **);
|
pcreds = va_arg(ap, md_creds_t **);
|
||||||
group = va_arg(ap, int);
|
group = (md_store_group_t)va_arg(ap, int);
|
||||||
md = va_arg(ap, const md_t *);
|
md = va_arg(ap, const md_t *);
|
||||||
|
|
||||||
if (ok_or_noent(rv = md_cert_load(reg->store, group, md->name, &cert, p))
|
if (ok_or_noent(rv = md_pkey_load(reg->store, group, md->name, &privkey, p))
|
||||||
&& ok_or_noent(rv = md_pkey_load(reg->store, group, md->name, &pkey, p))
|
&& ok_or_noent(rv = md_pubcert_load(reg->store, group, md->name, &pubcert, p))) {
|
||||||
&& ok_or_noent(rv = md_chain_load(reg->store, group, md->name, &chain, p))) {
|
|
||||||
rv = APR_SUCCESS;
|
rv = APR_SUCCESS;
|
||||||
|
|
||||||
creds = apr_pcalloc(p, sizeof(*creds));
|
creds = apr_pcalloc(p, sizeof(*creds));
|
||||||
creds->cert = cert;
|
creds->privkey = privkey;
|
||||||
creds->pkey = pkey;
|
if (pubcert && pubcert->nelts > 0) {
|
||||||
creds->chain = chain;
|
creds->pubcert = pubcert;
|
||||||
|
creds->cert = APR_ARRAY_IDX(pubcert, 0, md_cert_t *);
|
||||||
|
}
|
||||||
if (creds->cert) {
|
if (creds->cert) {
|
||||||
switch ((cert_state = md_cert_state_get(creds->cert))) {
|
switch ((cert_state = md_cert_state_get(creds->cert))) {
|
||||||
case MD_CERT_VALID:
|
case MD_CERT_VALID:
|
||||||
@@ -767,10 +773,12 @@ apr_status_t md_reg_sync(md_reg_t *reg, apr_pool_t *p, apr_pool_t *ptemp,
|
|||||||
smd->contacts = md->contacts;
|
smd->contacts = md->contacts;
|
||||||
fields |= MD_UPD_CONTACTS;
|
fields |= MD_UPD_CONTACTS;
|
||||||
}
|
}
|
||||||
if (MD_VAL_UPDATE(md, smd, renew_window)) {
|
if (MD_VAL_UPDATE(md, smd, renew_window)
|
||||||
|
|| MD_VAL_UPDATE(md, smd, renew_norm)) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, p,
|
||||||
"%s: update renew_window, old=%ld, new=%ld",
|
"%s: update renew norm=%ld, window=%ld",
|
||||||
smd->name, (long)smd->renew_window, md->renew_window);
|
smd->name, (long)md->renew_norm, (long)md->renew_window);
|
||||||
|
smd->renew_norm = md->renew_norm;
|
||||||
smd->renew_window = md->renew_window;
|
smd->renew_window = md->renew_window;
|
||||||
fields |= MD_UPD_RENEW_WINDOW;
|
fields |= MD_UPD_RENEW_WINDOW;
|
||||||
}
|
}
|
||||||
@@ -880,7 +888,7 @@ apr_status_t md_reg_stage(md_reg_t *reg, const md_t *md, const char *challenge,
|
|||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
proto = apr_hash_get(reg->protos, md->ca_proto, strlen(md->ca_proto));
|
proto = apr_hash_get(reg->protos, md->ca_proto, (apr_ssize_t)strlen(md->ca_proto));
|
||||||
if (!proto) {
|
if (!proto) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p,
|
||||||
"md %s has unknown CA protocol: %s", md->name, md->ca_proto);
|
"md %s has unknown CA protocol: %s", md->name, md->ca_proto);
|
||||||
@@ -918,7 +926,7 @@ static apr_status_t run_load(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_l
|
|||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
proto = apr_hash_get(reg->protos, md->ca_proto, strlen(md->ca_proto));
|
proto = apr_hash_get(reg->protos, md->ca_proto, (apr_ssize_t)strlen(md->ca_proto));
|
||||||
if (!proto) {
|
if (!proto) {
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p,
|
md_log_perror(MD_LOG_MARK, MD_LOG_WARNING, 0, p,
|
||||||
"md %s has unknown CA protocol: %s", md->name, md->ca_proto);
|
"md %s has unknown CA protocol: %s", md->name, md->ca_proto);
|
||||||
|
@@ -232,13 +232,13 @@ typedef struct {
|
|||||||
apr_status_t md_pkey_load(md_store_t *store, md_store_group_t group, const char *name,
|
apr_status_t md_pkey_load(md_store_t *store, md_store_group_t group, const char *name,
|
||||||
md_pkey_t **ppkey, apr_pool_t *p)
|
md_pkey_t **ppkey, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
return md_store_load(store, group, name, MD_FN_PKEY, MD_SV_PKEY, (void**)ppkey, p);
|
return md_store_load(store, group, name, MD_FN_PRIVKEY, MD_SV_PKEY, (void**)ppkey, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t md_pkey_save(md_store_t *store, apr_pool_t *p, md_store_group_t group, const char *name,
|
apr_status_t md_pkey_save(md_store_t *store, apr_pool_t *p, md_store_group_t group, const char *name,
|
||||||
struct md_pkey_t *pkey, int create)
|
struct md_pkey_t *pkey, int create)
|
||||||
{
|
{
|
||||||
return md_store_save(store, p, group, name, MD_FN_PKEY, MD_SV_PKEY, pkey, create);
|
return md_store_save(store, p, group, name, MD_FN_PRIVKEY, MD_SV_PKEY, pkey, create);
|
||||||
}
|
}
|
||||||
|
|
||||||
apr_status_t md_cert_load(md_store_t *store, md_store_group_t group, const char *name,
|
apr_status_t md_cert_load(md_store_t *store, md_store_group_t group, const char *name,
|
||||||
@@ -267,6 +267,19 @@ apr_status_t md_chain_save(md_store_t *store, apr_pool_t *p,
|
|||||||
return md_store_save(store, p, group, name, MD_FN_CHAIN, MD_SV_CHAIN, chain, create);
|
return md_store_save(store, p, group, name, MD_FN_CHAIN, MD_SV_CHAIN, chain, create);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apr_status_t md_pubcert_load(md_store_t *store, md_store_group_t group, const char *name,
|
||||||
|
struct apr_array_header_t **ppubcert, apr_pool_t *p)
|
||||||
|
{
|
||||||
|
return md_store_load(store, group, name, MD_FN_PUBCERT, MD_SV_CHAIN, (void**)ppubcert, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
apr_status_t md_pubcert_save(md_store_t *store, apr_pool_t *p,
|
||||||
|
md_store_group_t group, const char *name,
|
||||||
|
struct apr_array_header_t *pubcert, int create)
|
||||||
|
{
|
||||||
|
return md_store_save(store, p, group, name, MD_FN_PUBCERT, MD_SV_CHAIN, pubcert, create);
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
md_store_t *store;
|
md_store_t *store;
|
||||||
md_store_group_t group;
|
md_store_group_t group;
|
||||||
|
@@ -146,5 +146,11 @@ apr_status_t md_chain_load(md_store_t *store, md_store_group_t group,
|
|||||||
apr_status_t md_chain_save(md_store_t *store, apr_pool_t *p, md_store_group_t group,
|
apr_status_t md_chain_save(md_store_t *store, apr_pool_t *p, md_store_group_t group,
|
||||||
const char *name, struct apr_array_header_t *chain, int create);
|
const char *name, struct apr_array_header_t *chain, int create);
|
||||||
|
|
||||||
|
apr_status_t md_pubcert_load(md_store_t *store, md_store_group_t group, const char *name,
|
||||||
|
struct apr_array_header_t **ppubcert, apr_pool_t *p);
|
||||||
|
apr_status_t md_pubcert_save(md_store_t *store, apr_pool_t *p,
|
||||||
|
md_store_group_t group, const char *name,
|
||||||
|
struct apr_array_header_t *pubcert, int create);
|
||||||
|
|
||||||
|
|
||||||
#endif /* mod_md_md_store_h */
|
#endif /* mod_md_md_store_h */
|
||||||
|
@@ -37,7 +37,7 @@
|
|||||||
/**************************************************************************************************/
|
/**************************************************************************************************/
|
||||||
/* file system based implementation of md_store_t */
|
/* file system based implementation of md_store_t */
|
||||||
|
|
||||||
#define MD_STORE_VERSION 1.0
|
#define MD_STORE_VERSION 2
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
apr_fileperms_t dir;
|
apr_fileperms_t dir;
|
||||||
@@ -60,8 +60,6 @@ struct md_store_fs_t {
|
|||||||
|
|
||||||
int port_80;
|
int port_80;
|
||||||
int port_443;
|
int port_443;
|
||||||
|
|
||||||
const unsigned char *dupkey;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FS_STORE(store) (md_store_fs_t*)(((char*)store)-offsetof(md_store_fs_t, s))
|
#define FS_STORE(store) (md_store_fs_t*)(((char*)store)-offsetof(md_store_fs_t, s))
|
||||||
@@ -98,32 +96,88 @@ static apr_status_t init_store_file(md_store_fs_t *s_fs, const char *fname,
|
|||||||
{
|
{
|
||||||
md_json_t *json = md_json_create(p);
|
md_json_t *json = md_json_create(p);
|
||||||
const char *key64;
|
const char *key64;
|
||||||
|
unsigned char *key;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
unsigned char key[FS_STORE_KLEN];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
md_json_sets(MOD_MD_VERSION, json, MD_KEY_VERSION, NULL);
|
md_json_sets(MOD_MD_VERSION, json, MD_KEY_VERSION, NULL);
|
||||||
md_json_setn(MD_STORE_VERSION, json, MD_KEY_STORE, MD_KEY_VERSION, NULL);
|
md_json_setn(MD_STORE_VERSION, json, MD_KEY_STORE, MD_KEY_VERSION, NULL);
|
||||||
|
|
||||||
/*if (APR_SUCCESS != (rv = md_rand_bytes(key, sizeof(key), p))) {
|
s_fs->key_len = FS_STORE_KLEN;
|
||||||
|
s_fs->key = key = apr_pcalloc(p, FS_STORE_KLEN);
|
||||||
|
if (APR_SUCCESS != (rv = md_rand_bytes(key, s_fs->key_len, p))) {
|
||||||
return rv;
|
return rv;
|
||||||
}*/
|
|
||||||
for (i = 0; i < FS_STORE_KLEN; ++i) {
|
|
||||||
key[i] = 'a' + (i % 26);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s_fs->key_len = sizeof(key);
|
key64 = md_util_base64url_encode((char *)key, s_fs->key_len, ptemp);
|
||||||
s_fs->key = apr_pcalloc(p, sizeof(key) + 1);
|
|
||||||
memcpy((void*)s_fs->key, key, sizeof(key));
|
|
||||||
s_fs->dupkey = apr_pmemdup(p, key, sizeof(key));
|
|
||||||
|
|
||||||
key64 = md_util_base64url_encode((char *)key, sizeof(key), ptemp);
|
|
||||||
md_json_sets(key64, json, MD_KEY_KEY, NULL);
|
md_json_sets(key64, json, MD_KEY_KEY, NULL);
|
||||||
|
|
||||||
rv = md_json_fcreatex(json, ptemp, MD_JSON_FMT_INDENT, fname, MD_FPROT_F_UONLY);
|
rv = md_json_fcreatex(json, ptemp, MD_JSON_FMT_INDENT, fname, MD_FPROT_F_UONLY);
|
||||||
memset((char*)key64, 0, strlen(key64));
|
memset((char*)key64, 0, strlen(key64));
|
||||||
|
|
||||||
assert(memcmp(s_fs->key, s_fs->dupkey, FS_STORE_KLEN) == 0);
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static apr_status_t rename_pkey(void *baton, apr_pool_t *p, apr_pool_t *ptemp,
|
||||||
|
const char *dir, const char *name,
|
||||||
|
apr_filetype_e ftype)
|
||||||
|
{
|
||||||
|
const char *from, *to;
|
||||||
|
apr_status_t rv = APR_SUCCESS;
|
||||||
|
|
||||||
|
if (APR_SUCCESS == (rv = md_util_path_merge(&from, ptemp, dir, name, NULL))
|
||||||
|
&& APR_SUCCESS == (rv = md_util_path_merge(&to, ptemp, dir, MD_FN_PRIVKEY, NULL))) {
|
||||||
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "renaming %s/%s to %s",
|
||||||
|
dir, name, MD_FN_PRIVKEY);
|
||||||
|
return apr_file_rename(from, to, ptemp);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static apr_status_t mk_pubcert(void *baton, apr_pool_t *p, apr_pool_t *ptemp,
|
||||||
|
const char *dir, const char *name,
|
||||||
|
apr_filetype_e ftype)
|
||||||
|
{
|
||||||
|
md_cert_t *cert;
|
||||||
|
apr_array_header_t *chain, *pubcert;
|
||||||
|
const char *fname, *fpubcert;
|
||||||
|
apr_status_t rv = APR_SUCCESS;
|
||||||
|
|
||||||
|
if ( APR_SUCCESS == (rv = md_util_path_merge(&fpubcert, ptemp, dir, MD_FN_PUBCERT, NULL))
|
||||||
|
&& APR_STATUS_IS_ENOENT((rv = md_chain_fload(&pubcert, ptemp, fpubcert)))
|
||||||
|
&& APR_SUCCESS == (rv = md_util_path_merge(&fname, ptemp, dir, name, NULL))
|
||||||
|
&& APR_SUCCESS == (rv = md_cert_fload(&cert, ptemp, fname))
|
||||||
|
&& APR_SUCCESS == (rv = md_util_path_merge(&fname, ptemp, dir, MD_FN_CHAIN, NULL))) {
|
||||||
|
|
||||||
|
rv = md_chain_fload(&chain, ptemp, fname);
|
||||||
|
if (APR_STATUS_IS_ENOENT(rv)) {
|
||||||
|
chain = apr_array_make(ptemp, 1, sizeof(md_cert_t*));
|
||||||
|
rv = APR_SUCCESS;
|
||||||
|
}
|
||||||
|
if (APR_SUCCESS == rv) {
|
||||||
|
pubcert = apr_array_make(ptemp, chain->nelts + 1, sizeof(md_cert_t*));
|
||||||
|
APR_ARRAY_PUSH(pubcert, md_cert_t *) = cert;
|
||||||
|
apr_array_cat(pubcert, chain);
|
||||||
|
rv = md_chain_fsave(pubcert, ptemp, fpubcert, MD_FPROT_F_UONLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static apr_status_t upgrade_from_1_0(md_store_fs_t *s_fs, apr_pool_t *p, apr_pool_t *ptemp)
|
||||||
|
{
|
||||||
|
md_store_group_t g;
|
||||||
|
apr_status_t rv = APR_SUCCESS;
|
||||||
|
|
||||||
|
/* Migrate pkey.pem -> privkey.pem */
|
||||||
|
for (g = MD_SG_NONE; g < MD_SG_COUNT && APR_SUCCESS == rv; ++g) {
|
||||||
|
rv = md_util_files_do(rename_pkey, s_fs, p, s_fs->base,
|
||||||
|
md_store_group_name(g), "*", "pkey.pem", NULL);
|
||||||
|
}
|
||||||
|
/* Generate fullcert.pem from cert.pem and chain.pem where missing */
|
||||||
|
rv = md_util_files_do(mk_pubcert, s_fs, p, s_fs->base,
|
||||||
|
md_store_group_name(MD_SG_DOMAINS), "*", MD_FN_CERT, NULL);
|
||||||
|
rv = md_util_files_do(mk_pubcert, s_fs, p, s_fs->base,
|
||||||
|
md_store_group_name(MD_SG_ARCHIVE), "*", MD_FN_CERT, NULL);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +185,7 @@ static apr_status_t read_store_file(md_store_fs_t *s_fs, const char *fname,
|
|||||||
apr_pool_t *p, apr_pool_t *ptemp)
|
apr_pool_t *p, apr_pool_t *ptemp)
|
||||||
{
|
{
|
||||||
md_json_t *json;
|
md_json_t *json;
|
||||||
const char *key64;
|
const char *key64, *key;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
double store_version;
|
double store_version;
|
||||||
|
|
||||||
@@ -145,9 +199,6 @@ static apr_status_t read_store_file(md_store_fs_t *s_fs, const char *fname,
|
|||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "version too new: %s", store_version);
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "version too new: %s", store_version);
|
||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
else if (store_version > MD_STORE_VERSION) {
|
|
||||||
/* migrate future store version changes */
|
|
||||||
}
|
|
||||||
|
|
||||||
key64 = md_json_dups(p, json, MD_KEY_KEY, NULL);
|
key64 = md_json_dups(p, json, MD_KEY_KEY, NULL);
|
||||||
if (!key64) {
|
if (!key64) {
|
||||||
@@ -155,12 +206,27 @@ static apr_status_t read_store_file(md_store_fs_t *s_fs, const char *fname,
|
|||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_fs->key_len = md_util_base64url_decode((const char **)&s_fs->key, key64, p);
|
s_fs->key_len = md_util_base64url_decode(&key, key64, p);
|
||||||
if (s_fs->key_len < FS_STORE_KLEN) {
|
s_fs->key = (const unsigned char*)key;
|
||||||
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "key too short: %d", s_fs->key_len);
|
if (s_fs->key_len != FS_STORE_KLEN) {
|
||||||
|
md_log_perror(MD_LOG_MARK, MD_LOG_ERR, 0, p, "key length unexpected: %d",
|
||||||
|
s_fs->key_len);
|
||||||
return APR_EINVAL;
|
return APR_EINVAL;
|
||||||
}
|
}
|
||||||
s_fs->dupkey = apr_pmemdup(p, s_fs->key, FS_STORE_KLEN);
|
|
||||||
|
/* Need to migrate format? */
|
||||||
|
if (store_version < MD_STORE_VERSION) {
|
||||||
|
if (store_version <= 1.0) {
|
||||||
|
md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, p, "migrating store v1.0 -> v1.1");
|
||||||
|
rv = upgrade_from_1_0(s_fs, p, ptemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (APR_SUCCESS == rv) {
|
||||||
|
md_json_setn(MD_STORE_VERSION, json, MD_KEY_STORE, MD_KEY_VERSION, NULL);
|
||||||
|
rv = md_json_freplace(json, ptemp, MD_JSON_FMT_INDENT, fname, MD_FPROT_F_UONLY);
|
||||||
|
}
|
||||||
|
md_log_perror(MD_LOG_MARK, MD_LOG_INFO, rv, p, "migrated store");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -320,7 +386,6 @@ static void get_pass(const char **ppass, apr_size_t *plen,
|
|||||||
*plen = 0;
|
*plen = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
assert(memcmp(s_fs->key, s_fs->dupkey, FS_STORE_KLEN) == 0);
|
|
||||||
*ppass = (const char *)s_fs->key;
|
*ppass = (const char *)s_fs->key;
|
||||||
*plen = s_fs->key_len;
|
*plen = s_fs->key_len;
|
||||||
}
|
}
|
||||||
@@ -374,10 +439,10 @@ static apr_status_t pfs_load(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_l
|
|||||||
void **pvalue;
|
void **pvalue;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
|
|
||||||
group = va_arg(ap, int);
|
group = (md_store_group_t)va_arg(ap, int);
|
||||||
name = va_arg(ap, const char *);
|
name = va_arg(ap, const char *);
|
||||||
aspect = va_arg(ap, const char *);
|
aspect = va_arg(ap, const char *);
|
||||||
vtype = va_arg(ap, int);
|
vtype = (md_store_vtype_t)va_arg(ap, int);
|
||||||
pvalue= va_arg(ap, void **);
|
pvalue= va_arg(ap, void **);
|
||||||
|
|
||||||
rv = fs_get_fname(&fpath, &s_fs->s, group, name, aspect, ptemp);
|
rv = fs_get_fname(&fpath, &s_fs->s, group, name, aspect, ptemp);
|
||||||
@@ -438,8 +503,8 @@ static apr_status_t pfs_is_newer(void *baton, apr_pool_t *p, apr_pool_t *ptemp,
|
|||||||
int *pnewer;
|
int *pnewer;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
|
|
||||||
group1 = va_arg(ap, int);
|
group1 = (md_store_group_t)va_arg(ap, int);
|
||||||
group2 = va_arg(ap, int);
|
group2 = (md_store_group_t)va_arg(ap, int);
|
||||||
name = va_arg(ap, const char*);
|
name = va_arg(ap, const char*);
|
||||||
aspect = va_arg(ap, const char*);
|
aspect = va_arg(ap, const char*);
|
||||||
pnewer = va_arg(ap, int*);
|
pnewer = va_arg(ap, int*);
|
||||||
@@ -483,10 +548,10 @@ static apr_status_t pfs_save(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_l
|
|||||||
const char *pass;
|
const char *pass;
|
||||||
apr_size_t pass_len;
|
apr_size_t pass_len;
|
||||||
|
|
||||||
group = va_arg(ap, int);
|
group = (md_store_group_t)va_arg(ap, int);
|
||||||
name = va_arg(ap, const char*);
|
name = va_arg(ap, const char*);
|
||||||
aspect = va_arg(ap, const char*);
|
aspect = va_arg(ap, const char*);
|
||||||
vtype = va_arg(ap, int);
|
vtype = (md_store_vtype_t)va_arg(ap, int);
|
||||||
value = va_arg(ap, void *);
|
value = va_arg(ap, void *);
|
||||||
create = va_arg(ap, int);
|
create = va_arg(ap, int);
|
||||||
|
|
||||||
@@ -540,7 +605,7 @@ static apr_status_t pfs_remove(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va
|
|||||||
apr_finfo_t info;
|
apr_finfo_t info;
|
||||||
md_store_group_t group;
|
md_store_group_t group;
|
||||||
|
|
||||||
group = va_arg(ap, int);
|
group = (md_store_group_t)va_arg(ap, int);
|
||||||
name = va_arg(ap, const char*);
|
name = va_arg(ap, const char*);
|
||||||
aspect = va_arg(ap, const char *);
|
aspect = va_arg(ap, const char *);
|
||||||
force = va_arg(ap, int);
|
force = va_arg(ap, int);
|
||||||
@@ -599,7 +664,7 @@ static apr_status_t pfs_purge(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_
|
|||||||
md_store_group_t group;
|
md_store_group_t group;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
|
|
||||||
group = va_arg(ap, int);
|
group = (md_store_group_t)va_arg(ap, int);
|
||||||
name = va_arg(ap, const char*);
|
name = va_arg(ap, const char*);
|
||||||
|
|
||||||
groupname = md_store_group_name(group);
|
groupname = md_store_group_name(group);
|
||||||
@@ -684,8 +749,8 @@ static apr_status_t pfs_move(void *baton, apr_pool_t *p, apr_pool_t *ptemp, va_l
|
|||||||
int archive;
|
int archive;
|
||||||
apr_status_t rv;
|
apr_status_t rv;
|
||||||
|
|
||||||
from = va_arg(ap, int);
|
from = (md_store_group_t)va_arg(ap, int);
|
||||||
to = va_arg(ap, int);
|
to = (md_store_group_t)va_arg(ap, int);
|
||||||
name = va_arg(ap, const char*);
|
name = va_arg(ap, const char*);
|
||||||
archive = va_arg(ap, int);
|
archive = va_arg(ap, int);
|
||||||
|
|
||||||
|
@@ -73,7 +73,7 @@ char *md_util_str_tolower(char *s)
|
|||||||
{
|
{
|
||||||
char *orig = s;
|
char *orig = s;
|
||||||
while (*s) {
|
while (*s) {
|
||||||
*s = apr_tolower(*s);
|
*s = (char)apr_tolower(*s);
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
return orig;
|
return orig;
|
||||||
@@ -759,26 +759,28 @@ const char *md_print_duration(apr_pool_t *p, apr_interval_time_t duration)
|
|||||||
|
|
||||||
/* base64 url encoding ****************************************************************************/
|
/* base64 url encoding ****************************************************************************/
|
||||||
|
|
||||||
static const int BASE64URL_UINT6[] = {
|
#define N6 (unsigned int)-1
|
||||||
|
|
||||||
|
static const unsigned int BASE64URL_UINT6[] = {
|
||||||
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 0 */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 1 */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 1 */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, /* 2 */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, 62, N6, N6, /* 2 */
|
||||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 3 */
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, N6, N6, N6, N6, N6, N6, /* 3 */
|
||||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 4 */
|
N6, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 4 */
|
||||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, /* 5 */
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, N6, N6, N6, N6, 63, /* 5 */
|
||||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 6 */
|
N6, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 6 */
|
||||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 7 */
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, N6, N6, N6, N6, N6, /* 7 */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 8 */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 8 */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 9 */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* 9 */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* a */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* b */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* b */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* c */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* c */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* d */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, /* e */
|
||||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* f */
|
N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6, N6 /* f */
|
||||||
};
|
};
|
||||||
static const char BASE64URL_CHARS[] = {
|
static const unsigned char BASE64URL_CHARS[] = {
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0 - 9 */
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 0 - 9 */
|
||||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10 - 19 */
|
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 10 - 19 */
|
||||||
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20 - 29 */
|
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', /* 20 - 29 */
|
||||||
@@ -788,21 +790,23 @@ static const char BASE64URL_CHARS[] = {
|
|||||||
'8', '9', '-', '_', ' ', ' ', ' ', ' ', ' ', ' ', /* 60 - 69 */
|
'8', '9', '-', '_', ' ', ' ', ' ', ' ', ' ', ' ', /* 60 - 69 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BASE64URL_CHAR(x) BASE64URL_CHARS[ (unsigned int)(x) & 0x3fu ]
|
||||||
|
|
||||||
apr_size_t md_util_base64url_decode(const char **decoded, const char *encoded,
|
apr_size_t md_util_base64url_decode(const char **decoded, const char *encoded,
|
||||||
apr_pool_t *pool)
|
apr_pool_t *pool)
|
||||||
{
|
{
|
||||||
const unsigned char *e = (const unsigned char *)encoded;
|
const unsigned char *e = (const unsigned char *)encoded;
|
||||||
const unsigned char *p = e;
|
const unsigned char *p = e;
|
||||||
unsigned char *d;
|
unsigned char *d;
|
||||||
int n;
|
unsigned int n;
|
||||||
apr_size_t len, mlen, remain, i;
|
long len, mlen, remain, i;
|
||||||
|
|
||||||
while (*p && BASE64URL_UINT6[ *p ] != -1) {
|
while (*p && BASE64URL_UINT6[ *p ] != N6) {
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
len = p - e;
|
len = p - e;
|
||||||
mlen = (len/4)*4;
|
mlen = (len/4)*4;
|
||||||
*decoded = apr_pcalloc(pool, len+1);
|
*decoded = apr_pcalloc(pool, (apr_size_t)len + 1);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
d = (unsigned char*)*decoded;
|
d = (unsigned char*)*decoded;
|
||||||
@@ -811,60 +815,59 @@ apr_size_t md_util_base64url_decode(const char **decoded, const char *encoded,
|
|||||||
(BASE64URL_UINT6[ e[i+1] ] << 12) +
|
(BASE64URL_UINT6[ e[i+1] ] << 12) +
|
||||||
(BASE64URL_UINT6[ e[i+2] ] << 6) +
|
(BASE64URL_UINT6[ e[i+2] ] << 6) +
|
||||||
(BASE64URL_UINT6[ e[i+3] ]));
|
(BASE64URL_UINT6[ e[i+3] ]));
|
||||||
*d++ = n >> 16;
|
*d++ = (unsigned char)(n >> 16);
|
||||||
*d++ = n >> 8 & 0xffu;
|
*d++ = (unsigned char)(n >> 8 & 0xffu);
|
||||||
*d++ = n & 0xffu;
|
*d++ = (unsigned char)(n & 0xffu);
|
||||||
}
|
}
|
||||||
remain = len - mlen;
|
remain = len - mlen;
|
||||||
switch (remain) {
|
switch (remain) {
|
||||||
case 2:
|
case 2:
|
||||||
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
||||||
(BASE64URL_UINT6[ e[mlen+1] ] << 12));
|
(BASE64URL_UINT6[ e[mlen+1] ] << 12));
|
||||||
*d++ = n >> 16;
|
*d++ = (unsigned char)(n >> 16);
|
||||||
remain = 1;
|
remain = 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
n = ((BASE64URL_UINT6[ e[mlen+0] ] << 18) +
|
||||||
(BASE64URL_UINT6[ e[mlen+1] ] << 12) +
|
(BASE64URL_UINT6[ e[mlen+1] ] << 12) +
|
||||||
(BASE64URL_UINT6[ e[mlen+2] ] << 6));
|
(BASE64URL_UINT6[ e[mlen+2] ] << 6));
|
||||||
*d++ = n >> 16;
|
*d++ = (unsigned char)(n >> 16);
|
||||||
*d++ = n >> 8 & 0xffu;
|
*d++ = (unsigned char)(n >> 8 & 0xffu);
|
||||||
remain = 2;
|
remain = 2;
|
||||||
break;
|
break;
|
||||||
default: /* do nothing */
|
default: /* do nothing */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return mlen/4*3 + remain;
|
return (apr_size_t)(mlen/4*3 + remain);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *md_util_base64url_encode(const char *data,
|
const char *md_util_base64url_encode(const char *data, apr_size_t dlen, apr_pool_t *pool)
|
||||||
apr_size_t dlen, apr_pool_t *pool)
|
|
||||||
{
|
{
|
||||||
long i, len = (int)dlen;
|
int i, len = (int)dlen;
|
||||||
apr_size_t slen = ((dlen+2)/3)*4 + 1; /* 0 terminated */
|
apr_size_t slen = ((dlen+2)/3)*4 + 1; /* 0 terminated */
|
||||||
const unsigned char *udata = (const unsigned char*)data;
|
const unsigned char *udata = (const unsigned char*)data;
|
||||||
char *enc, *p = apr_pcalloc(pool, slen);
|
unsigned char *enc, *p = apr_pcalloc(pool, slen);
|
||||||
|
|
||||||
enc = p;
|
enc = p;
|
||||||
for (i = 0; i < len-2; i+= 3) {
|
for (i = 0; i < len-2; i+= 3) {
|
||||||
*p++ = BASE64URL_CHARS[ (udata[i] >> 2) & 0x3fu ];
|
*p++ = BASE64URL_CHAR( (udata[i] >> 2) );
|
||||||
*p++ = BASE64URL_CHARS[ ((udata[i] << 4) + (udata[i+1] >> 4)) & 0x3fu ];
|
*p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
|
||||||
*p++ = BASE64URL_CHARS[ ((udata[i+1] << 2) + (udata[i+2] >> 6)) & 0x3fu ];
|
*p++ = BASE64URL_CHAR( (udata[i+1] << 2) + (udata[i+2] >> 6) );
|
||||||
*p++ = BASE64URL_CHARS[ udata[i+2] & 0x3fu ];
|
*p++ = BASE64URL_CHAR( (udata[i+2]) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < len) {
|
if (i < len) {
|
||||||
*p++ = BASE64URL_CHARS[ (udata[i] >> 2) & 0x3fu ];
|
*p++ = BASE64URL_CHAR( (udata[i] >> 2) );
|
||||||
if (i == (len - 1)) {
|
if (i == (len - 1)) {
|
||||||
*p++ = BASE64URL_CHARS[ (udata[i] << 4) & 0x3fu ];
|
*p++ = BASE64URL_CHARS[ ((unsigned int)udata[i] << 4) & 0x3fu ];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*p++ = BASE64URL_CHARS[ ((udata[i] << 4) + (udata[i+1] >> 4)) & 0x3fu ];
|
*p++ = BASE64URL_CHAR( (udata[i] << 4) + (udata[i+1] >> 4) );
|
||||||
*p++ = BASE64URL_CHARS[ (udata[i+1] << 2) & 0x3fu ];
|
*p++ = BASE64URL_CHAR( (udata[i+1] << 2) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*p++ = '\0';
|
*p++ = '\0';
|
||||||
return enc;
|
return (char *)enc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@@ -874,12 +877,12 @@ const char *md_util_base64url_encode(const char *data,
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
const char *s;
|
const char *s;
|
||||||
apr_size_t slen;
|
apr_size_t slen;
|
||||||
int i;
|
apr_size_t i;
|
||||||
int link_start;
|
apr_size_t link_start;
|
||||||
apr_size_t link_len;
|
apr_size_t link_len;
|
||||||
int pn_start;
|
apr_size_t pn_start;
|
||||||
apr_size_t pn_len;
|
apr_size_t pn_len;
|
||||||
int pv_start;
|
apr_size_t pv_start;
|
||||||
apr_size_t pv_len;
|
apr_size_t pv_len;
|
||||||
} link_ctx;
|
} link_ctx;
|
||||||
|
|
||||||
@@ -960,9 +963,9 @@ static int skip_nonws(link_ctx *ctx)
|
|||||||
return (ctx->i < ctx->slen);
|
return (ctx->i < ctx->slen);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_chr(link_ctx *ctx, char c, int *pidx)
|
static unsigned int find_chr(link_ctx *ctx, char c, apr_size_t *pidx)
|
||||||
{
|
{
|
||||||
int j;
|
apr_size_t j;
|
||||||
for (j = ctx->i; j < ctx->slen; ++j) {
|
for (j = ctx->i; j < ctx->slen; ++j) {
|
||||||
if (ctx->s[j] == c) {
|
if (ctx->s[j] == c) {
|
||||||
*pidx = j;
|
*pidx = j;
|
||||||
@@ -984,7 +987,7 @@ static int read_chr(link_ctx *ctx, char c)
|
|||||||
static int skip_qstring(link_ctx *ctx)
|
static int skip_qstring(link_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (skip_ws(ctx) && read_chr(ctx, '\"')) {
|
if (skip_ws(ctx) && read_chr(ctx, '\"')) {
|
||||||
int end;
|
apr_size_t end;
|
||||||
if (find_chr(ctx, '\"', &end)) {
|
if (find_chr(ctx, '\"', &end)) {
|
||||||
ctx->i = end + 1;
|
ctx->i = end + 1;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -996,7 +999,7 @@ static int skip_qstring(link_ctx *ctx)
|
|||||||
static int skip_ptoken(link_ctx *ctx)
|
static int skip_ptoken(link_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (skip_ws(ctx)) {
|
if (skip_ws(ctx)) {
|
||||||
int i;
|
apr_size_t i;
|
||||||
for (i = ctx->i; i < ctx->slen && ptoken_char(ctx->s[i]); ++i) {
|
for (i = ctx->i; i < ctx->slen && ptoken_char(ctx->s[i]); ++i) {
|
||||||
/* nop */
|
/* nop */
|
||||||
}
|
}
|
||||||
@@ -1013,7 +1016,7 @@ static int read_link(link_ctx *ctx)
|
|||||||
{
|
{
|
||||||
ctx->link_start = ctx->link_len = 0;
|
ctx->link_start = ctx->link_len = 0;
|
||||||
if (skip_ws(ctx) && read_chr(ctx, '<')) {
|
if (skip_ws(ctx) && read_chr(ctx, '<')) {
|
||||||
int end;
|
apr_size_t end;
|
||||||
if (find_chr(ctx, '>', &end)) {
|
if (find_chr(ctx, '>', &end)) {
|
||||||
ctx->link_start = ctx->i;
|
ctx->link_start = ctx->i;
|
||||||
ctx->link_len = end - ctx->link_start;
|
ctx->link_len = end - ctx->link_start;
|
||||||
@@ -1027,7 +1030,7 @@ static int read_link(link_ctx *ctx)
|
|||||||
static int skip_pname(link_ctx *ctx)
|
static int skip_pname(link_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (skip_ws(ctx)) {
|
if (skip_ws(ctx)) {
|
||||||
int i;
|
apr_size_t i;
|
||||||
for (i = ctx->i; i < ctx->slen && attr_char(ctx->s[i]); ++i) {
|
for (i = ctx->i; i < ctx->slen && attr_char(ctx->s[i]); ++i) {
|
||||||
/* nop */
|
/* nop */
|
||||||
}
|
}
|
||||||
@@ -1068,7 +1071,7 @@ static int skip_param(link_ctx *ctx)
|
|||||||
|
|
||||||
static int pv_contains(link_ctx *ctx, const char *s)
|
static int pv_contains(link_ctx *ctx, const char *s)
|
||||||
{
|
{
|
||||||
int pvstart = ctx->pv_start;
|
apr_size_t pvstart = ctx->pv_start;
|
||||||
apr_size_t pvlen = ctx->pv_len;
|
apr_size_t pvlen = ctx->pv_len;
|
||||||
|
|
||||||
if (ctx->s[pvstart] == '\"' && pvlen > 1) {
|
if (ctx->s[pvstart] == '\"' && pvlen > 1) {
|
||||||
@@ -1078,7 +1081,7 @@ static int pv_contains(link_ctx *ctx, const char *s)
|
|||||||
if (pvlen > 0) {
|
if (pvlen > 0) {
|
||||||
apr_size_t slen = strlen(s);
|
apr_size_t slen = strlen(s);
|
||||||
link_ctx pvctx;
|
link_ctx pvctx;
|
||||||
int i;
|
apr_size_t i;
|
||||||
|
|
||||||
memset(&pvctx, 0, sizeof(pvctx));
|
memset(&pvctx, 0, sizeof(pvctx));
|
||||||
pvctx.s = ctx->s + pvstart;
|
pvctx.s = ctx->s + pvstart;
|
||||||
@@ -1148,7 +1151,7 @@ static int find_url(void *baton, const char *key, const char *value)
|
|||||||
|
|
||||||
memset(&ctx, 0, sizeof(ctx));
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
ctx.s = value;
|
ctx.s = value;
|
||||||
ctx.slen = (int)strlen(value);
|
ctx.slen = strlen(value);
|
||||||
|
|
||||||
while (read_link(&ctx)) {
|
while (read_link(&ctx)) {
|
||||||
while (skip_param(&ctx)) {
|
while (skip_param(&ctx)) {
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
* @macro
|
* @macro
|
||||||
* Version number of the md module as c string
|
* Version number of the md module as c string
|
||||||
*/
|
*/
|
||||||
#define MOD_MD_VERSION "0.7.0-git"
|
#define MOD_MD_VERSION "0.8.1"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro
|
* @macro
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||||
*/
|
*/
|
||||||
#define MOD_MD_VERSION_NUM 0x000700
|
#define MOD_MD_VERSION_NUM 0x000801
|
||||||
|
|
||||||
#define MD_EXPERIMENTAL 0
|
#define MD_EXPERIMENTAL 0
|
||||||
#define MD_ACME_DEF_URL "https://acme-v01.api.letsencrypt.org/directory"
|
#define MD_ACME_DEF_URL "https://acme-v01.api.letsencrypt.org/directory"
|
||||||
|
@@ -78,6 +78,9 @@ static void md_merge_srv(md_t *md, md_srv_conf_t *base_sc, apr_pool_t *p)
|
|||||||
if (md->drive_mode == MD_DRIVE_DEFAULT) {
|
if (md->drive_mode == MD_DRIVE_DEFAULT) {
|
||||||
md->drive_mode = md_config_geti(md->sc, MD_CONFIG_DRIVE_MODE);
|
md->drive_mode = md_config_geti(md->sc, MD_CONFIG_DRIVE_MODE);
|
||||||
}
|
}
|
||||||
|
if (md->renew_norm <= 0) {
|
||||||
|
md->renew_norm = md_config_get_interval(md->sc, MD_CONFIG_RENEW_NORM);
|
||||||
|
}
|
||||||
if (md->renew_window <= 0) {
|
if (md->renew_window <= 0) {
|
||||||
md->renew_window = md_config_get_interval(md->sc, MD_CONFIG_RENEW_WINDOW);
|
md->renew_window = md_config_get_interval(md->sc, MD_CONFIG_RENEW_WINDOW);
|
||||||
}
|
}
|
||||||
@@ -87,6 +90,10 @@ static void md_merge_srv(md_t *md, md_srv_conf_t *base_sc, apr_pool_t *p)
|
|||||||
if (!md->ca_challenges && md->sc->ca_challenges) {
|
if (!md->ca_challenges && md->sc->ca_challenges) {
|
||||||
md->ca_challenges = apr_array_copy(p, md->sc->ca_challenges);
|
md->ca_challenges = apr_array_copy(p, md->sc->ca_challenges);
|
||||||
}
|
}
|
||||||
|
if (!md->pkey_spec) {
|
||||||
|
md->pkey_spec = md->sc->pkey_spec;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s, apr_pool_t *p)
|
static apr_status_t check_coverage(md_t *md, const char *domain, server_rec *s, apr_pool_t *p)
|
||||||
@@ -460,6 +467,9 @@ static apr_status_t drive_md(md_watchdog *wd, md_t *md, apr_pool_t *ptemp)
|
|||||||
int errored, renew;
|
int errored, renew;
|
||||||
char ts[APR_RFC822_DATE_LEN];
|
char ts[APR_RFC822_DATE_LEN];
|
||||||
|
|
||||||
|
if (md->state == MD_S_MISSING) {
|
||||||
|
rv = APR_INCOMPLETE;
|
||||||
|
}
|
||||||
if (md->state == MD_S_COMPLETE && !md->expires) {
|
if (md->state == MD_S_COMPLETE && !md->expires) {
|
||||||
/* This is our indicator that we did already renewed this managed domain
|
/* This is our indicator that we did already renewed this managed domain
|
||||||
* successfully and only wait on the next restart for it to activate */
|
* successfully and only wait on the next restart for it to activate */
|
||||||
@@ -508,7 +518,7 @@ static apr_status_t run_watchdog(int state, void *baton, apr_pool_t *ptemp)
|
|||||||
md_watchdog *wd = baton;
|
md_watchdog *wd = baton;
|
||||||
apr_status_t rv = APR_SUCCESS;
|
apr_status_t rv = APR_SUCCESS;
|
||||||
md_t *md;
|
md_t *md;
|
||||||
apr_interval_time_t interval, now;
|
apr_time_t next_run, now;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
@@ -519,9 +529,6 @@ static apr_status_t run_watchdog(int state, void *baton, apr_pool_t *ptemp)
|
|||||||
case AP_WATCHDOG_STATE_RUNNING:
|
case AP_WATCHDOG_STATE_RUNNING:
|
||||||
assert(wd->reg);
|
assert(wd->reg);
|
||||||
|
|
||||||
/* normally, we'd like to run at least twice a day */
|
|
||||||
interval = apr_time_from_sec(MD_SECS_PER_DAY / 2);
|
|
||||||
|
|
||||||
wd->all_valid = 1;
|
wd->all_valid = 1;
|
||||||
wd->valid_not_before = 0;
|
wd->valid_not_before = 0;
|
||||||
wd->processed_count = 0;
|
wd->processed_count = 0;
|
||||||
@@ -536,7 +543,13 @@ static apr_status_t run_watchdog(int state, void *baton, apr_pool_t *ptemp)
|
|||||||
for (i = 0; i < wd->mds->nelts; ++i) {
|
for (i = 0; i < wd->mds->nelts; ++i) {
|
||||||
md = APR_ARRAY_IDX(wd->mds, i, md_t *);
|
md = APR_ARRAY_IDX(wd->mds, i, md_t *);
|
||||||
|
|
||||||
if (APR_SUCCESS != (rv = drive_md(wd, md, ptemp))) {
|
rv = drive_md(wd, md, ptemp);
|
||||||
|
|
||||||
|
if (APR_STATUS_IS_INCOMPLETE(rv)) {
|
||||||
|
/* configuration not complete, this MD cannot be driven further */
|
||||||
|
wd->all_valid = 0;
|
||||||
|
}
|
||||||
|
else if (APR_SUCCESS != rv) {
|
||||||
wd->all_valid = 0;
|
wd->all_valid = 0;
|
||||||
++wd->error_count;
|
++wd->error_count;
|
||||||
ap_log_error( APLOG_MARK, APLOG_ERR, rv, wd->s, APLOGNO(10056)
|
ap_log_error( APLOG_MARK, APLOG_ERR, rv, wd->s, APLOGNO(10056)
|
||||||
@@ -546,50 +559,57 @@ static apr_status_t run_watchdog(int state, void *baton, apr_pool_t *ptemp)
|
|||||||
|
|
||||||
/* Determine when we want to run next */
|
/* Determine when we want to run next */
|
||||||
wd->error_runs = wd->error_count? (wd->error_runs + 1) : 0;
|
wd->error_runs = wd->error_count? (wd->error_runs + 1) : 0;
|
||||||
|
|
||||||
if (wd->all_valid) {
|
if (wd->all_valid) {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s, "all managed domains are valid");
|
||||||
|
}
|
||||||
|
else if (wd->error_count == 0) {
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO()
|
||||||
|
"all managed domains driven as far as possible");
|
||||||
|
}
|
||||||
|
|
||||||
now = apr_time_now();
|
now = apr_time_now();
|
||||||
if (wd->next_valid > now && (wd->next_valid - now < interval)) {
|
/* normally, we'd like to run at least twice a day */
|
||||||
interval = wd->next_valid - now;
|
next_run = now + apr_time_from_sec(MD_SECS_PER_DAY / 2);
|
||||||
|
|
||||||
|
/* Unless we know of an MD change before that */
|
||||||
|
if (wd->next_change > 0 && wd->next_change < next_run) {
|
||||||
|
next_run = wd->next_change;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Or have to activate a new cert even before that */
|
||||||
|
if (wd->next_valid > now && wd->next_valid < next_run) {
|
||||||
|
next_run = wd->next_valid;
|
||||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s,
|
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s,
|
||||||
"Delaying activation of %d Managed Domain%s by %s",
|
"Delaying activation of %d Managed Domain%s by %s",
|
||||||
wd->processed_count, (wd->processed_count > 1)? "s have" : " has",
|
wd->processed_count, (wd->processed_count > 1)? "s have" : " has",
|
||||||
md_print_duration(ptemp, interval));
|
md_print_duration(ptemp, next_run - now));
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, wd->s,
|
/* Or encountered errors and like to retry even before that */
|
||||||
"all managed domains are valid");
|
if (wd->error_count > 0) {
|
||||||
}
|
apr_interval_time_t delay;
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* back off duration, depending on the errors we encounter in a row */
|
/* back off duration, depending on the errors we encounter in a row */
|
||||||
interval = apr_time_from_sec(5 << (wd->error_runs - 1));
|
delay = apr_time_from_sec(5 << (wd->error_runs - 1));
|
||||||
if (interval > apr_time_from_sec(60*60)) {
|
if (delay > apr_time_from_sec(60*60)) {
|
||||||
interval = apr_time_from_sec(60*60);
|
delay = apr_time_from_sec(60*60);
|
||||||
}
|
}
|
||||||
|
if (now + delay < next_run) {
|
||||||
ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057)
|
ap_log_error(APLOG_MARK, APLOG_INFO, 0, wd->s, APLOGNO(10057)
|
||||||
"encountered errors for the %d. time, next run in %d seconds",
|
"encountered errors for the %d. time, next try by %s",
|
||||||
wd->error_runs, (int)apr_time_sec(interval));
|
wd->error_runs, md_print_duration(ptemp, delay));
|
||||||
}
|
next_run = now + delay;
|
||||||
|
|
||||||
/* We follow the chosen min_interval for re-evaluation, unless we
|
|
||||||
* know of a change (renewal) that happens before that. */
|
|
||||||
if (wd->next_change) {
|
|
||||||
apr_interval_time_t until_next = wd->next_change - apr_time_now();
|
|
||||||
if (until_next < interval) {
|
|
||||||
interval = until_next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set when we'd like to be run next time.
|
|
||||||
* TODO: it seems that this is really only ticking down when the server
|
|
||||||
* runs. When you wake up a hibernated machine, the watchdog will not run right away
|
|
||||||
*/
|
|
||||||
if (APLOGdebug(wd->s)) {
|
if (APLOGdebug(wd->s)) {
|
||||||
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, wd->s, "next run in %s",
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO()
|
||||||
md_print_duration(ptemp, interval));
|
"next run in %s", md_print_duration(ptemp, next_run - now));
|
||||||
}
|
}
|
||||||
wd_set_interval(wd->watchdog, interval, wd, run_watchdog);
|
wd_set_interval(wd->watchdog, next_run - now, wd, run_watchdog);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AP_WATCHDOG_STATE_STOPPING:
|
case AP_WATCHDOG_STATE_STOPPING:
|
||||||
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10058)
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, wd->s, APLOGNO(10058)
|
||||||
"md watchdog stopping");
|
"md watchdog stopping");
|
||||||
@@ -684,7 +704,7 @@ static apr_status_t start_watchdog(apr_array_header_t *names, apr_pool_t *p,
|
|||||||
if (!wd->mds->nelts) {
|
if (!wd->mds->nelts) {
|
||||||
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10065)
|
ap_log_error( APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10065)
|
||||||
"no managed domain in state to drive, no watchdog needed, "
|
"no managed domain in state to drive, no watchdog needed, "
|
||||||
"will check again on next server restart");
|
"will check again on next server (graceful) restart");
|
||||||
apr_pool_destroy(wd->p);
|
apr_pool_destroy(wd->p);
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include <http_vhost.h>
|
#include <http_vhost.h>
|
||||||
|
|
||||||
#include "md.h"
|
#include "md.h"
|
||||||
|
#include "md_crypt.h"
|
||||||
#include "md_util.h"
|
#include "md_util.h"
|
||||||
#include "mod_md_private.h"
|
#include "mod_md_private.h"
|
||||||
#include "mod_md_config.h"
|
#include "mod_md_config.h"
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
#define MD_CMD_MEMBER "MDMember"
|
#define MD_CMD_MEMBER "MDMember"
|
||||||
#define MD_CMD_MEMBERS "MDMembers"
|
#define MD_CMD_MEMBERS "MDMembers"
|
||||||
#define MD_CMD_PORTMAP "MDPortMap"
|
#define MD_CMD_PORTMAP "MDPortMap"
|
||||||
|
#define MD_CMD_PKEYS "MDPrivateKeys"
|
||||||
#define MD_CMD_RENEWWINDOW "MDRenewWindow"
|
#define MD_CMD_RENEWWINDOW "MDRenewWindow"
|
||||||
#define MD_CMD_STOREDIR "MDStoreDir"
|
#define MD_CMD_STOREDIR "MDStoreDir"
|
||||||
|
|
||||||
@@ -65,8 +67,9 @@ static md_srv_conf_t defconf = {
|
|||||||
1,
|
1,
|
||||||
MD_DRIVE_AUTO,
|
MD_DRIVE_AUTO,
|
||||||
0,
|
0,
|
||||||
apr_time_from_sec(14 * MD_SECS_PER_DAY),
|
NULL,
|
||||||
|
apr_time_from_sec(90 * MD_SECS_PER_DAY), /* If the cert lifetime were 90 days, renew */
|
||||||
|
apr_time_from_sec(30 * MD_SECS_PER_DAY), /* 30 days before. Adjust to actual lifetime */
|
||||||
MD_ACME_DEF_URL,
|
MD_ACME_DEF_URL,
|
||||||
"ACME",
|
"ACME",
|
||||||
NULL,
|
NULL,
|
||||||
@@ -109,6 +112,8 @@ static void srv_conf_props_clear(md_srv_conf_t *sc)
|
|||||||
sc->transitive = DEF_VAL;
|
sc->transitive = DEF_VAL;
|
||||||
sc->drive_mode = DEF_VAL;
|
sc->drive_mode = DEF_VAL;
|
||||||
sc->must_staple = DEF_VAL;
|
sc->must_staple = DEF_VAL;
|
||||||
|
sc->pkey_spec = NULL;
|
||||||
|
sc->renew_norm = DEF_VAL;
|
||||||
sc->renew_window = DEF_VAL;
|
sc->renew_window = DEF_VAL;
|
||||||
sc->ca_url = NULL;
|
sc->ca_url = NULL;
|
||||||
sc->ca_proto = NULL;
|
sc->ca_proto = NULL;
|
||||||
@@ -121,6 +126,8 @@ static void srv_conf_props_copy(md_srv_conf_t *to, const md_srv_conf_t *from)
|
|||||||
to->transitive = from->transitive;
|
to->transitive = from->transitive;
|
||||||
to->drive_mode = from->drive_mode;
|
to->drive_mode = from->drive_mode;
|
||||||
to->must_staple = from->must_staple;
|
to->must_staple = from->must_staple;
|
||||||
|
to->pkey_spec = from->pkey_spec;
|
||||||
|
to->renew_norm = from->renew_norm;
|
||||||
to->renew_window = from->renew_window;
|
to->renew_window = from->renew_window;
|
||||||
to->ca_url = from->ca_url;
|
to->ca_url = from->ca_url;
|
||||||
to->ca_proto = from->ca_proto;
|
to->ca_proto = from->ca_proto;
|
||||||
@@ -133,6 +140,8 @@ static void srv_conf_props_apply(md_t *md, const md_srv_conf_t *from, apr_pool_t
|
|||||||
if (from->transitive != DEF_VAL) md->transitive = from->transitive;
|
if (from->transitive != DEF_VAL) md->transitive = from->transitive;
|
||||||
if (from->drive_mode != DEF_VAL) md->drive_mode = from->drive_mode;
|
if (from->drive_mode != DEF_VAL) md->drive_mode = from->drive_mode;
|
||||||
if (from->must_staple != DEF_VAL) md->must_staple = from->must_staple;
|
if (from->must_staple != DEF_VAL) md->must_staple = from->must_staple;
|
||||||
|
if (from->pkey_spec) md->pkey_spec = from->pkey_spec;
|
||||||
|
if (from->renew_norm != DEF_VAL) md->renew_norm = from->renew_norm;
|
||||||
if (from->renew_window != DEF_VAL) md->renew_window = from->renew_window;
|
if (from->renew_window != DEF_VAL) md->renew_window = from->renew_window;
|
||||||
|
|
||||||
if (from->ca_url) md->ca_url = from->ca_url;
|
if (from->ca_url) md->ca_url = from->ca_url;
|
||||||
@@ -166,6 +175,9 @@ static void *md_config_merge(apr_pool_t *pool, void *basev, void *addv)
|
|||||||
|
|
||||||
nsc->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive;
|
nsc->transitive = (add->transitive != DEF_VAL)? add->transitive : base->transitive;
|
||||||
nsc->drive_mode = (add->drive_mode != DEF_VAL)? add->drive_mode : base->drive_mode;
|
nsc->drive_mode = (add->drive_mode != DEF_VAL)? add->drive_mode : base->drive_mode;
|
||||||
|
nsc->must_staple = (add->must_staple != DEF_VAL)? add->must_staple : base->must_staple;
|
||||||
|
nsc->pkey_spec = add->pkey_spec? add->pkey_spec : base->pkey_spec;
|
||||||
|
nsc->renew_window = (add->renew_norm != DEF_VAL)? add->renew_norm : base->renew_norm;
|
||||||
nsc->renew_window = (add->renew_window != DEF_VAL)? add->renew_window : base->renew_window;
|
nsc->renew_window = (add->renew_window != DEF_VAL)? add->renew_window : base->renew_window;
|
||||||
|
|
||||||
nsc->ca_url = add->ca_url? add->ca_url : base->ca_url;
|
nsc->ca_url = add->ca_url? add->ca_url : base->ca_url;
|
||||||
@@ -242,7 +254,7 @@ static const char *md_config_sec_start(cmd_parms *cmd, void *mconfig, const char
|
|||||||
return MD_CMD_MD_SECTION "> directive missing closing '>'";
|
return MD_CMD_MD_SECTION "> directive missing closing '>'";
|
||||||
}
|
}
|
||||||
|
|
||||||
arg = apr_pstrndup(cmd->pool, arg, endp-arg);
|
arg = apr_pstrndup(cmd->pool, arg, (apr_size_t)(endp-arg));
|
||||||
if (!arg || !*arg) {
|
if (!arg || !*arg) {
|
||||||
return MD_CMD_MD_SECTION " > section must specify a unique domain name";
|
return MD_CMD_MD_SECTION " > section must specify a unique domain name";
|
||||||
}
|
}
|
||||||
@@ -444,24 +456,55 @@ static apr_status_t duration_parse(const char *value, apr_interval_time_t *ptime
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static apr_status_t percentage_parse(const char *value, int *ppercent)
|
||||||
|
{
|
||||||
|
char *endp;
|
||||||
|
apr_int64_t n;
|
||||||
|
|
||||||
|
n = apr_strtoi64(value, &endp, 10);
|
||||||
|
if (errno) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
if (*endp == '%') {
|
||||||
|
if (n < 0 || n >= 100) {
|
||||||
|
return APR_BADARG;
|
||||||
|
}
|
||||||
|
*ppercent = (int)n;
|
||||||
|
return APR_SUCCESS;
|
||||||
|
}
|
||||||
|
return APR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *md_config_set_renew_window(cmd_parms *cmd, void *dc, const char *value)
|
static const char *md_config_set_renew_window(cmd_parms *cmd, void *dc, const char *value)
|
||||||
{
|
{
|
||||||
md_srv_conf_t *config = md_config_get(cmd->server);
|
md_srv_conf_t *config = md_config_get(cmd->server);
|
||||||
const char *err;
|
const char *err;
|
||||||
apr_interval_time_t timeout;
|
apr_interval_time_t timeout;
|
||||||
|
int percent;
|
||||||
/* Inspired by http_core.c */
|
|
||||||
if (duration_parse(value, &timeout, "d") != APR_SUCCESS) {
|
|
||||||
return "MDRenewWindow has wrong format";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!inside_section(cmd, MD_CMD_MD_SECTION)
|
if (!inside_section(cmd, MD_CMD_MD_SECTION)
|
||||||
&& (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
|
&& (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Inspired by http_core.c */
|
||||||
|
if (duration_parse(value, &timeout, "d") == APR_SUCCESS) {
|
||||||
|
config->renew_norm = 0;
|
||||||
config->renew_window = timeout;
|
config->renew_window = timeout;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
switch (percentage_parse(value, &percent)) {
|
||||||
|
case APR_SUCCESS:
|
||||||
|
config->renew_norm = 100;
|
||||||
|
config->renew_window = percent;
|
||||||
|
return NULL;
|
||||||
|
case APR_BADARG:
|
||||||
|
return "MDRenewWindow as percent must be less than 100";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "MDRenewWindow has unrecognized format";
|
||||||
|
}
|
||||||
|
|
||||||
static const char *md_config_set_store_dir(cmd_parms *cmd, void *arg, const char *value)
|
static const char *md_config_set_store_dir(cmd_parms *cmd, void *arg, const char *value)
|
||||||
{
|
{
|
||||||
@@ -555,6 +598,57 @@ static const char *md_config_set_cha_tyes(cmd_parms *cmd, void *dc,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *md_config_set_pkeys(cmd_parms *cmd, void *arg,
|
||||||
|
int argc, char *const argv[])
|
||||||
|
{
|
||||||
|
md_srv_conf_t *config = md_config_get(cmd->server);
|
||||||
|
const char *err, *ptype;
|
||||||
|
apr_int64_t bits;
|
||||||
|
|
||||||
|
if (!inside_section(cmd, MD_CMD_MD_SECTION)
|
||||||
|
&& (err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (argc <= 0) {
|
||||||
|
return "needs to specify the private key type";
|
||||||
|
}
|
||||||
|
|
||||||
|
ptype = argv[0];
|
||||||
|
if (!apr_strnatcasecmp("Default", ptype)) {
|
||||||
|
if (argc > 1) {
|
||||||
|
return "type 'Default' takes no parameter";
|
||||||
|
}
|
||||||
|
if (!config->pkey_spec) {
|
||||||
|
config->pkey_spec = apr_pcalloc(cmd->pool, sizeof(*config->pkey_spec));
|
||||||
|
}
|
||||||
|
config->pkey_spec->type = MD_PKEY_TYPE_DEFAULT;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (!apr_strnatcasecmp("RSA", ptype)) {
|
||||||
|
if (argc == 1) {
|
||||||
|
bits = MD_PKEY_RSA_BITS_DEF;
|
||||||
|
}
|
||||||
|
else if (argc == 2) {
|
||||||
|
bits = (int)apr_atoi64(argv[1]);
|
||||||
|
if (bits < 2048 || bits >= INT_MAX) {
|
||||||
|
return "must be a 2048 or higher in order to be considered safe. "
|
||||||
|
"Too large a value will slow down everything. Larger then 4096 probably does "
|
||||||
|
"not make sense unless quantum cryptography really changes spin.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "key type 'RSA' has only one optinal parameter, the number of bits";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config->pkey_spec) {
|
||||||
|
config->pkey_spec = apr_pcalloc(cmd->pool, sizeof(*config->pkey_spec));
|
||||||
|
}
|
||||||
|
config->pkey_spec->type = MD_PKEY_TYPE_RSA;
|
||||||
|
config->pkey_spec->params.rsa.bits = (unsigned int)bits;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return apr_pstrcat(cmd->pool, "unsupported private key type \"", ptype, "\"", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
const command_rec md_cmds[] = {
|
const command_rec md_cmds[] = {
|
||||||
AP_INIT_TAKE1( MD_CMD_CA, md_config_set_ca, NULL, RSRC_CONF,
|
AP_INIT_TAKE1( MD_CMD_CA, md_config_set_ca, NULL, RSRC_CONF,
|
||||||
@@ -582,6 +676,8 @@ const command_rec md_cmds[] = {
|
|||||||
"to indicate that the server port 8000 is reachable as port 80 from the "
|
"to indicate that the server port 8000 is reachable as port 80 from the "
|
||||||
"internet. Use 80:- to indicate that port 80 is not reachable from "
|
"internet. Use 80:- to indicate that port 80 is not reachable from "
|
||||||
"the outside."),
|
"the outside."),
|
||||||
|
AP_INIT_TAKE_ARGV( MD_CMD_PKEYS, md_config_set_pkeys, NULL, RSRC_CONF,
|
||||||
|
"set the type and parameters for private key generation"),
|
||||||
AP_INIT_TAKE1( MD_CMD_STOREDIR, md_config_set_store_dir, NULL, RSRC_CONF,
|
AP_INIT_TAKE1( MD_CMD_STOREDIR, md_config_set_store_dir, NULL, RSRC_CONF,
|
||||||
"the directory for file system storage of managed domain data."),
|
"the directory for file system storage of managed domain data."),
|
||||||
AP_INIT_TAKE1( MD_CMD_RENEWWINDOW, md_config_set_renew_window, NULL, RSRC_CONF,
|
AP_INIT_TAKE1( MD_CMD_RENEWWINDOW, md_config_set_renew_window, NULL, RSRC_CONF,
|
||||||
@@ -654,6 +750,8 @@ int md_config_geti(const md_srv_conf_t *sc, md_config_var_t var)
|
|||||||
apr_interval_time_t md_config_get_interval(const md_srv_conf_t *sc, md_config_var_t var)
|
apr_interval_time_t md_config_get_interval(const md_srv_conf_t *sc, md_config_var_t var)
|
||||||
{
|
{
|
||||||
switch (var) {
|
switch (var) {
|
||||||
|
case MD_CONFIG_RENEW_NORM:
|
||||||
|
return (sc->renew_norm != DEF_VAL)? sc->renew_norm : defconf.renew_norm;
|
||||||
case MD_CONFIG_RENEW_WINDOW:
|
case MD_CONFIG_RENEW_WINDOW:
|
||||||
return (sc->renew_window != DEF_VAL)? sc->renew_window : defconf.renew_window;
|
return (sc->renew_window != DEF_VAL)? sc->renew_window : defconf.renew_window;
|
||||||
default:
|
default:
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#define mod_md_md_config_h
|
#define mod_md_md_config_h
|
||||||
|
|
||||||
struct md_store_t;
|
struct md_store_t;
|
||||||
|
struct md_pkey_spec_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MD_CONFIG_CA_URL,
|
MD_CONFIG_CA_URL,
|
||||||
@@ -26,6 +27,7 @@ typedef enum {
|
|||||||
MD_CONFIG_DRIVE_MODE,
|
MD_CONFIG_DRIVE_MODE,
|
||||||
MD_CONFIG_LOCAL_80,
|
MD_CONFIG_LOCAL_80,
|
||||||
MD_CONFIG_LOCAL_443,
|
MD_CONFIG_LOCAL_443,
|
||||||
|
MD_CONFIG_RENEW_NORM,
|
||||||
MD_CONFIG_RENEW_WINDOW,
|
MD_CONFIG_RENEW_WINDOW,
|
||||||
MD_CONFIG_TRANSITIVE,
|
MD_CONFIG_TRANSITIVE,
|
||||||
} md_config_var_t;
|
} md_config_var_t;
|
||||||
@@ -51,6 +53,10 @@ typedef struct md_srv_conf_t {
|
|||||||
int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */
|
int transitive; /* != 0 iff VirtualHost names/aliases are auto-added */
|
||||||
int drive_mode; /* mode of obtaining credentials */
|
int drive_mode; /* mode of obtaining credentials */
|
||||||
int must_staple; /* certificates should set the OCSP Must Staple extension */
|
int must_staple; /* certificates should set the OCSP Must Staple extension */
|
||||||
|
struct md_pkey_spec_t *pkey_spec; /* specification for generating private keys */
|
||||||
|
apr_interval_time_t renew_norm; /* If > 0, use as normalizing value for cert lifetime
|
||||||
|
* Example: renew_norm=90d renew_win=30d, cert lives
|
||||||
|
* for 12 days => renewal 4 days before */
|
||||||
apr_interval_time_t renew_window; /* time before expiration that starts renewal */
|
apr_interval_time_t renew_window; /* time before expiration that starts renewal */
|
||||||
|
|
||||||
const char *ca_url; /* url of CA certificate service */
|
const char *ca_url; /* url of CA certificate service */
|
||||||
|
@@ -34,7 +34,7 @@
|
|||||||
#include "md_util.h"
|
#include "md_util.h"
|
||||||
#include "mod_md_os.h"
|
#include "mod_md_os.h"
|
||||||
|
|
||||||
apr_status_t md_try_chown(const char *fname, int uid, int gid, apr_pool_t *p)
|
apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool_t *p)
|
||||||
{
|
{
|
||||||
#if AP_NEED_SET_MUTEX_PERMS
|
#if AP_NEED_SET_MUTEX_PERMS
|
||||||
if (-1 == chown(fname, (uid_t)uid, (gid_t)gid)) {
|
if (-1 == chown(fname, (uid_t)uid, (gid_t)gid)) {
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
* Try chown'ing the file/directory. Give id -1 to not change uid/gid.
|
* Try chown'ing the file/directory. Give id -1 to not change uid/gid.
|
||||||
* Will return APR_ENOTIMPL on platforms not supporting this operation.
|
* Will return APR_ENOTIMPL on platforms not supporting this operation.
|
||||||
*/
|
*/
|
||||||
apr_status_t md_try_chown(const char *fname, int uid, int gid, apr_pool_t *p);
|
apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool_t *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a file or directory read/write(/searchable) by httpd workers.
|
* Make a file or directory read/write(/searchable) by httpd workers.
|
||||||
|
@@ -1723,8 +1723,9 @@ static apr_status_t ssl_init_server_ctx(server_rec *s,
|
|||||||
else if (APR_STATUS_IS_EAGAIN(rv)) {
|
else if (APR_STATUS_IS_EAGAIN(rv)) {
|
||||||
/* Managed Domain not ready yet. This is not a reason to fail the config */
|
/* Managed Domain not ready yet. This is not a reason to fail the config */
|
||||||
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085)
|
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085)
|
||||||
"Init: (%s) disabling this host for now as certificate/key data "
|
"Init: %s will respond with '503 Service Unavailable' for now. This "
|
||||||
"for the Managed Domain is incomplete.", ssl_util_vhostid(p, s));
|
"host is part of a Managed Domain, but no SSL certificate is "
|
||||||
|
"available (yet).", ssl_util_vhostid(p, s));
|
||||||
pks->service_unavailable = 1;
|
pks->service_unavailable = 1;
|
||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user