pluto's crl handling now uses the x509 plugin

This commit is contained in:
Andreas Steffen
2009-09-30 09:29:15 +02:00
parent 5406c65702
commit 0c8d08068e
3 changed files with 159 additions and 394 deletions
+5 -1
View File
@@ -168,7 +168,11 @@ static x509crl_t *builder_load_crl(certificate_type_t type, va_list args)
*crl = empty_x509crl; *crl = empty_x509crl;
crl->distributionPoints = linked_list_create(); crl->distributionPoints = linked_list_create();
if (parse_x509crl(chunk_clone(blob), 0, crl)) crl->crl = lib->creds->create(lib->creds,
CRED_CERTIFICATE, CERT_X509_CRL,
BUILD_BLOB_ASN1_DER, blob,
BUILD_END);
if (crl->crl)
{ {
return crl; return crl;
} }
+145 -354
View File
@@ -24,12 +24,6 @@
#include <freeswan.h> #include <freeswan.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <asn1/oid.h>
#include <crypto/hashers/hasher.h>
#include <credentials/certificates/certificate.h>
#include "constants.h" #include "constants.h"
#include "defs.h" #include "defs.h"
#include "log.h" #include "log.h"
@@ -47,87 +41,11 @@
static x509crl_t *x509crls = NULL; static x509crl_t *x509crls = NULL;
/**
* ASN.1 definition of an X.509 certificate revocation list
*/
static const asn1Object_t crlObjects[] = {
{ 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "version", ASN1_INTEGER, ASN1_OPT |
ASN1_BODY }, /* 2 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
{ 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
{ 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
{ 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
ASN1_LOOP }, /* 8 */
{ 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
{ 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
{ 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
{ 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
ASN1_LOOP }, /* 12 */
{ 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
{ 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
{ 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
ASN1_BODY }, /* 15 */
{ 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
{ 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
{ 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
{ 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
{ 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
ASN1_BODY }, /* 23 */
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 28 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define CRL_OBJ_CERTIFICATE_LIST 0
#define CRL_OBJ_TBS_CERT_LIST 1
#define CRL_OBJ_VERSION 2
#define CRL_OBJ_SIG_ALG 4
#define CRL_OBJ_ISSUER 5
#define CRL_OBJ_THIS_UPDATE 6
#define CRL_OBJ_NEXT_UPDATE 7
#define CRL_OBJ_USER_CERTIFICATE 10
#define CRL_OBJ_REVOCATION_DATE 11
#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
#define CRL_OBJ_EXTN_ID 22
#define CRL_OBJ_CRITICAL 23
#define CRL_OBJ_EXTN_VALUE 24
#define CRL_OBJ_ALGORITHM 27
#define CRL_OBJ_SIGNATURE 28
const x509crl_t empty_x509crl = { const x509crl_t empty_x509crl = {
NULL , /* crl */
NULL , /* *next */ NULL , /* *next */
UNDEFINED_TIME, /* installed */ UNDEFINED_TIME, /* installed */
NULL , /* distributionPoints */ NULL , /* distributionPoints */
{ NULL, 0 } , /* certificateList */
{ NULL, 0 } , /* tbsCertList */
1 , /* version */
OID_UNKNOWN , /* sigAlg */
{ NULL, 0 } , /* issuer */
UNDEFINED_TIME, /* thisUpdate */
UNDEFINED_TIME, /* nextUpdate */
NULL , /* revokedCertificates */
/* crlExtensions */
/* extension */
/* extnID */
/* critical */
/* extnValue */
{ NULL, 0 } , /* authKeyID */
{ NULL, 0 } , /* authKeySerialNumber */
{ NULL, 0 } , /* crlNumber */
OID_UNKNOWN , /* algorithm */
{ NULL, 0 } /* signature */
}; };
/** /**
@@ -135,51 +53,42 @@ const x509crl_t empty_x509crl = {
*/ */
static x509crl_t* get_x509crl(chunk_t issuer, chunk_t keyid) static x509crl_t* get_x509crl(chunk_t issuer, chunk_t keyid)
{ {
x509crl_t *crl = x509crls; x509crl_t *x509crl = x509crls;
x509crl_t *prev_crl = NULL; x509crl_t *prev_crl = NULL;
while (crl != NULL) while (x509crl != NULL)
{ {
if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL) certificate_t *cert_crl = x509crl->crl;
? same_keyid(keyid, crl->authKeyID) crl_t *crl = (crl_t*)cert_crl;
: (same_dn(crl->issuer, issuer))) identification_t *crl_issuer = cert_crl->get_issuer(cert_crl);
chunk_t crl_issuer_dn = crl_issuer->get_encoding(crl_issuer);
chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
if ((keyid.ptr && authKeyID.ptr)? same_keyid(keyid, authKeyID) :
same_dn(crl_issuer_dn, issuer))
{ {
if (crl != x509crls) if (x509crl != x509crls)
{ {
/* bring the CRL up front */ /* bring the CRL up front */
prev_crl->next = crl->next; prev_crl->next = x509crl->next;
crl->next = x509crls; x509crl->next = x509crls;
x509crls = crl; x509crls = x509crl;
} }
return crl; return x509crl;
} }
prev_crl = crl; prev_crl = x509crl;
crl = crl->next; x509crl = x509crl->next;
} }
return NULL; return NULL;
} }
/**
* Free the dynamic memory used to store revoked certificates
*/
static void free_revoked_certs(revokedCert_t* revokedCerts)
{
while (revokedCerts != NULL)
{
revokedCert_t * revokedCert = revokedCerts;
revokedCerts = revokedCert->next;
free(revokedCert);
}
}
/** /**
* Free the dynamic memory used to store CRLs * Free the dynamic memory used to store CRLs
*/ */
void free_crl(x509crl_t *crl) void free_crl(x509crl_t *crl)
{ {
DESTROY_IF(crl->crl);
crl->distributionPoints->destroy_function(crl->distributionPoints, free); crl->distributionPoints->destroy_function(crl->distributionPoints, free);
free_revoked_certs(crl->revokedCertificates);
free(crl->certificateList.ptr);
free(crl); free(crl);
} }
@@ -196,7 +105,9 @@ void free_crls(void)
lock_crl_list("free_crls"); lock_crl_list("free_crls");
while (x509crls != NULL) while (x509crls != NULL)
{
free_first_crl(); free_first_crl();
}
unlock_crl_list("free_crls"); unlock_crl_list("free_crls");
} }
@@ -204,23 +115,29 @@ void free_crls(void)
/** /**
* Insert X.509 CRL into chained list * Insert X.509 CRL into chained list
*/ */
bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl) bool insert_crl(x509crl_t *x509crl, char *crl_uri, bool cache_crl)
{ {
certificate_t *cert_crl = x509crl->crl;
crl_t *crl = (crl_t*)cert_crl;
identification_t *issuer = cert_crl->get_issuer(cert_crl);
chunk_t issuer_dn = issuer->get_encoding(issuer);
chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
x509cert_t *issuer_cert; x509cert_t *issuer_cert;
x509crl_t *oldcrl; x509crl_t *oldcrl;
time_t now, nextUpdate;
bool valid_sig; bool valid_sig;
/* add distribution point */ /* add distribution point */
add_distribution_point(crl->distributionPoints, crl_uri); add_distribution_point(x509crl->distributionPoints, crl_uri);
lock_authcert_list("insert_crl"); lock_authcert_list("insert_crl");
/* get the issuer cacert */ /* get the issuer cacert */
issuer_cert = get_authcert(crl->issuer, crl->authKeyID, AUTH_CA); issuer_cert = get_authcert(issuer_dn, authKeyID, AUTH_CA);
if (issuer_cert == NULL) if (issuer_cert == NULL)
{ {
plog("crl issuer cacert not found"); plog("crl issuer cacert not found");
free_crl(crl); free_crl(x509crl);
unlock_authcert_list("insert_crl"); unlock_authcert_list("insert_crl");
return FALSE; return FALSE;
} }
@@ -229,28 +146,32 @@ bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl)
) )
/* check the issuer's signature of the crl */ /* check the issuer's signature of the crl */
valid_sig = x509_check_signature(crl->tbsCertList, crl->signature, valid_sig = cert_crl->issued_by(cert_crl, issuer_cert->cert);
crl->algorithm, issuer_cert->cert);
unlock_authcert_list("insert_crl"); unlock_authcert_list("insert_crl");
if (!valid_sig) if (!valid_sig)
{ {
free_crl(crl); free_crl(x509crl);
return FALSE; return FALSE;
} }
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_log("crl signature is valid") DBG_log("crl signature is valid")
) )
/* note the current time */
time(&now);
lock_crl_list("insert_crl"); lock_crl_list("insert_crl");
oldcrl = get_x509crl(crl->issuer, crl->authKeyID); oldcrl = get_x509crl(issuer_dn, authKeyID);
if (oldcrl != NULL) if (oldcrl != NULL)
{ {
if (crl->thisUpdate > oldcrl->thisUpdate) certificate_t *old_cert_crl = oldcrl->crl;
if (cert_crl->is_newer(cert_crl, old_cert_crl))
{ {
/* keep any known CRL distribution points */ /* keep any known CRL distribution points */
add_distribution_points(crl->distributionPoints, add_distribution_points(x509crl->distributionPoints,
oldcrl->distributionPoints); oldcrl->distributionPoints);
/* now delete the old CRL */ /* now delete the old CRL */
@@ -265,39 +186,39 @@ bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl)
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_log("thisUpdate is not newer - existing crl not replaced"); DBG_log("thisUpdate is not newer - existing crl not replaced");
) )
free_crl(crl); free_crl(x509crl);
return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval; old_cert_crl->get_validity(old_cert_crl, &now, NULL, &nextUpdate);
return nextUpdate - now > 2*crl_check_interval;
} }
} }
/* insert new CRL */ /* insert new CRL */
crl->next = x509crls; x509crl->next = x509crls;
x509crls = crl; x509crls = x509crl;
unlock_crl_list("insert_crl"); unlock_crl_list("insert_crl");
/* If crl caching is enabled then the crl is saved locally. /* If crl caching is enabled then the crl is saved locally.
* Only http or ldap URIs are cached but not local file URIs. * Only http or ldap URIs are cached but not local file URIs.
* The issuer's subjectKeyID is used as a unique filename * The CRL's authorityKeyIdentifier is used as a unique filename
*/ */
if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0) if (cache_crl && strncasecmp(crl_uri, "file", 4) != 0)
{ {
char path[BUF_LEN], buf[BUF_LEN]; char buf[BUF_LEN];
certificate_t *certificate = issuer_cert->cert; chunk_t hex, encoding;
x509_t *x509 = (x509_t*)certificate;
chunk_t subjectKeyID;
subjectKeyID = x509->get_subjectKeyIdentifier(x509); hex = chunk_to_hex(crl->get_authKeyIdentifier(crl), NULL, FALSE);
if (subjectKeyID.ptr) snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_PATH, hex);
{ free(hex.ptr);
datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf); encoding = cert_crl->get_encoding(cert_crl);
chunk_write(crl->certificateList, path, "crl", 0022, TRUE); chunk_write(encoding, buf, "crl", 022, TRUE);
} free(encoding.ptr);
} }
/* is the fetched crl valid? */ /* is the fetched crl valid? */
return crl->nextUpdate - time(NULL) > 2*crl_check_interval; cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
return nextUpdate - now > 2*crl_check_interval;
} }
/** /**
@@ -328,17 +249,18 @@ void load_crls(void)
while (n--) while (n--)
{ {
char *filename = filelist[n]->d_name; char *filename = filelist[n]->d_name;
x509crl_t *crl; x509crl_t *x509crl;
crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE,
CERT_PLUTO_CRL, BUILD_FROM_FILE, filename, BUILD_END); CERT_PLUTO_CRL,
if (crl) BUILD_FROM_FILE, filename, BUILD_END);
if (x509crl)
{ {
char crl_uri[BUF_LEN]; char crl_uri[BUF_LEN];
plog(" loaded crl from '%s'", filename); plog(" loaded crl from '%s'", filename);
snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename); snprintf(crl_uri, BUF_LEN, "file://%s/%s", CRL_PATH, filename);
insert_crl(crl, crl_uri, FALSE); insert_crl(x509crl, crl_uri, FALSE);
} }
free(filelist[n]); free(filelist[n]);
} }
@@ -349,175 +271,38 @@ void load_crls(void)
ignore_result(chdir(save_dir)); ignore_result(chdir(save_dir));
} }
/**
* Parses a CRL revocation reason code
*/
static crl_reason_t parse_crl_reasonCode(chunk_t object)
{
crl_reason_t reason = CRL_REASON_UNSPECIFIED;
if (*object.ptr == ASN1_ENUMERATED
&& asn1_length(&object) == 1)
{
reason = *object.ptr;
}
DBG(DBG_PARSING,
DBG_log(" '%N'", crl_reason_names, reason)
)
return reason;
}
/*
* Parses an X.509 CRL
*/
bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
{
u_char buf[BUF_LEN];
asn1_parser_t *parser;
chunk_t extnID;
chunk_t userCertificate = chunk_empty;
chunk_t object;
int objectID;
bool success = FALSE;
bool critical;
parser = asn1_parser_create(crlObjects, blob);
while (parser->iterate(parser, &objectID, &object))
{
u_int level = parser->get_level(parser)+1;
switch (objectID) {
case CRL_OBJ_CERTIFICATE_LIST:
crl->certificateList = object;
break;
case CRL_OBJ_TBS_CERT_LIST:
crl->tbsCertList = object;
break;
case CRL_OBJ_VERSION:
crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
DBG(DBG_PARSING,
DBG_log(" v%d", crl->version);
)
break;
case CRL_OBJ_SIG_ALG:
crl->sigAlg = asn1_parse_algorithmIdentifier(object, level, NULL);
break;
case CRL_OBJ_ISSUER:
crl->issuer = object;
DBG(DBG_PARSING,
dntoa(buf, BUF_LEN, object);
DBG_log(" '%s'",buf)
)
break;
case CRL_OBJ_THIS_UPDATE:
crl->thisUpdate = asn1_parse_time(object, level);
break;
case CRL_OBJ_NEXT_UPDATE:
crl->nextUpdate = asn1_parse_time(object, level);
break;
case CRL_OBJ_USER_CERTIFICATE:
userCertificate = object;
break;
case CRL_OBJ_REVOCATION_DATE:
{
/* put all the serial numbers and the revocation date in a chained list
with revocedCertificates pointing to the first revoked certificate */
revokedCert_t *revokedCert = malloc_thing(revokedCert_t);
revokedCert->userCertificate = userCertificate;
revokedCert->revocationDate = asn1_parse_time(object, level);
revokedCert->revocationReason = CRL_REASON_UNSPECIFIED;
revokedCert->next = crl->revokedCertificates;
crl->revokedCertificates = revokedCert;
}
break;
case CRL_OBJ_CRL_ENTRY_EXTN_ID:
case CRL_OBJ_EXTN_ID:
extnID = object;
break;
case CRL_OBJ_CRL_ENTRY_CRITICAL:
case CRL_OBJ_CRITICAL:
critical = object.len && *object.ptr;
DBG(DBG_PARSING,
DBG_log(" %s",(critical)?"TRUE":"FALSE");
)
break;
case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
case CRL_OBJ_EXTN_VALUE:
{
u_int extn_oid = asn1_known_oid(extnID);
if (extn_oid == OID_CRL_REASON_CODE)
{
crl->revokedCertificates->revocationReason =
parse_crl_reasonCode(object);
}
else if (extn_oid == OID_AUTHORITY_KEY_ID)
{
parse_authorityKeyIdentifier(object, level
, &crl->authKeyID, &crl->authKeySerialNumber);
}
else if (extn_oid == OID_CRL_NUMBER)
{
if (!asn1_parse_simple_object(&object, ASN1_INTEGER,
level, "crlNumber"))
{
goto end;
}
crl->crlNumber = object;
}
}
break;
case CRL_OBJ_ALGORITHM:
crl->algorithm = asn1_parse_algorithmIdentifier(object, level, NULL);
break;
case CRL_OBJ_SIGNATURE:
crl->signature = object;
break;
default:
break;
}
}
success = parser->success(parser);
time(&crl->installed);
end:
parser->destroy(parser);
return success;
}
/* Checks if the current certificate is revoked. It goes through the /* Checks if the current certificate is revoked. It goes through the
* list of revoked certificates of the corresponding crl. Either the * list of revoked certificates of the corresponding crl. Either the
* status CERT_GOOD or CERT_REVOKED is returned * status CERT_GOOD or CERT_REVOKED is returned
*/ */
static cert_status_t static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial,
check_revocation(const x509crl_t *crl, chunk_t serial time_t *revocationDate,
, time_t *revocationDate, crl_reason_t * revocationReason) crl_reason_t *revocationReason)
{ {
revokedCert_t *revokedCert = crl->revokedCertificates; enumerator_t *enumerator;
cert_status_t status;
*revocationDate = UNDEFINED_TIME; chunk_t serial;
*revocationReason = CRL_REASON_UNSPECIFIED;
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_dump_chunk("serial number:", serial) DBG_log("serial number: %#B", &cert_serial)
) )
*revocationDate = UNDEFINED_TIME;
*revocationReason = CRL_REASON_UNSPECIFIED;
status = CERT_GOOD;
while(revokedCert != NULL) enumerator = crl->create_enumerator(crl);
while (enumerator->enumerate(enumerator, &serial,
revocationDate, revocationReason))
{ {
/* compare serial numbers */ if (chunk_equals(serial, cert_serial))
if (revokedCert->userCertificate.len == serial.len &&
memeq(revokedCert->userCertificate.ptr, serial.ptr, serial.len))
{ {
*revocationDate = revokedCert->revocationDate; status = CERT_REVOKED;
*revocationReason = revokedCert->revocationReason; break;
return CERT_REVOKED;
} }
revokedCert = revokedCert->next;
} }
return CERT_GOOD; enumerator->destroy(enumerator);
return status;
} }
/* /*
@@ -525,35 +310,39 @@ check_revocation(const x509crl_t *crl, chunk_t serial
*/ */
void check_crls(void) void check_crls(void)
{ {
x509crl_t *crl; x509crl_t *x509crl;
time_t now, nextUpdate, time_left;
lock_crl_list("check_crls"); lock_crl_list("check_crls");
crl = x509crls; time(&now);
x509crl = x509crls;
while (crl != NULL) while (x509crl != NULL)
{ {
time_t time_left = crl->nextUpdate - time(NULL); certificate_t *cert_crl = x509crl->crl;
u_char buf[BUF_LEN]; crl_t *crl = (crl_t*)cert_crl;
identification_t *issuer = cert_crl->get_issuer(cert_crl);
chunk_t issuer_dn = issuer->get_encoding(issuer);
chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
time_left = nextUpdate - now;
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
dntoa(buf, BUF_LEN, crl->issuer); DBG_log("issuer: '%Y'", issuer);
DBG_log("issuer: '%s'",buf); if (authKeyID.ptr)
if (crl->authKeyID.ptr != NULL)
{ {
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' DBG_log("authkey: %#B", authKeyID);
, buf, BUF_LEN);
DBG_log("authkey: %s", buf);
} }
DBG_log("%ld seconds left", time_left) DBG_log("%ld seconds left", time_left)
) )
if (time_left < 2*crl_check_interval) if (time_left < 2*crl_check_interval)
{ {
fetch_req_t *req = build_crl_fetch_request(crl->issuer, fetch_req_t *req = build_crl_fetch_request(issuer_dn, authKeyID,
crl->authKeyID, x509crl->distributionPoints);
crl->distributionPoints);
add_crl_fetch_request(req); add_crl_fetch_request(req);
} }
crl = crl->next; x509crl = x509crl->next;
} }
unlock_crl_list("check_crls"); unlock_crl_list("check_crls");
} }
@@ -570,7 +359,7 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
identification_t *issuer = certificate->get_issuer(certificate); identification_t *issuer = certificate->get_issuer(certificate);
chunk_t issuer_dn = issuer->get_encoding(issuer); chunk_t issuer_dn = issuer->get_encoding(issuer);
chunk_t authKeyID = x509->get_authKeyIdentifier(x509); chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
x509crl_t *crl; x509crl_t *x509crl;
ca_info_t *ca; ca_info_t *ca;
enumerator_t *enumerator; enumerator_t *enumerator;
char *point; char *point;
@@ -581,9 +370,9 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
*revocationReason = CRL_REASON_UNSPECIFIED; *revocationReason = CRL_REASON_UNSPECIFIED;
lock_crl_list("verify_by_crl"); lock_crl_list("verify_by_crl");
crl = get_x509crl(issuer_dn, authKeyID); x509crl = get_x509crl(issuer_dn, authKeyID);
if (crl == NULL) if (x509crl == NULL)
{ {
linked_list_t *crluris; linked_list_t *crluris;
@@ -621,6 +410,9 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
} }
else else
{ {
certificate_t *cert_crl = x509crl->crl;
crl_t *crl = (crl_t*)cert_crl;
chunk_t authKeyID = crl->get_authKeyIdentifier(crl);
x509cert_t *issuer_cert; x509cert_t *issuer_cert;
bool valid; bool valid;
@@ -630,47 +422,49 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
if (ca) if (ca)
{ {
add_distribution_points(crl->distributionPoints, ca->crluris); add_distribution_points(x509crl->distributionPoints, ca->crluris);
} }
enumerator = x509->create_crl_uri_enumerator(x509); enumerator = x509->create_crl_uri_enumerator(x509);
while (enumerator->enumerate(enumerator, &point)) while (enumerator->enumerate(enumerator, &point))
{ {
add_distribution_point(crl->distributionPoints, point); add_distribution_point(x509crl->distributionPoints, point);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
lock_authcert_list("verify_by_crl"); lock_authcert_list("verify_by_crl");
issuer_cert = get_authcert(crl->issuer, crl->authKeyID, AUTH_CA); issuer_cert = get_authcert(issuer_dn, authKeyID, AUTH_CA);
valid = x509_check_signature(crl->tbsCertList, crl->signature, valid = cert_crl->issued_by(cert_crl, issuer_cert->cert);
crl->algorithm, issuer_cert->cert);
unlock_authcert_list("verify_by_crl"); unlock_authcert_list("verify_by_crl");
if (valid) if (valid)
{ {
time_t now, nextUpdate;
cert_status_t status; cert_status_t status;
DBG(DBG_CONTROL, DBG(DBG_CONTROL,
DBG_log("crl signature is valid") DBG_log("crl signature is valid")
) )
/* return the expiration date */ /* return the expiration date */
*until = crl->nextUpdate; time(&now);
cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
*until = nextUpdate;
/* has the certificate been revoked? */ /* has the certificate been revoked? */
status = check_revocation(crl, x509->get_serial(x509), revocationDate status = check_revocation(crl, x509->get_serial(x509), revocationDate
, revocationReason); , revocationReason);
if (*until < time(NULL)) if (*until < now)
{ {
fetch_req_t *req; fetch_req_t *req;
plog("crl update is overdue since %T", until, TRUE); plog("crl update is overdue since %T", until, TRUE);
/* try to fetch a crl update */ /* try to fetch a crl update */
req = build_crl_fetch_request(crl->issuer, crl->authKeyID, req = build_crl_fetch_request(issuer_dn, authKeyID,
crl->distributionPoints); x509crl->distributionPoints);
unlock_crl_list("verify_by_crl"); unlock_crl_list("verify_by_crl");
add_crl_fetch_request(req); add_crl_fetch_request(req);
@@ -699,62 +493,59 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
*/ */
void list_crls(bool utc, bool strict) void list_crls(bool utc, bool strict)
{ {
x509crl_t *crl; x509crl_t *x509crl;
lock_crl_list("list_crls"); lock_crl_list("list_crls");
crl = x509crls; x509crl = x509crls;
if (crl != NULL) if (x509crl)
{ {
whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of X.509 CRLs:"); whack_log(RC_COMMENT, "List of X.509 CRLs:");
whack_log(RC_COMMENT, " "); whack_log(RC_COMMENT, " ");
} }
while (crl != NULL) while (x509crl)
{ {
u_char buf[BUF_LEN]; certificate_t *cert_crl = x509crl->crl;
crl_t *crl = (crl_t*)cert_crl;
chunk_t serial, authKeyID;
time_t thisUpdate, nextUpdate;
u_int revoked = 0; u_int revoked = 0;
revokedCert_t *revokedCert = crl->revokedCertificates; enumerator_t *enumerator;
/* count number of revoked certificates in CRL */ /* count number of revoked certificates in CRL */
while (revokedCert != NULL) enumerator = crl->create_enumerator(crl);
while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
{ {
revoked++; revoked++;
revokedCert = revokedCert->next;
} }
enumerator->destroy(enumerator);
whack_log(RC_COMMENT, "%T, revoked certs: %d", whack_log(RC_COMMENT, "%T, revoked certs: %d",
&crl->installed, utc, revoked); &x509crl->installed, utc, revoked);
dntoa(buf, BUF_LEN, crl->issuer); whack_log(RC_COMMENT, " issuer: '%Y'",
whack_log(RC_COMMENT, " issuer: '%s'", buf); cert_crl->get_issuer(cert_crl));
if (crl->crlNumber.ptr != NULL) serial = crl->get_serial(crl);
if (serial.ptr)
{ {
datatot(crl->crlNumber.ptr, crl->crlNumber.len, ':' whack_log(RC_COMMENT, " crlnumber: %#B", &serial);
, buf, BUF_LEN);
whack_log(RC_COMMENT, " crlnumber: %s", buf);
} }
list_distribution_points(crl->distributionPoints); list_distribution_points(x509crl->distributionPoints);
cert_crl->get_validity(cert_crl, NULL, &thisUpdate, &nextUpdate);
whack_log(RC_COMMENT, " updates: this %T", whack_log(RC_COMMENT, " updates: this %T",
&crl->thisUpdate, utc); &thisUpdate, utc);
whack_log(RC_COMMENT, " next %T %s", whack_log(RC_COMMENT, " next %T %s",
&crl->nextUpdate, utc, &nextUpdate, utc,
check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict)); check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict));
if (crl->authKeyID.ptr != NULL) authKeyID = crl->get_authKeyIdentifier(crl);
if (authKeyID.ptr)
{ {
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':' whack_log(RC_COMMENT, " authkey: %#B", &authKeyID);
, buf, BUF_LEN);
whack_log(RC_COMMENT, " authkey: %s", buf);
}
if (crl->authKeySerialNumber.ptr != NULL)
{
datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':'
, buf, BUF_LEN);
whack_log(RC_COMMENT, " aserial: %s", buf);
} }
crl = crl->next; x509crl = x509crl->next;
} }
unlock_crl_list("list_crls"); unlock_crl_list("list_crls");
} }
+9 -39
View File
@@ -15,49 +15,19 @@
#include "constants.h" #include "constants.h"
#include <utils/linked_list.h> #include <utils/linked_list.h>
#include <credentials/certificates/certificate.h>
#include <credentials/certificates/crl.h> #include <credentials/certificates/crl.h>
/* access structure for a revoked serial number */
typedef struct revokedCert revokedCert_t;
struct revokedCert{
revokedCert_t *next;
chunk_t userCertificate;
time_t revocationDate;
crl_reason_t revocationReason;
};
/* storage structure for an X.509 CRL */ /* storage structure for an X.509 CRL */
typedef struct x509crl x509crl_t; typedef struct x509crl x509crl_t;
struct x509crl { struct x509crl {
x509crl_t *next; certificate_t *crl;
time_t installed; x509crl_t *next;
linked_list_t *distributionPoints; time_t installed;
chunk_t certificateList; linked_list_t *distributionPoints;
chunk_t tbsCertList; chunk_t signature;
u_int version;
/* signature */
int sigAlg;
chunk_t issuer;
time_t thisUpdate;
time_t nextUpdate;
revokedCert_t *revokedCertificates;
/* v2 extensions */
/* crlExtensions */
/* extension */
/* extnID */
/* critical */
/* extnValue */
chunk_t authKeyID;
chunk_t authKeySerialNumber;
chunk_t crlNumber;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
}; };
/* apply a strict CRL policy /* apply a strict CRL policy
@@ -78,12 +48,12 @@ extern long crl_check_interval;
/* used for initialization */ /* used for initialization */
extern const x509crl_t empty_x509crl; extern const x509crl_t empty_x509crl;
extern bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl);
extern void load_crls(void); extern void load_crls(void);
extern void check_crls(void); extern void check_crls(void);
extern bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl); extern bool insert_crl(x509crl_t *crl, char *crl_uri, bool cache_crl);
extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
, time_t *revocationDate, crl_reason_t *revocationReason); time_t *revocationDate,
crl_reason_t *revocationReason);
extern void list_crls(bool utc, bool strict); extern void list_crls(bool utc, bool strict);
extern void free_crls(void); extern void free_crls(void);
extern void free_crl(x509crl_t *crl); extern void free_crl(x509crl_t *crl);