hx509: Add Heimdal cert ext for ticket max_life

This adds support for using a Heimdal-specific PKIX extension to derive
a maximum Kerberos ticket lifetime from a client's PKINIT certificate:

 - a `--pkinit-max-life` to the `hxtool ca` command
 - `hx509_ca_tbs_set_pkinit_max_life()`
 - `hx509_cert_get_pkinit_max_life()`
 - `HX509_CA_TEMPLATE_PKINIT_MAX_LIFE`

There are two extensions.  One is an EKU, which if present means that
the maximum ticket lifetime should be derived from the notAfter minus
notBefore.  The other is a certificate extension whose value is a
maximum ticket lifetime in seconds.  The latter is preferred.
This commit is contained in:
Nicolas Williams
2021-03-24 15:57:15 -05:00
parent f0e628c2cf
commit 15b2094079
7 changed files with 112 additions and 4 deletions

View File

@@ -1633,6 +1633,63 @@ hx509_cert_get_notAfter(hx509_cert p)
return _hx509_Time2time_t(&p->data->tbsCertificate.validity.notAfter);
}
/**
* Get a maximum Kerberos credential lifetime from a Heimdal certificate
* extension.
*
* @param context hx509 context.
* @param cert Certificate.
* @param bound If larger than zero, return no more than this.
*
* @return maximum ticket lifetime.
*/
HX509_LIB_FUNCTION time_t HX509_LIB_CALL
hx509_cert_get_pkinit_max_life(hx509_context context,
hx509_cert cert,
time_t bound)
{
HeimPkinitPrincMaxLifeSecs r = 0;
size_t sz, i;
time_t b, e;
int ret;
for (i = 0; i < cert->data->tbsCertificate.extensions->len; i++) {
Extension *ext = &cert->data->tbsCertificate.extensions->val[i];
if (ext->_ioschoice_extnValue.element !=
choice_Extension_iosnumunknown &&
ext->_ioschoice_extnValue.element !=
choice_Extension_iosnum_id_heim_ce_pkinit_princ_max_life)
continue;
if (ext->_ioschoice_extnValue.element == choice_Extension_iosnumunknown &&
der_heim_oid_cmp(&asn1_oid_id_heim_ce_pkinit_princ_max_life, &ext->extnID))
continue;
if (ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife) {
r = *ext->_ioschoice_extnValue.u.ext_HeimPkinitPrincMaxLife;
} else {
ret = decode_HeimPkinitPrincMaxLifeSecs(ext->extnValue.data,
ext->extnValue.length,
&r, &sz);
/* No need to free_HeimPkinitPrincMaxLifeSecs(); it's an int */
if (ret || r < 1)
return 0;
}
if (bound > 0 && r > bound)
return bound;
return r;
}
if (hx509_cert_check_eku(context, cert,
&asn1_oid_id_heim_eku_pkinit_certlife_is_max_life, 0))
return 0;
b = hx509_cert_get_notBefore(cert);
e = hx509_cert_get_notAfter(cert);
if (e > b)
r = e - b;
if (bound > 0 && r > bound)
return bound;
return r;
}
/**
* Get the SubjectPublicKeyInfo structure from the hx509 certificate.
*