Add eku, ku and san to the certificate.

git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@19580 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
Love Hörnquist Åstrand
2006-12-30 14:49:37 +00:00
parent b5c3feb43f
commit 993dacac92
2 changed files with 267 additions and 27 deletions

View File

@@ -32,15 +32,13 @@
*/
#include "hx_locl.h"
#include <pkinit_asn1.h>
RCSID("$Id$");
struct hx509_ca_tbs {
hx509_name subject;
SubjectPublicKeyInfo spki;
struct {
ExtKeyUsage *val;
size_t len;
} eku;
ExtKeyUsage eku;
GeneralNames san;
unsigned key_usage;
struct {
@@ -72,16 +70,12 @@ hx509_ca_tbs_init(hx509_context context, hx509_ca_tbs *tbs)
void
hx509_ca_tbs_free(hx509_ca_tbs *tbs)
{
size_t i;
if (tbs == NULL || *tbs == NULL)
return;
free_SubjectPublicKeyInfo(&(*tbs)->spki);
free_GeneralNames(&(*tbs)->san);
for (i = 0; i < (*tbs)->eku.len; i++)
free_ExtKeyUsage(&(*tbs)->eku.val[i]);
free((*tbs)->eku.val);
free_ExtKeyUsage(&(*tbs)->eku);
hx509_name_free(&(*tbs)->subject);
@@ -102,6 +96,130 @@ hx509_ca_tbs_set_spki(hx509_context contex,
return ret;
}
int
hx509_ca_tbs_add_eku(hx509_context contex,
hx509_ca_tbs tbs,
const heim_oid *oid)
{
void *ptr;
int ret;
ptr = realloc(tbs->eku.val, sizeof(tbs->eku.val[0]) * (tbs->eku.len + 1));
if (ptr == NULL)
return ENOMEM;
tbs->eku.val = ptr;
ret = der_copy_oid(oid, &tbs->eku.val[tbs->eku.len]);
if (ret)
return ret;
tbs->eku.len += 1;
return 0;
}
int
hx509_ca_tbs_add_san_otherName(hx509_context context,
hx509_ca_tbs tbs,
const heim_oid *oid,
const heim_octet_string *os)
{
GeneralName gn;
memset(&gn, 0, sizeof(gn));
gn.element = choice_GeneralName_otherName;
gn.u.otherName.type_id = *oid;
gn.u.otherName.value = *os;
return add_GeneralNames(&tbs->san, &gn);
}
int
hx509_ca_tbs_add_san_pkinit(hx509_context context,
hx509_ca_tbs tbs,
const char *principal)
{
heim_octet_string os;
KRB5PrincipalName p;
size_t size;
int ret;
char *s = NULL;
memset(&p, 0, sizeof(p));
/* parse principal */
{
const char *str;
char *q;
int n;
/* count number of component */
n = 1;
for(str = principal; *str != '\0' && *str != '@'; str++){
if(*str=='\\'){
if(str[1] == '\0' || str[1] == '@') {
ret = EINVAL;
hx509_set_error_string(context, 0, ret,
"trailing \\ in principal name");
goto out;
}
str++;
} else if(*str == '/')
n++;
}
p.principalName.name_string.val =
calloc(n, sizeof(*p.principalName.name_string.val));
if (p.principalName.name_string.val == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "malloc: out of memory");
goto out;
}
p.principalName.name_string.len = n;
p.principalName.name_type = KRB5_NT_PRINCIPAL;
q = s = strdup(principal);
if (q == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "malloc: out of memory");
goto out;
}
p.realm = strrchr(q, '@');
if (p.realm == NULL) {
ret = EINVAL;
hx509_set_error_string(context, 0, ret, "Missing @ in principal");
goto out;
};
*p.realm++ = '\0';
n = 0;
while (q) {
p.principalName.name_string.val[n++] = q;
q = strchr(q, '/');
if (q)
*q++ = '\0';
}
}
ASN1_MALLOC_ENCODE(KRB5PrincipalName, os.data, os.length, &p, &size, ret);
if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
if (size != os.length)
_hx509_abort("internal ASN.1 encoder error");
ret = hx509_ca_tbs_add_san_otherName(context,
tbs,
oid_id_pkinit_san(),
&os);
free(os.data);
out:
if (p.principalName.name_string.val)
free (p.principalName.name_string.val);
if (s)
free(s);
return ret;
}
int
hx509_ca_tbs_set_subject(hx509_context context,
hx509_ca_tbs tbs,
@@ -112,6 +230,48 @@ hx509_ca_tbs_set_subject(hx509_context context,
return hx509_name_copy(context, subject, &tbs->subject);
}
static int
add_extension(hx509_context context,
TBSCertificate *tbsc,
int critical_flag,
const heim_oid *oid,
const heim_octet_string *data)
{
Extension ext;
int ret;
memset(&ext, 0, sizeof(ext));
if (critical_flag) {
ext.critical = malloc(sizeof(*ext.critical));
if (ext.critical == NULL) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
*ext.critical = TRUE;
}
ret = der_copy_oid(oid, &ext.extnID);
if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
ret = der_copy_octet_string(data, &ext.extnValue);
if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
ret = add_Extensions(tbsc->extensions, &ext);
if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
out:
free_Extension(&ext);
return ret;
}
static int
ca_sign(hx509_context context,
hx509_ca_tbs tbs,
@@ -245,34 +405,58 @@ ca_sign(hx509_context context,
/* add KeyUsage */
{
Extension ext;
KeyUsage ku;
memset(&ext, 0, sizeof(ext));
ku = int2KeyUsage(key_usage);
ret = der_copy_oid(oid_id_x509_ce_keyUsage(), &ext.extnID);
if (ret) {
ret = ENOMEM;
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
ASN1_MALLOC_ENCODE(KeyUsage,
ext.extnValue.data,
ext.extnValue.length,
&ku, &size, ret);
ASN1_MALLOC_ENCODE(KeyUsage, data.data, data.length, &ku, &size, ret);
if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory");
goto out;
}
ret = add_Extensions(tbsc->extensions, &ext);
if (ret) {
hx509_set_error_string(context, 0, ret, "Out of memory");
if (size != data.length)
_hx509_abort("internal ASN.1 encoder error");
ret = add_extension(context, tbsc, 1,
oid_id_x509_ce_keyUsage(), &data);
free(data.data);
if (ret)
goto out;
}
/* add ExtendedKeyUsage */
if (tbs->eku.len > 0) {
ASN1_MALLOC_ENCODE(ExtKeyUsage, data.data, data.length,
&tbs->eku, &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, 0,
oid_id_x509_ce_extKeyUsage(), &data);
free(data.data);
if (ret)
goto out;
}
/* add SubjectAltName */
if (tbs->san.len > 0) {
ASN1_MALLOC_ENCODE(GeneralNames, data.data, data.length,
&tbs->san, &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, 0,
oid_id_x509_ce_subjectAltName(),
&data);
free(data.data);
if (ret)
goto out;
}
free_Extension(&ext);
}
/* X509v3 Extended Key Usage: */
/* X509v3 Subject Key Identifier: */
/* X509v3 Authority Key Identifier: */

View File

@@ -1124,6 +1124,60 @@ hxtool_hex(struct hex_options *opt, int argc, char **argv)
return 0;
}
static int
eval_types(hx509_context context,
hx509_ca_tbs tbs,
const struct certificate_sign_options *opt)
{
int pkinit = 0;
int i, ret;
for (i = 0; i < opt->type_strings.num_strings; i++) {
const char *type = opt->type_strings.strings[i];
if (strcmp(type, "https-server") == 0) {
ret = hx509_ca_tbs_add_eku(context, tbs,
oid_id_pkix_kp_serverAuth());
if (ret)
hx509_err(context, ret, 1, "hx509_ca_tbs_add_eku");
} else if (strcmp(type, "https-client") == 0) {
ret = hx509_ca_tbs_add_eku(context, tbs,
oid_id_pkix_kp_clientAuth());
if (ret)
hx509_err(context, ret, 1, "hx509_ca_tbs_add_eku");
} else if (strcmp(type, "pkinit-kdc") == 0) {
pkinit++;
ret = hx509_ca_tbs_add_eku(context, tbs,
oid_id_pkkdcekuoid());
if (ret)
hx509_err(context, ret, 1, "hx509_ca_tbs_add_eku");
} else if (strcmp(type, "pkinit-client") == 0) {
pkinit++;
ret = hx509_ca_tbs_add_eku(context, tbs,
oid_id_pkekuoid());
if (ret)
hx509_err(context, ret, 1, "hx509_ca_tbs_add_eku");
} else
errx(1, "unknown type %s", type);
}
if (pkinit > 1)
errx(1, "More the one PK-INIT type given");
if (opt->pk_init_principal_string) {
if (!pkinit)
errx(1, "pk-init principal given but no pk-init oid");
ret = hx509_ca_tbs_add_san_pkinit(context, tbs,
opt->pk_init_principal_string);
if (ret)
hx509_err(context, ret, 1, "hx509_ca_tbs_add_san_pkinit");
}
return 0;
}
int
hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv)
{
@@ -1220,6 +1274,8 @@ hxtool_ca(struct certificate_sign_options *opt, int argc, char **argv)
if (ret)
hx509_err(context, ret, 1, "hx509_ca_tbs_set_subject");
eval_types(context, tbs, opt);
ret = hx509_ca_sign(context, tbs, signer, &cert);
if (ret)
hx509_err(context, ret, 1, "hx509_ca_sign");