bx509d: Allow requesting longer cert lifetimes
Add a `lifetime=NUMunit` query parameter. Also add a krb5.conf parameter to indicate whether this is allowed. We already have a max lifetime configuration parameter.
This commit is contained in:
41
kdc/bx509d.8
41
kdc/bx509d.8
@@ -113,6 +113,45 @@ Uses a thread per-client instead of as many threads as there are CPUs.
|
||||
.Xc
|
||||
verbose
|
||||
.El
|
||||
.Sh API
|
||||
This service provides an HTTP-based Certification Authority (CA).
|
||||
The protocol consists of a
|
||||
.Ar GET
|
||||
of
|
||||
.Ar /bx509
|
||||
with the base-63 encoding of a DER encoding of a PKCS#10
|
||||
.Ar CertificationRequest
|
||||
(Certificate Signing Request, or CSR) in a
|
||||
.Ar csr
|
||||
required query parameter.
|
||||
In a successful query, the response body will contain a PEM
|
||||
encoded end entity certificate and certification chain.
|
||||
.Pp
|
||||
Authentication is required.
|
||||
Unauthenticated requests will elicit a 401 response.
|
||||
.Pp
|
||||
Subject Alternative Names (SANs) and Extended Key Usage values
|
||||
may be requested, both in-band in the CSR as a requested
|
||||
extensions attribute, and/or via optional query parameters.
|
||||
.Pp
|
||||
Supported query parameters (separated by ampersands)
|
||||
.Bl -tag -width Ds -offset indent
|
||||
.It Li csr = Va <base64-encoded-DER-encoded-CSR>
|
||||
.It Li dNSName = Va <hostname>
|
||||
.It Li rfc822Name = Va <email-address>
|
||||
.It Li xMPPName = Va <XMPP-address>
|
||||
.It Li krb5PrincipalName = Va <Kerberos-principal-name>
|
||||
.It Li ms-upn = Va <UPN>
|
||||
.It Li eku = Va <OID>
|
||||
.It Li lifetime = Va <lifetime>
|
||||
.El
|
||||
.Pp
|
||||
More than one name or EKU may be requested.
|
||||
.Pp
|
||||
Certificate lifetimes are expressed as a decimal number and
|
||||
an optional unit (which defaults to
|
||||
.Dq day
|
||||
).
|
||||
.Sh ENVIRONMENT
|
||||
.Bl -tag -width Ds
|
||||
.It Ev KRB5_CONFIG
|
||||
@@ -122,6 +161,8 @@ the default being
|
||||
.Pa /etc/krb5.conf .
|
||||
.El
|
||||
.Sh FILES
|
||||
Configuration parameters are specified in
|
||||
.Ar /etc/krb5.conf .
|
||||
.Bl -tag -width Ds
|
||||
.It Pa /etc/krb5.conf
|
||||
.El
|
||||
|
11
kdc/bx509d.c
11
kdc/bx509d.c
@@ -117,6 +117,7 @@ typedef struct bx509_request_desc {
|
||||
|
||||
struct MHD_Connection *connection;
|
||||
krb5_times token_times;
|
||||
time_t req_life;
|
||||
hx509_request req;
|
||||
const char *target;
|
||||
const char *redir;
|
||||
@@ -667,6 +668,8 @@ bx509_param_cb(void *d,
|
||||
} else if (strcmp(key, "csr") == 0 && val) {
|
||||
heim_audit_addkv((heim_svc_req_desc)a->r, 0, "requested_csr", "true");
|
||||
a->ret = 0; /* Handled upstairs */
|
||||
} else if (strcmp(key, "lifetime") == 0 && val) {
|
||||
a->r->req_life = parse_time(val, "day");
|
||||
} else {
|
||||
/* Produce error for unknown params */
|
||||
heim_audit_addkv((heim_svc_req_desc)a->r, 0, "requested_unknown", "true");
|
||||
@@ -798,7 +801,8 @@ do_CA(struct bx509_request_desc *r, const char *csr)
|
||||
|
||||
/* Issue the certificate */
|
||||
ret = kdc_issue_certificate(r->context, "bx509", logfac, r->req, p,
|
||||
&r->token_times, 1 /* send_chain */, &certs);
|
||||
&r->token_times, r->req_life,
|
||||
1 /* send_chain */, &certs);
|
||||
krb5_free_principal(r->context, p);
|
||||
if (ret) {
|
||||
if (ret == KRB5KDC_ERR_POLICY || ret == EACCES)
|
||||
@@ -872,6 +876,7 @@ set_req_desc(struct MHD_Connection *connection,
|
||||
r->cname = NULL;
|
||||
r->addr = NULL;
|
||||
r->req = NULL;
|
||||
r->req_life = 0;
|
||||
r->kv = heim_array_create();
|
||||
ci = MHD_get_connection_info(connection,
|
||||
MHD_CONNECTION_INFO_CLIENT_ADDRESS);
|
||||
@@ -1268,8 +1273,8 @@ bnegotiate_do_CA(struct bx509_request_desc *r)
|
||||
/* Issue the certificate */
|
||||
if (ret == 0)
|
||||
ret = kdc_issue_certificate(r->context, "bx509", logfac, req, p,
|
||||
&r->token_times, 1 /* send_chain */,
|
||||
&certs);
|
||||
&r->token_times, 0,
|
||||
1 /* send_chain */, &certs);
|
||||
krb5_free_principal(r->context, p);
|
||||
hx509_request_free(&req);
|
||||
p = NULL;
|
||||
|
5
kdc/ca.c
5
kdc/ca.c
@@ -104,6 +104,7 @@ kdc_issue_certificate(krb5_context context,
|
||||
hx509_request req,
|
||||
krb5_principal cprinc,
|
||||
krb5_times *auth_times,
|
||||
time_t req_life,
|
||||
int send_chain,
|
||||
hx509_certs *out)
|
||||
{
|
||||
@@ -122,7 +123,9 @@ kdc_issue_certificate(krb5_context context,
|
||||
(const heim_config_binding *)cf,
|
||||
logf, req, &cprinc2,
|
||||
auth_times->starttime,
|
||||
auth_times->endtime, send_chain,
|
||||
auth_times->endtime,
|
||||
req_life,
|
||||
send_chain,
|
||||
out);
|
||||
if (ret == EACCES)
|
||||
ret = KRB5KDC_ERR_POLICY;
|
||||
|
@@ -1005,8 +1005,8 @@ _kdc_do_kx509(kx509_req_context r)
|
||||
krb5_data_zero(rep.certificate);
|
||||
krb5_ticket_get_times(r->context, ticket, &r->ticket_times);
|
||||
ret = kdc_issue_certificate(r->context, r->config->app, r->logf, r->csr,
|
||||
cprincipal, &r->ticket_times, r->send_chain,
|
||||
&certs);
|
||||
cprincipal, &r->ticket_times, 0 /*req_life*/,
|
||||
r->send_chain, &certs);
|
||||
if (ret) {
|
||||
int level = 1;
|
||||
const char *msg = krb5_get_error_message(r->context, ret);
|
||||
|
@@ -2,12 +2,15 @@
|
||||
|
||||
static int authorized_flag;
|
||||
static int help_flag;
|
||||
static char *lifetime_string;
|
||||
static const char *app_string = "kdc";
|
||||
static int version_flag;
|
||||
|
||||
struct getargs args[] = {
|
||||
{ "authorized", 'A', arg_flag, &authorized_flag,
|
||||
"Assume CSR is authorized", NULL },
|
||||
{ "lifetime", 'l', arg_string, &lifetime_string,
|
||||
"Certificate lifetime desired", "TIME" },
|
||||
{ "help", 'h', arg_flag, &help_flag,
|
||||
"Print usage message", NULL },
|
||||
{ "app", 'a', arg_string, &app_string,
|
||||
@@ -78,6 +81,7 @@ main(int argc, char **argv)
|
||||
hx509_certs certs = NULL;
|
||||
const char *argv0 = argv[0];
|
||||
const char *out = "MEMORY:junk-it";
|
||||
time_t req_life = 0;
|
||||
int optidx = 0;
|
||||
|
||||
setprogname(argv[0]);
|
||||
@@ -143,8 +147,9 @@ main(int argc, char **argv)
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.starttime = time(NULL);
|
||||
t.endtime = t.starttime + 3600;
|
||||
if ((ret = kdc_issue_certificate(context, app_string, logf, req, p, &t, 1,
|
||||
&certs)))
|
||||
req_life = lifetime_string ? parse_time(lifetime_string, "day") : 0;
|
||||
if ((ret = kdc_issue_certificate(context, app_string, logf, req, p, &t,
|
||||
req_life, 1, &certs)))
|
||||
krb5_err(context, 1, ret, "Certificate issuance failed");
|
||||
|
||||
if (argv[2])
|
||||
|
@@ -2835,6 +2835,7 @@ enomem:
|
||||
static heim_error_code
|
||||
tbs_set_times(hx509_context context,
|
||||
const heim_config_binding *cf,
|
||||
heim_log_facility *logf,
|
||||
time_t starttime,
|
||||
time_t endtime,
|
||||
time_t req_life,
|
||||
@@ -2847,15 +2848,29 @@ tbs_set_times(hx509_context context,
|
||||
time_t clamp =
|
||||
heim_config_get_time_default(context->hcontext, cf, 0,
|
||||
"max_cert_lifetime", NULL);
|
||||
int allow_more =
|
||||
heim_config_get_bool_default(context->hcontext, cf, FALSE,
|
||||
"allow_extra_lifetime", NULL);
|
||||
|
||||
if (!allow_more && fudge && now + fudge > endtime)
|
||||
allow_more = 1;
|
||||
|
||||
starttime = starttime ? starttime : now - 5 * 60;
|
||||
if (fudge && now + fudge > endtime)
|
||||
endtime = now + fudge;
|
||||
if (req_life && req_life < endtime - now)
|
||||
if (req_life > 0 && req_life < endtime - now)
|
||||
endtime = now + req_life;
|
||||
if (clamp && clamp < endtime - now)
|
||||
endtime = now + clamp;
|
||||
|
||||
if (endtime < now) {
|
||||
heim_log_msg(context->hcontext, logf, 3, NULL,
|
||||
"Endtime would be in the past");
|
||||
hx509_set_error_string(context, 0, ERANGE,
|
||||
"Endtime would be in the past");
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
hx509_ca_tbs_set_notAfter(context, tbs, endtime);
|
||||
hx509_ca_tbs_set_notBefore(context, tbs, starttime);
|
||||
return 0;
|
||||
@@ -2874,6 +2889,7 @@ _hx509_ca_issue_certificate(hx509_context context,
|
||||
KRB5PrincipalName *cprinc,
|
||||
time_t starttime,
|
||||
time_t endtime,
|
||||
time_t req_life,
|
||||
int send_chain,
|
||||
hx509_certs *out)
|
||||
{
|
||||
@@ -2995,8 +3011,8 @@ _hx509_ca_issue_certificate(hx509_context context,
|
||||
|
||||
/* Work out cert expiration */
|
||||
if (ret == 0)
|
||||
ret = tbs_set_times(context, cf, starttime, endtime,
|
||||
0 /* XXX req_life */, tbs);
|
||||
ret = tbs_set_times(context, cf, logf, starttime, endtime, req_life,
|
||||
tbs);
|
||||
|
||||
/* Expand the subjectName template in the TBS using the env */
|
||||
if (ret == 0)
|
||||
|
@@ -827,9 +827,30 @@ for non-default client and server certificates.
|
||||
and where the parameters are as follows:
|
||||
.Bl -tag -width "xxx" -offset indent
|
||||
.It Li ca = Va file
|
||||
Specifies the PEM credentials for the kx509 certification
|
||||
authority. If not specified for any specific use-case, then that
|
||||
use-case will be disabled.
|
||||
Specifies the PEM credentials for the kx509 / bx509d certification
|
||||
authority.
|
||||
If not specified for any specific use-case, then that use-case
|
||||
will be disabled.
|
||||
.It Li max_cert_lifetime = Va NUMunit
|
||||
Specifies the maximum certificate lifetime as a decimal number
|
||||
and an optional unit (the default unit is
|
||||
.Dq day
|
||||
).
|
||||
.It Li force_cert_lifetime = Va NUMunit
|
||||
Specifies a minimum certificate lifetime as a decimal number and
|
||||
an optional unit (the default unit is
|
||||
.Dq day
|
||||
).
|
||||
.It Li allow_extra_lifetime = Va boolean
|
||||
Indicates whether a client may request longer lifetimes than
|
||||
their authentication credentials.
|
||||
Defaults to false.
|
||||
If a
|
||||
.Li force_cert_lifetime
|
||||
is specified, then
|
||||
.Li allow_extra_lifetime
|
||||
is implicitly forced to
|
||||
.Va true .
|
||||
.It Li require_initial_kca_tickets = Va boolean
|
||||
Specified whether to require that tickets for the
|
||||
.Li kca_service
|
||||
|
Reference in New Issue
Block a user