pluto's crl handling now uses the x509 plugin
This commit is contained in:
+5
-1
@@ -168,7 +168,11 @@ static x509crl_t *builder_load_crl(certificate_type_t type, va_list args)
|
||||
*crl = empty_x509crl;
|
||||
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;
|
||||
}
|
||||
|
||||
+145
-354
@@ -24,12 +24,6 @@
|
||||
|
||||
#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 "defs.h"
|
||||
#include "log.h"
|
||||
@@ -47,87 +41,11 @@
|
||||
|
||||
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 = {
|
||||
NULL , /* crl */
|
||||
NULL , /* *next */
|
||||
UNDEFINED_TIME, /* installed */
|
||||
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)
|
||||
{
|
||||
x509crl_t *crl = x509crls;
|
||||
x509crl_t *x509crl = x509crls;
|
||||
x509crl_t *prev_crl = NULL;
|
||||
|
||||
while (crl != NULL)
|
||||
while (x509crl != NULL)
|
||||
{
|
||||
if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL)
|
||||
? same_keyid(keyid, crl->authKeyID)
|
||||
: (same_dn(crl->issuer, issuer)))
|
||||
certificate_t *cert_crl = x509crl->crl;
|
||||
crl_t *crl = (crl_t*)cert_crl;
|
||||
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 */
|
||||
prev_crl->next = crl->next;
|
||||
crl->next = x509crls;
|
||||
x509crls = crl;
|
||||
prev_crl->next = x509crl->next;
|
||||
x509crl->next = x509crls;
|
||||
x509crls = x509crl;
|
||||
}
|
||||
return crl;
|
||||
return x509crl;
|
||||
}
|
||||
prev_crl = crl;
|
||||
crl = crl->next;
|
||||
prev_crl = x509crl;
|
||||
x509crl = x509crl->next;
|
||||
}
|
||||
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
|
||||
*/
|
||||
void free_crl(x509crl_t *crl)
|
||||
{
|
||||
DESTROY_IF(crl->crl);
|
||||
crl->distributionPoints->destroy_function(crl->distributionPoints, free);
|
||||
free_revoked_certs(crl->revokedCertificates);
|
||||
free(crl->certificateList.ptr);
|
||||
free(crl);
|
||||
}
|
||||
|
||||
@@ -196,7 +105,9 @@ void free_crls(void)
|
||||
lock_crl_list("free_crls");
|
||||
|
||||
while (x509crls != NULL)
|
||||
{
|
||||
free_first_crl();
|
||||
}
|
||||
|
||||
unlock_crl_list("free_crls");
|
||||
}
|
||||
@@ -204,23 +115,29 @@ void free_crls(void)
|
||||
/**
|
||||
* 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;
|
||||
x509crl_t *oldcrl;
|
||||
time_t now, nextUpdate;
|
||||
bool valid_sig;
|
||||
|
||||
/* add distribution point */
|
||||
add_distribution_point(crl->distributionPoints, crl_uri);
|
||||
add_distribution_point(x509crl->distributionPoints, crl_uri);
|
||||
|
||||
lock_authcert_list("insert_crl");
|
||||
|
||||
/* 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)
|
||||
{
|
||||
plog("crl issuer cacert not found");
|
||||
free_crl(crl);
|
||||
free_crl(x509crl);
|
||||
unlock_authcert_list("insert_crl");
|
||||
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 */
|
||||
valid_sig = x509_check_signature(crl->tbsCertList, crl->signature,
|
||||
crl->algorithm, issuer_cert->cert);
|
||||
valid_sig = cert_crl->issued_by(cert_crl, issuer_cert->cert);
|
||||
unlock_authcert_list("insert_crl");
|
||||
|
||||
if (!valid_sig)
|
||||
{
|
||||
free_crl(crl);
|
||||
free_crl(x509crl);
|
||||
return FALSE;
|
||||
}
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("crl signature is valid")
|
||||
)
|
||||
|
||||
/* note the current time */
|
||||
time(&now);
|
||||
|
||||
lock_crl_list("insert_crl");
|
||||
oldcrl = get_x509crl(crl->issuer, crl->authKeyID);
|
||||
oldcrl = get_x509crl(issuer_dn, authKeyID);
|
||||
|
||||
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 */
|
||||
add_distribution_points(crl->distributionPoints,
|
||||
add_distribution_points(x509crl->distributionPoints,
|
||||
oldcrl->distributionPoints);
|
||||
|
||||
/* 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_log("thisUpdate is not newer - existing crl not replaced");
|
||||
)
|
||||
free_crl(crl);
|
||||
return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval;
|
||||
free_crl(x509crl);
|
||||
old_cert_crl->get_validity(old_cert_crl, &now, NULL, &nextUpdate);
|
||||
return nextUpdate - now > 2*crl_check_interval;
|
||||
}
|
||||
}
|
||||
|
||||
/* insert new CRL */
|
||||
crl->next = x509crls;
|
||||
x509crls = crl;
|
||||
x509crl->next = x509crls;
|
||||
x509crls = x509crl;
|
||||
|
||||
unlock_crl_list("insert_crl");
|
||||
|
||||
/* If crl caching is enabled then the crl is saved locally.
|
||||
* 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)
|
||||
{
|
||||
char path[BUF_LEN], buf[BUF_LEN];
|
||||
certificate_t *certificate = issuer_cert->cert;
|
||||
x509_t *x509 = (x509_t*)certificate;
|
||||
chunk_t subjectKeyID;
|
||||
char buf[BUF_LEN];
|
||||
chunk_t hex, encoding;
|
||||
|
||||
subjectKeyID = x509->get_subjectKeyIdentifier(x509);
|
||||
if (subjectKeyID.ptr)
|
||||
{
|
||||
datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
|
||||
snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf);
|
||||
chunk_write(crl->certificateList, path, "crl", 0022, TRUE);
|
||||
}
|
||||
hex = chunk_to_hex(crl->get_authKeyIdentifier(crl), NULL, FALSE);
|
||||
snprintf(buf, sizeof(buf), "%s/%s.crl", CRL_PATH, hex);
|
||||
free(hex.ptr);
|
||||
|
||||
encoding = cert_crl->get_encoding(cert_crl);
|
||||
chunk_write(encoding, buf, "crl", 022, TRUE);
|
||||
free(encoding.ptr);
|
||||
}
|
||||
|
||||
/* 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--)
|
||||
{
|
||||
char *filename = filelist[n]->d_name;
|
||||
x509crl_t *crl;
|
||||
x509crl_t *x509crl;
|
||||
|
||||
crl = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
||||
CERT_PLUTO_CRL, BUILD_FROM_FILE, filename, BUILD_END);
|
||||
if (crl)
|
||||
x509crl = lib->creds->create(lib->creds, CRED_CERTIFICATE,
|
||||
CERT_PLUTO_CRL,
|
||||
BUILD_FROM_FILE, filename, BUILD_END);
|
||||
if (x509crl)
|
||||
{
|
||||
char crl_uri[BUF_LEN];
|
||||
|
||||
plog(" loaded crl from '%s'", 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]);
|
||||
}
|
||||
@@ -349,175 +271,38 @@ void load_crls(void)
|
||||
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
|
||||
* list of revoked certificates of the corresponding crl. Either the
|
||||
* status CERT_GOOD or CERT_REVOKED is returned
|
||||
*/
|
||||
static cert_status_t
|
||||
check_revocation(const x509crl_t *crl, chunk_t serial
|
||||
, time_t *revocationDate, crl_reason_t * revocationReason)
|
||||
static cert_status_t check_revocation(crl_t *crl, chunk_t cert_serial,
|
||||
time_t *revocationDate,
|
||||
crl_reason_t *revocationReason)
|
||||
{
|
||||
revokedCert_t *revokedCert = crl->revokedCertificates;
|
||||
|
||||
*revocationDate = UNDEFINED_TIME;
|
||||
*revocationReason = CRL_REASON_UNSPECIFIED;
|
||||
enumerator_t *enumerator;
|
||||
cert_status_t status;
|
||||
chunk_t serial;
|
||||
|
||||
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 (revokedCert->userCertificate.len == serial.len &&
|
||||
memeq(revokedCert->userCertificate.ptr, serial.ptr, serial.len))
|
||||
if (chunk_equals(serial, cert_serial))
|
||||
{
|
||||
*revocationDate = revokedCert->revocationDate;
|
||||
*revocationReason = revokedCert->revocationReason;
|
||||
return CERT_REVOKED;
|
||||
status = CERT_REVOKED;
|
||||
break;
|
||||
}
|
||||
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)
|
||||
{
|
||||
x509crl_t *crl;
|
||||
x509crl_t *x509crl;
|
||||
time_t now, nextUpdate, time_left;
|
||||
|
||||
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);
|
||||
u_char buf[BUF_LEN];
|
||||
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);
|
||||
|
||||
cert_crl->get_validity(cert_crl, &now, NULL, &nextUpdate);
|
||||
time_left = nextUpdate - now;
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
dntoa(buf, BUF_LEN, crl->issuer);
|
||||
DBG_log("issuer: '%s'",buf);
|
||||
if (crl->authKeyID.ptr != NULL)
|
||||
DBG_log("issuer: '%Y'", issuer);
|
||||
if (authKeyID.ptr)
|
||||
{
|
||||
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
|
||||
, buf, BUF_LEN);
|
||||
DBG_log("authkey: %s", buf);
|
||||
DBG_log("authkey: %#B", authKeyID);
|
||||
}
|
||||
DBG_log("%ld seconds left", time_left)
|
||||
)
|
||||
if (time_left < 2*crl_check_interval)
|
||||
{
|
||||
fetch_req_t *req = build_crl_fetch_request(crl->issuer,
|
||||
crl->authKeyID,
|
||||
crl->distributionPoints);
|
||||
fetch_req_t *req = build_crl_fetch_request(issuer_dn, authKeyID,
|
||||
x509crl->distributionPoints);
|
||||
add_crl_fetch_request(req);
|
||||
}
|
||||
crl = crl->next;
|
||||
x509crl = x509crl->next;
|
||||
}
|
||||
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);
|
||||
chunk_t issuer_dn = issuer->get_encoding(issuer);
|
||||
chunk_t authKeyID = x509->get_authKeyIdentifier(x509);
|
||||
x509crl_t *crl;
|
||||
x509crl_t *x509crl;
|
||||
ca_info_t *ca;
|
||||
enumerator_t *enumerator;
|
||||
char *point;
|
||||
@@ -581,9 +370,9 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
|
||||
*revocationReason = CRL_REASON_UNSPECIFIED;
|
||||
|
||||
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;
|
||||
|
||||
@@ -621,6 +410,9 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
|
||||
}
|
||||
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;
|
||||
bool valid;
|
||||
|
||||
@@ -630,47 +422,49 @@ cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
|
||||
|
||||
if (ca)
|
||||
{
|
||||
add_distribution_points(crl->distributionPoints, ca->crluris);
|
||||
add_distribution_points(x509crl->distributionPoints, ca->crluris);
|
||||
}
|
||||
|
||||
enumerator = x509->create_crl_uri_enumerator(x509);
|
||||
while (enumerator->enumerate(enumerator, &point))
|
||||
{
|
||||
add_distribution_point(crl->distributionPoints, point);
|
||||
add_distribution_point(x509crl->distributionPoints, point);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
lock_authcert_list("verify_by_crl");
|
||||
|
||||
issuer_cert = get_authcert(crl->issuer, crl->authKeyID, AUTH_CA);
|
||||
valid = x509_check_signature(crl->tbsCertList, crl->signature,
|
||||
crl->algorithm, issuer_cert->cert);
|
||||
issuer_cert = get_authcert(issuer_dn, authKeyID, AUTH_CA);
|
||||
valid = cert_crl->issued_by(cert_crl, issuer_cert->cert);
|
||||
|
||||
unlock_authcert_list("verify_by_crl");
|
||||
|
||||
if (valid)
|
||||
{
|
||||
time_t now, nextUpdate;
|
||||
cert_status_t status;
|
||||
|
||||
DBG(DBG_CONTROL,
|
||||
DBG_log("crl signature is valid")
|
||||
)
|
||||
/* 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? */
|
||||
status = check_revocation(crl, x509->get_serial(x509), revocationDate
|
||||
, revocationReason);
|
||||
|
||||
if (*until < time(NULL))
|
||||
if (*until < now)
|
||||
{
|
||||
fetch_req_t *req;
|
||||
|
||||
plog("crl update is overdue since %T", until, TRUE);
|
||||
|
||||
/* try to fetch a crl update */
|
||||
req = build_crl_fetch_request(crl->issuer, crl->authKeyID,
|
||||
crl->distributionPoints);
|
||||
req = build_crl_fetch_request(issuer_dn, authKeyID,
|
||||
x509crl->distributionPoints);
|
||||
unlock_crl_list("verify_by_crl");
|
||||
|
||||
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)
|
||||
{
|
||||
x509crl_t *crl;
|
||||
x509crl_t *x509crl;
|
||||
|
||||
lock_crl_list("list_crls");
|
||||
crl = x509crls;
|
||||
x509crl = x509crls;
|
||||
|
||||
if (crl != NULL)
|
||||
if (x509crl)
|
||||
{
|
||||
whack_log(RC_COMMENT, " ");
|
||||
whack_log(RC_COMMENT, "List of X.509 CRLs:");
|
||||
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;
|
||||
revokedCert_t *revokedCert = crl->revokedCertificates;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
/* count number of revoked certificates in CRL */
|
||||
while (revokedCert != NULL)
|
||||
enumerator = crl->create_enumerator(crl);
|
||||
while (enumerator->enumerate(enumerator, NULL, NULL, NULL))
|
||||
{
|
||||
revoked++;
|
||||
revokedCert = revokedCert->next;
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
|
||||
whack_log(RC_COMMENT, "%T, revoked certs: %d",
|
||||
&crl->installed, utc, revoked);
|
||||
dntoa(buf, BUF_LEN, crl->issuer);
|
||||
whack_log(RC_COMMENT, " issuer: '%s'", buf);
|
||||
if (crl->crlNumber.ptr != NULL)
|
||||
&x509crl->installed, utc, revoked);
|
||||
whack_log(RC_COMMENT, " issuer: '%Y'",
|
||||
cert_crl->get_issuer(cert_crl));
|
||||
serial = crl->get_serial(crl);
|
||||
if (serial.ptr)
|
||||
{
|
||||
datatot(crl->crlNumber.ptr, crl->crlNumber.len, ':'
|
||||
, buf, BUF_LEN);
|
||||
whack_log(RC_COMMENT, " crlnumber: %s", buf);
|
||||
whack_log(RC_COMMENT, " crlnumber: %#B", &serial);
|
||||
}
|
||||
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",
|
||||
&crl->thisUpdate, utc);
|
||||
&thisUpdate, utc);
|
||||
whack_log(RC_COMMENT, " next %T %s",
|
||||
&crl->nextUpdate, utc,
|
||||
check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict));
|
||||
if (crl->authKeyID.ptr != NULL)
|
||||
&nextUpdate, utc,
|
||||
check_expiry(nextUpdate, CRL_WARNING_INTERVAL, strict));
|
||||
authKeyID = crl->get_authKeyIdentifier(crl);
|
||||
if (authKeyID.ptr)
|
||||
{
|
||||
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
|
||||
, 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);
|
||||
whack_log(RC_COMMENT, " authkey: %#B", &authKeyID);
|
||||
}
|
||||
|
||||
crl = crl->next;
|
||||
x509crl = x509crl->next;
|
||||
}
|
||||
unlock_crl_list("list_crls");
|
||||
}
|
||||
|
||||
+9
-39
@@ -15,49 +15,19 @@
|
||||
#include "constants.h"
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <credentials/certificates/certificate.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 */
|
||||
|
||||
typedef struct x509crl x509crl_t;
|
||||
|
||||
struct x509crl {
|
||||
x509crl_t *next;
|
||||
time_t installed;
|
||||
linked_list_t *distributionPoints;
|
||||
chunk_t certificateList;
|
||||
chunk_t tbsCertList;
|
||||
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;
|
||||
certificate_t *crl;
|
||||
x509crl_t *next;
|
||||
time_t installed;
|
||||
linked_list_t *distributionPoints;
|
||||
chunk_t signature;
|
||||
};
|
||||
|
||||
/* apply a strict CRL policy
|
||||
@@ -78,12 +48,12 @@ extern long crl_check_interval;
|
||||
/* used for initialization */
|
||||
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 check_crls(void);
|
||||
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
|
||||
, time_t *revocationDate, crl_reason_t *revocationReason);
|
||||
extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until,
|
||||
time_t *revocationDate,
|
||||
crl_reason_t *revocationReason);
|
||||
extern void list_crls(bool utc, bool strict);
|
||||
extern void free_crls(void);
|
||||
extern void free_crl(x509crl_t *crl);
|
||||
|
||||
Reference in New Issue
Block a user