More validation checks.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@19816 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -41,6 +41,15 @@ struct hx509_validate_ctx_data {
|
|||||||
void *ctx;
|
void *ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cert_status {
|
||||||
|
unsigned int selfsigned:1;
|
||||||
|
unsigned int isca:1;
|
||||||
|
unsigned int haveIAN:1;
|
||||||
|
unsigned int haveSKI:1;
|
||||||
|
unsigned int haveAKI:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -158,7 +167,9 @@ validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...)
|
|||||||
enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C };
|
enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C };
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e)
|
check_Null(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
|
enum critical_flag cf, const Extension *e)
|
||||||
{
|
{
|
||||||
switch(cf) {
|
switch(cf) {
|
||||||
case D_C:
|
case D_C:
|
||||||
@@ -191,13 +202,53 @@ check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
check_subjectKeyIdentifier(hx509_validate_ctx ctx,
|
check_subjectKeyIdentifier(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
enum critical_flag cf,
|
enum critical_flag cf,
|
||||||
const Extension *e)
|
const Extension *e)
|
||||||
{
|
{
|
||||||
check_Null(ctx, cf, e);
|
SubjectKeyIdentifier si;
|
||||||
|
size_t size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
status->haveSKI = 1;
|
||||||
|
check_Null(ctx, status, cf, e);
|
||||||
|
|
||||||
|
ret = decode_SubjectKeyIdentifier(e->extnValue.data,
|
||||||
|
e->extnValue.length,
|
||||||
|
&si, &size);
|
||||||
|
if (ret) {
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"Decoding SubjectKeyIdentifier failed: %d", ret);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (size != e->extnValue.length) {
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"Decoding SKI ahve extra bits on the end");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (si.length == 0)
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"SKI is too short (0 bytes)");
|
||||||
|
if (si.length > 20)
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"SKI is too long");
|
||||||
|
free_SubjectKeyIdentifier(&si);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_authorityKeyIdentifier(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
|
enum critical_flag cf,
|
||||||
|
const Extension *e)
|
||||||
|
{
|
||||||
|
status->haveAKI = 1;
|
||||||
|
check_Null(ctx, status, cf, e);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
|
check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
|
||||||
{
|
{
|
||||||
@@ -209,12 +260,14 @@ check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
|
|||||||
ret = decode_KRB5PrincipalName(a->data, a->length,
|
ret = decode_KRB5PrincipalName(a->data, a->length,
|
||||||
&kn, &size);
|
&kn, &size);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("Decoding kerberos name in SAN failed: %d", ret);
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"Decoding kerberos name in SAN failed: %d", ret);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size != a->length) {
|
if (size != a->length) {
|
||||||
printf("Decoding kerberos name have extra bits on the end");
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"Decoding kerberos name have extra bits on the end");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +302,7 @@ struct {
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
check_altName(hx509_validate_ctx ctx,
|
check_altName(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
const char *name,
|
const char *name,
|
||||||
enum critical_flag cf,
|
enum critical_flag cf,
|
||||||
const Extension *e)
|
const Extension *e)
|
||||||
@@ -257,7 +311,7 @@ check_altName(hx509_validate_ctx ctx,
|
|||||||
size_t size;
|
size_t size;
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
check_Null(ctx, cf, e);
|
check_Null(ctx, status, cf, e);
|
||||||
|
|
||||||
if (e->extnValue.length == 0) {
|
if (e->extnValue.length == 0) {
|
||||||
printf("%sAltName empty, not allowed", name);
|
printf("%sAltName empty, not allowed", name);
|
||||||
@@ -343,23 +397,27 @@ check_altName(hx509_validate_ctx ctx,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
check_subjectAltName(hx509_validate_ctx ctx,
|
check_subjectAltName(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
enum critical_flag cf,
|
enum critical_flag cf,
|
||||||
const Extension *e)
|
const Extension *e)
|
||||||
{
|
{
|
||||||
return check_altName(ctx, "subject", cf, e);
|
return check_altName(ctx, status, "subject", cf, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_issuerAltName(hx509_validate_ctx ctx,
|
check_issuerAltName(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
enum critical_flag cf,
|
enum critical_flag cf,
|
||||||
const Extension *e)
|
const Extension *e)
|
||||||
{
|
{
|
||||||
return check_altName(ctx, "issuer", cf, e);
|
status->haveIAN = 1;
|
||||||
|
return check_altName(ctx, status, "issuer", cf, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_basicConstraints(hx509_validate_ctx ctx,
|
check_basicConstraints(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
enum critical_flag cf,
|
enum critical_flag cf,
|
||||||
const Extension *e)
|
const Extension *e)
|
||||||
{
|
{
|
||||||
@@ -367,7 +425,7 @@ check_basicConstraints(hx509_validate_ctx ctx,
|
|||||||
size_t size;
|
size_t size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
check_Null(ctx, cf, e);
|
check_Null(ctx, status, cf, e);
|
||||||
|
|
||||||
ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length,
|
ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length,
|
||||||
&b, &size);
|
&b, &size);
|
||||||
@@ -384,6 +442,14 @@ check_basicConstraints(hx509_validate_ctx ctx,
|
|||||||
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
||||||
"\tpathLenConstraint: %d\n", *b.pathLenConstraint);
|
"\tpathLenConstraint: %d\n", *b.pathLenConstraint);
|
||||||
|
|
||||||
|
if (b.cA) {
|
||||||
|
if (*b.cA)
|
||||||
|
status->isca = 1;
|
||||||
|
else
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"cA is FALSE, not allowed to be\n");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,6 +457,7 @@ struct {
|
|||||||
const char *name;
|
const char *name;
|
||||||
const heim_oid *(*oid)(void);
|
const heim_oid *(*oid)(void);
|
||||||
int (*func)(hx509_validate_ctx ctx,
|
int (*func)(hx509_validate_ctx ctx,
|
||||||
|
struct cert_status *status,
|
||||||
enum critical_flag cf,
|
enum critical_flag cf,
|
||||||
const Extension *);
|
const Extension *);
|
||||||
enum critical_flag cf;
|
enum critical_flag cf;
|
||||||
@@ -413,7 +480,7 @@ struct {
|
|||||||
{ ext(cRLDistributionPoints, Null), S_N_C },
|
{ ext(cRLDistributionPoints, Null), S_N_C },
|
||||||
{ ext(certificatePolicies, Null) },
|
{ ext(certificatePolicies, Null) },
|
||||||
{ ext(policyMappings, Null), M_N_C },
|
{ ext(policyMappings, Null), M_N_C },
|
||||||
{ ext(authorityKeyIdentifier, Null), M_N_C },
|
{ ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C },
|
||||||
{ ext(policyConstraints, Null), D_C },
|
{ ext(policyConstraints, Null), D_C },
|
||||||
{ ext(extKeyUsage, Null), D_C },
|
{ ext(extKeyUsage, Null), D_C },
|
||||||
{ ext(freshestCRL, Null), M_N_C },
|
{ ext(freshestCRL, Null), M_N_C },
|
||||||
@@ -459,31 +526,42 @@ hx509_validate_cert(hx509_context context,
|
|||||||
{
|
{
|
||||||
Certificate *c = _hx509_get_cert(cert);
|
Certificate *c = _hx509_get_cert(cert);
|
||||||
TBSCertificate *t = &c->tbsCertificate;
|
TBSCertificate *t = &c->tbsCertificate;
|
||||||
hx509_name name;
|
hx509_name issuer, subject;
|
||||||
char *str;
|
char *str;
|
||||||
|
struct cert_status status;
|
||||||
|
|
||||||
|
memset(&status, 0, sizeof(status));
|
||||||
|
|
||||||
if (_hx509_cert_get_version(c) != 3)
|
if (_hx509_cert_get_version(c) != 3)
|
||||||
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
||||||
"Not version 3 certificate\n");
|
"Not version 3 certificate\n");
|
||||||
|
|
||||||
if (t->version && *t->version < 2 && t->extensions)
|
if ((t->version || *t->version < 2) && t->extensions)
|
||||||
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
"Not version 3 certificate with extensions\n");
|
"Not version 3 certificate with extensions\n");
|
||||||
|
|
||||||
_hx509_name_from_Name(&t->subject, &name);
|
if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL)
|
||||||
hx509_name_to_string(name, &str);
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
hx509_name_free(&name);
|
"Version 3 certificate without extensions\n");
|
||||||
|
|
||||||
|
_hx509_name_from_Name(&t->subject, &subject);
|
||||||
|
hx509_name_to_string(subject, &str);
|
||||||
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
||||||
"subject name: %s\n", str);
|
"subject name: %s\n", str);
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
_hx509_name_from_Name(&t->issuer, &name);
|
_hx509_name_from_Name(&t->issuer, &issuer);
|
||||||
hx509_name_to_string(name, &str);
|
hx509_name_to_string(issuer, &str);
|
||||||
hx509_name_free(&name);
|
|
||||||
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
||||||
"issuer name: %s\n", str);
|
"issuer name: %s\n", str);
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
|
if (hx509_name_cmp(subject, issuer) == 0)
|
||||||
|
status.selfsigned = 1;
|
||||||
|
|
||||||
|
hx509_name_free(&subject);
|
||||||
|
hx509_name_free(&issuer);
|
||||||
|
|
||||||
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
|
||||||
"Validity:\n");
|
"Validity:\n");
|
||||||
|
|
||||||
@@ -528,11 +606,33 @@ hx509_validate_cert(hx509_context context,
|
|||||||
"checking extention: %s\n",
|
"checking extention: %s\n",
|
||||||
check_extension[j].name);
|
check_extension[j].name);
|
||||||
(*check_extension[j].func)(ctx,
|
(*check_extension[j].func)(ctx,
|
||||||
|
&status,
|
||||||
check_extension[j].cf,
|
check_extension[j].cf,
|
||||||
&t->extensions->val[i]);
|
&t->extensions->val[i]);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n");
|
validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n");
|
||||||
|
|
||||||
|
if (status.isca) {
|
||||||
|
if (!status.haveSKI)
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"CA certificate have no SubjectKeyIdentifier\n");
|
||||||
|
|
||||||
|
if (!status.haveSKI)
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"CA certificate have no SubjectKeyIdentifier\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!status.haveAKI)
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"Is not CA and doesn't have "
|
||||||
|
"AuthorityKeyIdentifier\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!status.haveSKI)
|
||||||
|
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
|
||||||
|
"Doesn't have SubjectKeyIdentifier\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user