summaryrefslogtreecommitdiffstats
path: root/source4/heimdal/lib/hx509/print.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/hx509/print.c')
-rw-r--r--source4/heimdal/lib/hx509/print.c401
1 files changed, 344 insertions, 57 deletions
diff --git a/source4/heimdal/lib/hx509/print.c b/source4/heimdal/lib/hx509/print.c
index 802ac12b4e7..dc9d4cfa58c 100644
--- a/source4/heimdal/lib/hx509/print.c
+++ b/source4/heimdal/lib/hx509/print.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004 - 2006 Kungliga Tekniska Högskolan
+ * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -32,7 +32,7 @@
*/
#include "hx_locl.h"
-RCSID("$Id: print.c,v 1.15 2006/12/07 20:37:57 lha Exp $");
+RCSID("$Id: print.c 20908 2007-06-05 02:59:33Z lha $");
struct hx509_validate_ctx_data {
@@ -41,6 +41,18 @@ struct hx509_validate_ctx_data {
void *ctx;
};
+struct cert_status {
+ unsigned int selfsigned:1;
+ unsigned int isca:1;
+ unsigned int isproxy:1;
+ unsigned int haveSAN:1;
+ unsigned int haveIAN:1;
+ unsigned int haveSKI:1;
+ unsigned int haveAKI:1;
+ unsigned int haveCRLDP:1;
+};
+
+
/*
*
*/
@@ -155,10 +167,16 @@ validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...)
va_end(va);
}
+/*
+ * Dont Care, SHOULD critical, SHOULD NOT critical, MUST critical,
+ * MUST NOT critical
+ */
enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C };
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) {
case D_C:
@@ -191,13 +209,96 @@ check_Null(hx509_validate_ctx ctx, enum critical_flag cf, const Extension *e)
static int
check_subjectKeyIdentifier(hx509_validate_ctx ctx,
+ struct cert_status *status,
enum critical_flag cf,
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");
+
+ {
+ char *id;
+ hex_encode(si.data, si.length, &id);
+ if (id) {
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "\tsubject key id: %s\n", id);
+ free(id);
+ }
+ }
+
+ free_SubjectKeyIdentifier(&si);
+
+ return 0;
+}
+
+static int
+check_authorityKeyIdentifier(hx509_validate_ctx ctx,
+ struct cert_status *status,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ AuthorityKeyIdentifier ai;
+ size_t size;
+ int ret;
+
+ status->haveAKI = 1;
+ check_Null(ctx, status, cf, e);
+
+ status->haveSKI = 1;
+ check_Null(ctx, status, cf, e);
+
+ ret = decode_AuthorityKeyIdentifier(e->extnValue.data,
+ e->extnValue.length,
+ &ai, &size);
+ if (ret) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Decoding AuthorityKeyIdentifier 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 (ai.keyIdentifier) {
+ char *id;
+ hex_encode(ai.keyIdentifier->data, ai.keyIdentifier->length, &id);
+ if (id) {
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "\tauthority key id: %s\n", id);
+ free(id);
+ }
+ }
+
return 0;
}
+
static int
check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
{
@@ -206,15 +307,16 @@ check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
size_t size;
int ret;
- ret = decode_KRB5PrincipalName(a->data, a->length,
- &kn, &size);
+ ret = decode_KRB5PrincipalName(a->data, a->length, &kn, &size);
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;
}
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;
}
@@ -233,22 +335,117 @@ check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
}
static int
-check_dnssrv_san(hx509_validate_ctx ctx, heim_any *a)
+check_utf8_string_san(hx509_validate_ctx ctx, heim_any *a)
{
+ PKIXXmppAddr jid;
+ size_t size;
+ int ret;
+
+ ret = decode_PKIXXmppAddr(a->data, a->length, &jid, &size);
+ if (ret) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Decoding JID in SAN failed: %d", ret);
+ return 1;
+ }
+
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", jid);
+ free_PKIXXmppAddr(&jid);
+
return 0;
}
+static int
+check_altnull(hx509_validate_ctx ctx, heim_any *a)
+{
+ return 0;
+}
+
+static int
+check_CRLDistributionPoints(hx509_validate_ctx ctx,
+ struct cert_status *status,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ CRLDistributionPoints dp;
+ size_t size;
+ int ret, i;
+
+ check_Null(ctx, status, cf, e);
+
+ ret = decode_CRLDistributionPoints(e->extnValue.data,
+ e->extnValue.length,
+ &dp, &size);
+ if (ret) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Decoding CRL Distribution Points failed: %d\n", ret);
+ return 1;
+ }
+
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "CRL Distribution Points:\n");
+ for (i = 0 ; i < dp.len; i++) {
+ if (dp.val[i].distributionPoint) {
+ DistributionPointName dpname;
+ heim_any *data = dp.val[i].distributionPoint;
+ int j;
+
+ ret = decode_DistributionPointName(data->data, data->length,
+ &dpname, NULL);
+ if (ret) {
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Failed to parse CRL Distribution Point Name: %d\n", ret);
+ continue;
+ }
+
+ switch (dpname.element) {
+ case choice_DistributionPointName_fullName:
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Fullname:\n");
+
+ for (j = 0 ; j < dpname.u.fullName.len; j++) {
+ char *s;
+ GeneralName *name = &dpname.u.fullName.val[j];
+
+ ret = hx509_general_name_unparse(name, &s);
+ if (ret == 0 && s != NULL) {
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " %s\n", s);
+ free(s);
+ }
+ }
+ break;
+ case choice_DistributionPointName_nameRelativeToCRLIssuer:
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "Unknown nameRelativeToCRLIssuer");
+ break;
+ default:
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Unknown DistributionPointName");
+ break;
+ }
+ free_DistributionPointName(&dpname);
+ }
+ }
+ free_CRLDistributionPoints(&dp);
+
+ status->haveCRLDP = 1;
+
+ return 0;
+}
+
+
struct {
const char *name;
const heim_oid *(*oid)(void);
int (*func)(hx509_validate_ctx, heim_any *);
} check_altname[] = {
{ "pk-init", oid_id_pkinit_san, check_pkinit_san },
- { "dns-srv", oid_id_pkix_on_dnsSRV, check_dnssrv_san }
+ { "jabber", oid_id_pkix_on_xmppAddr, check_utf8_string_san },
+ { "dns-srv", oid_id_pkix_on_dnsSRV, check_altnull },
+ { "card-id", oid_id_uspkicommon_card_id, check_altnull },
+ { "Microsoft NT-PRINCIPAL-NAME", oid_id_pkinit_ms_san, check_utf8_string_san }
};
static int
check_altName(hx509_validate_ctx ctx,
+ struct cert_status *status,
const char *name,
enum critical_flag cf,
const Extension *e)
@@ -257,20 +454,24 @@ check_altName(hx509_validate_ctx ctx,
size_t size;
int ret, i;
- check_Null(ctx, cf, e);
+ check_Null(ctx, status, cf, e);
if (e->extnValue.length == 0) {
- printf("%sAltName empty, not allowed", name);
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "%sAltName empty, not allowed", name);
return 1;
}
ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length,
&gn, &size);
if (ret) {
- printf("\tret = %d while decoding %s GeneralNames\n", ret, name);
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "\tret = %d while decoding %s GeneralNames\n",
+ ret, name);
return 1;
}
if (gn.len == 0) {
- printf("%sAltName generalName empty, not allowed", name);
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "%sAltName generalName empty, not allowed\n", name);
return 1;
}
@@ -278,7 +479,9 @@ check_altName(hx509_validate_ctx ctx,
switch (gn.val[i].element) {
case choice_GeneralName_otherName: {
unsigned j;
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%sAltName otherName ", name);
+
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "%sAltName otherName ", name);
for (j = 0; j < sizeof(check_altname)/sizeof(check_altname[0]); j++) {
if (der_heim_oid_cmp((*check_altname[j].oid)(),
@@ -298,41 +501,18 @@ check_altName(hx509_validate_ctx ctx,
validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n");
break;
}
- case choice_GeneralName_rfc822Name:
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "rfc822Name: %s\n",
- gn.val[i].u.rfc822Name);
- break;
- case choice_GeneralName_dNSName:
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "dNSName: %s\n",
- gn.val[i].u.dNSName);
- break;
- case choice_GeneralName_directoryName: {
- Name dir;
+ default: {
char *s;
- dir.element = gn.val[i].u.directoryName.element;
- dir.u.rdnSequence = gn.val[i].u.directoryName.u.rdnSequence;
- ret = _hx509_unparse_Name(&dir, &s);
+ ret = hx509_general_name_unparse(&gn.val[i], &s);
if (ret) {
- printf("unable to parse %sAltName directoryName\n", name);
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "ret = %d unparsing GeneralName\n", ret);
return 1;
}
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "directoryName: %s\n", s);
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s\n", s);
free(s);
break;
}
- case choice_GeneralName_uniformResourceIdentifier:
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "uri: %s\n",
- gn.val[i].u.uniformResourceIdentifier);
- break;
- case choice_GeneralName_iPAddress:
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "ip address\n");
- break;
- case choice_GeneralName_registeredID:
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "registered id: ");
- hx509_oid_print(&gn.val[i].u.registeredID,
- validate_vprint, ctx);
- validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n");
- break;
}
}
@@ -343,23 +523,28 @@ check_altName(hx509_validate_ctx ctx,
static int
check_subjectAltName(hx509_validate_ctx ctx,
+ struct cert_status *status,
enum critical_flag cf,
const Extension *e)
{
- return check_altName(ctx, "subject", cf, e);
+ status->haveSAN = 1;
+ return check_altName(ctx, status, "subject", cf, e);
}
static int
check_issuerAltName(hx509_validate_ctx ctx,
+ struct cert_status *status,
enum critical_flag cf,
const Extension *e)
{
- return check_altName(ctx, "issuer", cf, e);
+ status->haveIAN = 1;
+ return check_altName(ctx, status, "issuer", cf, e);
}
static int
check_basicConstraints(hx509_validate_ctx ctx,
+ struct cert_status *status,
enum critical_flag cf,
const Extension *e)
{
@@ -367,7 +552,7 @@ check_basicConstraints(hx509_validate_ctx ctx,
size_t size;
int ret;
- check_Null(ctx, cf, e);
+ check_Null(ctx, status, cf, e);
ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length,
&b, &size);
@@ -384,6 +569,30 @@ check_basicConstraints(hx509_validate_ctx ctx,
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
"\tpathLenConstraint: %d\n", *b.pathLenConstraint);
+ if (b.cA) {
+ if (*b.cA) {
+ if (!e->critical)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Is a CA and not BasicConstraints CRITICAL\n");
+ status->isca = 1;
+ }
+ else
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "cA is FALSE, not allowed to be\n");
+ }
+ free_BasicConstraints(&b);
+
+ return 0;
+}
+
+static int
+check_proxyCertInfo(hx509_validate_ctx ctx,
+ struct cert_status *status,
+ enum critical_flag cf,
+ const Extension *e)
+{
+ status->isproxy = 1;
+
return 0;
}
@@ -391,6 +600,7 @@ struct {
const char *name;
const heim_oid *(*oid)(void);
int (*func)(hx509_validate_ctx ctx,
+ struct cert_status *status,
enum critical_flag cf,
const Extension *);
enum critical_flag cf;
@@ -401,7 +611,7 @@ struct {
{ ext(keyUsage, Null), S_C },
{ ext(subjectAltName, subjectAltName), M_N_C },
{ ext(issuerAltName, issuerAltName), S_N_C },
- { ext(basicConstraints, basicConstraints), M_C },
+ { ext(basicConstraints, basicConstraints), D_C },
{ ext(cRLNumber, Null), M_N_C },
{ ext(cRLReason, Null), M_N_C },
{ ext(holdInstructionCode, Null), M_N_C },
@@ -410,14 +620,20 @@ struct {
{ ext(issuingDistributionPoint, Null), M_C },
{ ext(certificateIssuer, Null), M_C },
{ ext(nameConstraints, Null), M_C },
- { ext(cRLDistributionPoints, Null), S_N_C },
+ { ext(cRLDistributionPoints, CRLDistributionPoints), S_N_C },
{ ext(certificatePolicies, Null) },
{ ext(policyMappings, Null), M_N_C },
- { ext(authorityKeyIdentifier, Null), M_N_C },
+ { ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C },
{ ext(policyConstraints, Null), D_C },
{ ext(extKeyUsage, Null), D_C },
{ ext(freshestCRL, Null), M_N_C },
{ ext(inhibitAnyPolicy, Null), M_C },
+ { "proxyCertInfo", oid_id_pe_proxyCertInfo,
+ check_proxyCertInfo, M_C },
+ { "US Fed PKI - PIV Interim", oid_id_uspkicommon_piv_interim,
+ check_Null, D_C },
+ { "Netscape cert comment", oid_id_netscape_cert_comment,
+ check_Null, D_C },
{ NULL }
};
@@ -459,31 +675,45 @@ hx509_validate_cert(hx509_context context,
{
Certificate *c = _hx509_get_cert(cert);
TBSCertificate *t = &c->tbsCertificate;
- hx509_name name;
+ hx509_name issuer, subject;
char *str;
+ struct cert_status status;
+ int ret;
+
+ memset(&status, 0, sizeof(status));
if (_hx509_cert_get_version(c) != 3)
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
"Not version 3 certificate\n");
- if (t->version && *t->version < 2 && t->extensions)
+ if ((t->version == NULL || *t->version < 2) && t->extensions)
validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
"Not version 3 certificate with extensions\n");
- _hx509_name_from_Name(&t->subject, &name);
- hx509_name_to_string(name, &str);
- hx509_name_free(&name);
+ if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Version 3 certificate without extensions\n");
+
+ ret = hx509_cert_get_subject(cert, &subject);
+ if (ret) abort();
+ hx509_name_to_string(subject, &str);
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
"subject name: %s\n", str);
free(str);
- _hx509_name_from_Name(&t->issuer, &name);
- hx509_name_to_string(name, &str);
- hx509_name_free(&name);
+ ret = hx509_cert_get_issuer(cert, &issuer);
+ if (ret) abort();
+ hx509_name_to_string(issuer, &str);
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
"issuer name: %s\n", str);
free(str);
+ if (hx509_name_cmp(subject, issuer) == 0) {
+ status.selfsigned = 1;
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "\tis a self-signed certificate\n");
+ }
+
validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
"Validity:\n");
@@ -528,11 +758,68 @@ hx509_validate_cert(hx509_context context,
"checking extention: %s\n",
check_extension[j].name);
(*check_extension[j].func)(ctx,
+ &status,
check_extension[j].cf,
&t->extensions->val[i]);
}
} else
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");
+
+ } 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");
+
+ if (status.isproxy && status.isca)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Proxy and CA at the same time!\n");
+
+ if (status.isproxy) {
+ if (status.haveSAN)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Proxy and have SAN\n");
+ if (status.haveIAN)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Proxy and have IAN\n");
+ }
+
+ if (hx509_name_is_null_p(subject) && !status.haveSAN)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "NULL subject DN and doesn't have a SAN\n");
+
+ if (!status.selfsigned && !status.haveCRLDP)
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Not a CA nor PROXY and doesn't have"
+ "CRL Dist Point\n");
+
+ if (status.selfsigned) {
+ ret = _hx509_verify_signature_bitstring(context,
+ c,
+ &c->signatureAlgorithm,
+ &c->tbsCertificate._save,
+ &c->signatureValue);
+ if (ret == 0)
+ validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
+ "Self-signed certificate was self-signed\n");
+ else
+ validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
+ "Self-signed certificate NOT really self-signed!\n");
+ }
+
+ hx509_name_free(&subject);
+ hx509_name_free(&issuer);
+
return 0;
}