kx509: add time-to-live for kx509 -t option

It's useful to check for having so many seconds left in useful
credential lifetime.
This commit is contained in:
Nicolas Williams
2019-10-10 15:17:04 -05:00
parent 94bf464f8d
commit 0cc708ba36
3 changed files with 83 additions and 30 deletions

View File

@@ -270,8 +270,8 @@ command = {
option = {
long = "test"
short = "t"
type = "flag"
help = "exit successfully if certificate and private key are in credential cache"
type = "integer"
help = "check for certificate with at least given time left"
}
option = {
name = "private-key"

View File

@@ -56,8 +56,8 @@
.Fl Fl extract
.Xc
.Oc
.Oo Fl t \*(Ba Xo
.Fl Fl test
.Oo Fl t Ar time-left \*(Ba Xo
.Fl Fl test= Ns Ar time-left
.Xc
.Oc
.Oo Fl C Ar PKCS10:filename \*(Ba Xo
@@ -89,9 +89,14 @@ Options supported:
.It Fl c Ar cache , Fl Fl cache= Ns Ar cache
credential cache to use (if not given, then the default will be
used).
.It Fl t , Fl Fl test
.It Fl t Ar time-left , Fl Fl test= Ns Ar time-left
Test for there being an active and valid certificate in the
credential cache.
credential cache, with at least
.Ar time-left
seconds left of valid life. If given with the
.Fl o
then the certificates in the hx509 store are tested along with
those in the credentials cache (if any).
.It Fl x , Fl Fl extract
Extract, rather than acquire credentials.
.It Fl s , Fl Fl save

View File

@@ -39,14 +39,30 @@
#include "../lib/krb5/krb5_locl.h"
#include "hx509-private.h"
struct validate_store {
size_t ncerts;
int grace;
};
static int
validate1(hx509_context hx509ctx, void *d, hx509_cert cert)
{
struct validate_store *v = d;
if (hx509_cert_get_notAfter(cert) < time(NULL) + v->grace)
return HX509_CERT_USED_AFTER_TIME;
v->ncerts++;
return 0;
}
static void
validate(krb5_context context,
int grace,
const char *hx509_store,
krb5_data *der_cert,
krb5_data *pkcs8_priv_key)
{
hx509_context hx509ctx = NULL;
hx509_private_key key = NULL;
hx509_cert cert;
krb5_error_code ret;
@@ -54,19 +70,44 @@ validate(krb5_context context,
if (ret)
krb5_err(context, 1, ret, "hx509 context init");
cert = hx509_cert_init_data(hx509ctx, der_cert->data,
der_cert->length, NULL);
if (cert == NULL)
krb5_err(context, 1, errno, "certificate could not be loaded");
ret = hx509_parse_private_key(hx509ctx, NULL, pkcs8_priv_key->data,
pkcs8_priv_key->length,
HX509_KEY_FORMAT_PKCS8, &key);
if (ret)
krb5_err(context, 1, ret, "certificate could not be loaded");
if (hx509_cert_get_notAfter(cert) < time(NULL))
krb5_errx(context, 1, "certificate is expired");
hx509_private_key_free(&key);
hx509_cert_free(cert);
if (der_cert->data && pkcs8_priv_key->data) {
hx509_private_key key = NULL;
cert = hx509_cert_init_data(hx509ctx, der_cert->data,
der_cert->length, NULL);
if (cert == NULL)
krb5_err(context, 1, errno, "certificate could not be loaded");
ret = hx509_parse_private_key(hx509ctx, NULL, pkcs8_priv_key->data,
pkcs8_priv_key->length,
HX509_KEY_FORMAT_PKCS8, &key);
if (ret)
krb5_err(context, 1, ret, "certificate could not be loaded");
if (hx509_cert_get_notAfter(cert) < time(NULL) + grace)
krb5_errx(context, 1, "certificate is expired");
hx509_private_key_free(&key);
hx509_cert_free(cert);
}
if (hx509_store) {
struct validate_store v;
hx509_certs certs;
v.ncerts = 0;
v.grace = grace;
ret = hx509_certs_init(hx509ctx, hx509_store, 0, NULL, &certs);
if (ret)
krb5_err(context, 1, ret, "could not read hx509 store %s",
hx509_store);
ret = hx509_certs_iter_f(hx509ctx, certs, validate1, &v);
if (ret)
krb5_err(context, 1, ret, "at least one certificate in %s expired",
hx509_store);
if (!v.ncerts)
krb5_errx(context, 1, "no certificates in %s", hx509_store);
hx509_certs_free(&certs);
}
hx509_context_free(&hx509ctx);
}
@@ -124,7 +165,8 @@ store(krb5_context context,
hx509_store = krb5_config_get_string(context, NULL, "libdefaults",
"kx509_store", NULL);
if (hx509_store) {
ret = _krb5_expand_path_tokens(context, hx509_store, 1, &store_exp);
ret = _krb5_expand_path_tokens(context, hx509_store, 1,
&store_exp);
if (ret)
krb5_err(context, 1, ret, "expanding tokens in default "
"hx509 store");
@@ -202,28 +244,32 @@ kx509(struct kx509_options *opt, int argc, char **argv)
if (opt->save_flag)
ccout = cc;
if (opt->test_flag &&
if (opt->test_integer &&
(opt->extract_flag || opt->csr_string || opt->private_key_string))
krb5_errx(context, 1, "--test is exclusive of --extract, --csr, and "
"--private-key");
if (opt->extract_flag && (opt->csr_string || opt->private_key_string))
krb5_errx(context, 1, "--extract is exclusive of --csr and --private-key");
krb5_errx(context, 1, "--extract is exclusive of --csr and "
"--private-key");
if (opt->test_flag || opt->extract_flag) {
if (opt->test_integer || opt->extract_flag) {
krb5_data der_cert, pkcs8_key, chain;
der_cert.data = pkcs8_key.data = chain.data = NULL;
der_cert.length = pkcs8_key.length = chain.length = 0;
ret = krb5_cc_get_config(context, cc, NULL, "kx509cert", &der_cert);
if (ret == 0)
ret = krb5_cc_get_config(context, cc, NULL, "kx509key", &pkcs8_key);
ret = krb5_cc_get_config(context, cc, NULL, "kx509key",
&pkcs8_key);
if (ret == 0)
ret = krb5_cc_get_config(context, cc, NULL, "kx509cert-chain", &chain);
ret = krb5_cc_get_config(context, cc, NULL, "kx509cert-chain",
&chain);
if (ret)
krb5_err(context, 1, ret, "no certificate in credential cache");
if (opt->test_flag)
validate(context, opt->out_string, &der_cert, &pkcs8_key);
if (opt->test_integer)
validate(context, opt->test_integer, opt->out_string, &der_cert,
&pkcs8_key);
else
store(context, opt->out_string, &der_cert, &pkcs8_key, &chain);
krb5_data_free(&pkcs8_key);
@@ -240,13 +286,15 @@ kx509(struct kx509_options *opt, int argc, char **argv)
if (ret == 0 && opt->csr_string)
set_csr(context, req, opt->csr_string);
if (ret == 0 && opt->private_key_string)
ret = krb5_kx509_ctx_set_key(context, req, opt->private_key_string);
ret = krb5_kx509_ctx_set_key(context, req,
opt->private_key_string);
if (ret)
krb5_err(context, 1, ret, "could not setup kx509 request options");
ret = krb5_kx509_ext(context, req, cc, opt->out_string, ccout);
if (ret)
krb5_err(context, 1, ret, "could not acquire certificate with kx509");
krb5_err(context, 1, ret,
"could not acquire certificate with kx509");
krb5_kx509_ctx_free(context, &req);
}