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

@@ -58,6 +58,7 @@ struct hx509_ca_tbs {
} flags;
time_t notBefore;
time_t notAfter;
HeimPkinitPrincMaxLifeSecs pkinitTicketMaxLife;
int pathLenConstraint; /* both for CA and Proxy */
CRLDistributionPoints crldp;
heim_bit_string subjectUniqueID;
@@ -186,6 +187,15 @@ hx509_ca_tbs_set_notAfter_lifetime(hx509_context context,
return hx509_ca_tbs_set_notAfter(context, tbs, time(NULL) + delta);
}
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_ca_tbs_set_pkinit_max_life(hx509_context context,
hx509_ca_tbs tbs,
time_t max_life)
{
tbs->pkinitTicketMaxLife = max_life;
return 0;
}
static const struct units templatebits[] = {
{ "ExtendedKeyUsage", HX509_CA_TEMPLATE_EKU },
{ "KeyUsage", HX509_CA_TEMPLATE_KU },
@@ -194,6 +204,7 @@ static const struct units templatebits[] = {
{ "notBefore", HX509_CA_TEMPLATE_NOTBEFORE },
{ "serial", HX509_CA_TEMPLATE_SERIAL },
{ "subject", HX509_CA_TEMPLATE_SUBJECT },
{ "pkinitMaxLife", HX509_CA_TEMPLATE_PKINIT_MAX_LIFE },
{ NULL, 0 }
};
@@ -285,6 +296,12 @@ hx509_ca_tbs_set_template(hx509_context context,
}
free_ExtKeyUsage(&eku);
}
if (flags & HX509_CA_TEMPLATE_PKINIT_MAX_LIFE) {
time_t max_life;
if ((max_life = hx509_cert_get_pkinit_max_life(context, cert, 0)) > 0)
hx509_ca_tbs_set_pkinit_max_life(context, tbs, max_life);
}
return 0;
}
@@ -1812,7 +1829,7 @@ ca_sign(hx509_context context,
goto out;
}
/* add KeyUsage */
/* Add KeyUsage */
if (KeyUsage2int(tbs->ku) > 0) {
ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length,
&tbs->ku, &size, ret);
@@ -1829,7 +1846,7 @@ ca_sign(hx509_context context,
goto out;
}
/* add ExtendedKeyUsage */
/* Add ExtendedKeyUsage */
if (tbs->eku.len > 0) {
ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
&tbs->eku, &size, ret);
@@ -1846,7 +1863,7 @@ ca_sign(hx509_context context,
goto out;
}
/* add Subject Alternative Name */
/* Add Subject Alternative Name */
if (tbs->san.len > 0) {
ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
&tbs->san, &size, ret);
@@ -1950,7 +1967,7 @@ ca_sign(hx509_context context,
goto out;
}
/* add Proxy */
/* Add Proxy */
if (tbs->flags.proxy) {
ProxyCertInfo info;
@@ -2044,6 +2061,23 @@ ca_sign(hx509_context context,
goto out;
}
/* Add Heimdal PKINIT ticket max life extension */
if (tbs->pkinitTicketMaxLife > 0) {
ASN1_MALLOC_ENCODE(HeimPkinitPrincMaxLifeSecs, data.data, data.length,
&tbs->pkinitTicketMaxLife, &size, ret);
if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
if (size != data.length)
_hx509_abort("internal ASN.1 encoder error");
ret = add_extension(context, tbsc, FALSE,
&asn1_oid_id_heim_ce_pkinit_princ_max_life, &data);
free(data.data);
if (ret)
goto out;
}
ASN1_MALLOC_ENCODE(TBSCertificate, data.data, data.length,tbsc, &size, ret);
if (ret) {
hx509_set_error_string(context, 0, ret, "malloc out of memory");