Add more hxtool EKU options, and KeyUsage too

This is necessary in order to have more control over, e.g., template
certificates for kx509.  But also it's good to have this more generally.

Some batteries not included.  Specifically: no attempt is made to validate that
given KeyUsage values are compatible with the subjectPublicKey's alrogithm and
parameters.
This commit is contained in:
Nicolas Williams
2019-06-23 14:31:13 -05:00
parent 005ba36b83
commit 859c587dc2
5 changed files with 91 additions and 29 deletions

View File

@@ -43,9 +43,9 @@
struct hx509_ca_tbs { struct hx509_ca_tbs {
hx509_name subject; hx509_name subject;
SubjectPublicKeyInfo spki; SubjectPublicKeyInfo spki;
KeyUsage ku;
ExtKeyUsage eku; ExtKeyUsage eku;
GeneralNames san; GeneralNames san;
unsigned key_usage;
heim_integer serial; heim_integer serial;
struct { struct {
unsigned int proxy:1; unsigned int proxy:1;
@@ -262,11 +262,9 @@ hx509_ca_tbs_set_template(hx509_context context,
return ret; return ret;
} }
if (flags & HX509_CA_TEMPLATE_KU) { if (flags & HX509_CA_TEMPLATE_KU) {
KeyUsage ku; ret = _hx509_cert_get_keyusage(context, cert, &tbs->ku);
ret = _hx509_cert_get_keyusage(context, cert, &ku);
if (ret) if (ret)
return ret; return ret;
tbs->key_usage = KeyUsage2int(ku);
} }
if (flags & HX509_CA_TEMPLATE_EKU) { if (flags & HX509_CA_TEMPLATE_EKU) {
ExtKeyUsage eku; ExtKeyUsage eku;
@@ -405,6 +403,28 @@ hx509_ca_tbs_set_serialnumber(hx509_context context,
return ret; return ret;
} }
/**
* An an extended key usage to the to-be-signed certificate object.
* Duplicates will detected and not added.
*
* @param context A hx509 context.
* @param tbs object to be signed.
* @param oid extended key usage to add.
*
* @return An hx509 error code, see hx509_get_error_string().
*
* @ingroup hx509_ca
*/
HX509_LIB_FUNCTION int HX509_LIB_CALL
hx509_ca_tbs_add_ku(hx509_context context,
hx509_ca_tbs tbs,
KeyUsage ku)
{
tbs->ku = ku;
return 0;
}
/** /**
* An an extended key usage to the to-be-signed certificate object. * An an extended key usage to the to-be-signed certificate object.
* Duplicates will detected and not added. * Duplicates will detected and not added.
@@ -1033,7 +1053,6 @@ ca_sign(hx509_context context,
const AlgorithmIdentifier *sigalg; const AlgorithmIdentifier *sigalg;
time_t notBefore; time_t notBefore;
time_t notAfter; time_t notAfter;
unsigned key_usage;
sigalg = tbs->sigalg; sigalg = tbs->sigalg;
if (sigalg == NULL) if (sigalg == NULL)
@@ -1053,21 +1072,12 @@ ca_sign(hx509_context context,
if (notAfter == 0) if (notAfter == 0)
notAfter = time(NULL) + 3600 * 24 * 365; notAfter = time(NULL) + 3600 * 24 * 365;
key_usage = tbs->key_usage;
if (key_usage == 0) {
KeyUsage ku;
memset(&ku, 0, sizeof(ku));
ku.digitalSignature = 1;
ku.keyEncipherment = 1;
key_usage = KeyUsage2int(ku);
}
if (tbs->flags.ca) { if (tbs->flags.ca) {
KeyUsage ku; tbs->ku.keyCertSign = 1;
memset(&ku, 0, sizeof(ku)); tbs->ku.cRLSign = 1;
ku.keyCertSign = 1; } else if (KeyUsage2int(tbs->ku) == 0) {
ku.cRLSign = 1; tbs->ku.digitalSignature = 1;
key_usage |= KeyUsage2int(ku); tbs->ku.keyEncipherment = 1;
} }
/* /*
@@ -1237,11 +1247,9 @@ ca_sign(hx509_context context,
} }
/* add KeyUsage */ /* add KeyUsage */
{ if (KeyUsage2int(tbs->ku) > 0) {
KeyUsage ku; ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length,
&tbs->ku, &size, ret);
ku = int2KeyUsage(key_usage);
ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret);
if (ret) { if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory"); hx509_set_error_string(context, 0, ret, "Out of memory");
goto out; goto out;
@@ -1265,7 +1273,7 @@ ca_sign(hx509_context context,
} }
if (size != data.length) if (size != data.length)
_hx509_abort("internal ASN.1 encoder error"); _hx509_abort("internal ASN.1 encoder error");
ret = add_extension(context, tbsc, 0, ret = add_extension(context, tbsc, 1,
&asn1_oid_id_x509_ce_extKeyUsage, &data); &asn1_oid_id_x509_ce_extKeyUsage, &data);
free(data.data); free(data.data);
if (ret) if (ret)

View File

@@ -426,6 +426,12 @@ command = {
type = "string" type = "string"
help = "Subject DN" help = "Subject DN"
} }
option = {
long = "eku"
type = "strings"
argument = "oid-string"
help = "Add Extended Key Usage OID"
}
option = { option = {
long = "email" long = "email"
type = "strings" type = "strings"
@@ -650,6 +656,17 @@ command = {
type = "integer" type = "integer"
help = "Maximum path length (CA and proxy certificates), -1 no limit" help = "Maximum path length (CA and proxy certificates), -1 no limit"
} }
option = {
long = "eku"
type = "strings"
argument = "oid-string"
help = "Add Extended Key Usage OID"
}
option = {
long = "ku"
type = "strings"
help = "Key Usage (digitalSignature, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign, encipherOnly, decipherOnly)"
}
option = { option = {
long = "hostname" long = "hostname"
type = "strings" type = "strings"

View File

@@ -1365,6 +1365,15 @@ request_create(struct request_create_options *opt, int argc, char **argv)
hx509_err(context, 1, ret, "hx509_request_add_dns_name"); hx509_err(context, 1, ret, "hx509_request_add_dns_name");
} }
for (i = 0; i < opt->eku_strings.num_strings; i++) {
heim_oid oid;
parse_oid(opt->eku_strings.strings[i], NULL, &oid);
ret = _hx509_request_add_eku(context, req, &oid);
if (ret)
hx509_err(context, 1, ret, "hx509_request_add_eku");
}
ret = hx509_private_key2SPKI(context, signer, &key); ret = hx509_private_key2SPKI(context, signer, &key);
if (ret) if (ret)
@@ -1792,6 +1801,7 @@ hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv)
hx509_private_key cert_key = NULL; hx509_private_key cert_key = NULL;
hx509_name subject = NULL; hx509_name subject = NULL;
SubjectPublicKeyInfo spki; SubjectPublicKeyInfo spki;
size_t i;
int delta = 0; int delta = 0;
memset(&spki, 0, sizeof(spki)); memset(&spki, 0, sizeof(spki));
@@ -1803,10 +1813,8 @@ hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv)
if (opt->certificate_string == NULL) if (opt->certificate_string == NULL)
errx(1, "--certificate argument missing"); errx(1, "--certificate argument missing");
if (opt->template_certificate_string) { if (opt->template_certificate_string && opt->template_fields_string == NULL)
if (opt->template_fields_string == NULL) errx(1, "--template-certificate used but no --template-fields given");
errx(1, "--template-certificate not no --template-fields");
}
if (opt->lifetime_string) { if (opt->lifetime_string) {
delta = parse_time(opt->lifetime_string, "day"); delta = parse_time(opt->lifetime_string, "day");
@@ -1928,6 +1936,31 @@ hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv)
if (ret) if (ret)
hx509_err(context, 1, ret, "hx509_ca_tbs_init"); hx509_err(context, 1, ret, "hx509_ca_tbs_init");
for (i = 0; i < opt->eku_strings.num_strings; i++) {
heim_oid oid;
parse_oid(opt->eku_strings.strings[i], NULL, &oid);
ret = hx509_ca_tbs_add_eku(context, tbs, &oid);
if (ret)
hx509_err(context, 1, ret, "hx509_request_add_eku");
}
if (opt->ku_strings.num_strings) {
const struct units *kus = asn1_KeyUsage_units();
const struct units *kup;
uint64_t n = 0;
for (i = 0; i < opt->ku_strings.num_strings; i++) {
for (kup = kus; kup->name; kup++) {
if (strcmp(kup->name, opt->ku_strings.strings[i]))
continue;
n |= kup->mult;
break;
}
}
ret = hx509_ca_tbs_add_ku(context, tbs, int2KeyUsage(n));
if (ret)
hx509_err(context, 1, ret, "hx509_request_add_ku");
}
if (opt->signature_algorithm_string) { if (opt->signature_algorithm_string) {
const AlgorithmIdentifier *sigalg; const AlgorithmIdentifier *sigalg;
if (strcasecmp(opt->signature_algorithm_string, "rsa-with-sha1") == 0) if (strcasecmp(opt->signature_algorithm_string, "rsa-with-sha1") == 0)

View File

@@ -18,6 +18,7 @@ EXPORTS
hx509_private_key_free hx509_private_key_free
_hx509_private_key_ref _hx509_private_key_ref
_hx509_request_add_dns_name _hx509_request_add_dns_name
_hx509_request_add_eku
_hx509_request_add_email _hx509_request_add_email
_hx509_private_key_export _hx509_private_key_export
_hx509_private_key_exportable _hx509_private_key_exportable
@@ -42,6 +43,7 @@ EXPORTS
hx509_ca_sign_self hx509_ca_sign_self
hx509_ca_tbs_add_crl_dp_uri hx509_ca_tbs_add_crl_dp_uri
hx509_ca_tbs_add_eku hx509_ca_tbs_add_eku
hx509_ca_tbs_add_ku
hx509_ca_tbs_add_san_hostname hx509_ca_tbs_add_san_hostname
hx509_ca_tbs_add_san_jid hx509_ca_tbs_add_san_jid
hx509_ca_tbs_add_san_ms_upn hx509_ca_tbs_add_san_ms_upn

View File

@@ -22,6 +22,7 @@ HEIMDAL_X509_1.2 {
_hx509_private_key_oid; _hx509_private_key_oid;
_hx509_private_key_ref; _hx509_private_key_ref;
_hx509_request_add_dns_name; _hx509_request_add_dns_name;
_hx509_request_add_eku;
_hx509_request_add_email; _hx509_request_add_email;
_hx509_request_parse; _hx509_request_parse;
_hx509_request_print; _hx509_request_print;
@@ -34,6 +35,7 @@ HEIMDAL_X509_1.2 {
hx509_ca_sign_self; hx509_ca_sign_self;
hx509_ca_tbs_add_crl_dp_uri; hx509_ca_tbs_add_crl_dp_uri;
hx509_ca_tbs_add_eku; hx509_ca_tbs_add_eku;
hx509_ca_tbs_add_ku;
hx509_ca_tbs_add_san_hostname; hx509_ca_tbs_add_san_hostname;
hx509_ca_tbs_add_san_jid; hx509_ca_tbs_add_san_jid;
hx509_ca_tbs_add_san_ms_upn; hx509_ca_tbs_add_san_ms_upn;